From eca10db155777ca80990f9ac8c2ccd9ede93613d Mon Sep 17 00:00:00 2001 From: Aditya Alluri Date: Wed, 17 Apr 2019 14:58:28 +0000 Subject: [PATCH 01/31] Patching HDK 1.4.8 1. Fixed XRT installation instruction for 2018.3 2. artifact update for SDAccel helloworld_ocl_runtime example 3. updating tool version tables in README.md --- README.md | 9 +++++---- SDAccel/docs/XRT_installation_instructions.md | 8 ++++---- .../aws/helloworld_ocl_runtime/2018.3/helloworld | Bin .../aws/helloworld_ocl_runtime/2018.3/sdaccel.ini | 2 ++ .../examples/aws/helloworld_ocl_runtime/sdaccel.ini | 2 ++ shared/lib/check_src_headers.py | 2 ++ 6 files changed, 15 insertions(+), 8 deletions(-) mode change 100644 => 100755 SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/helloworld create mode 100644 SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/sdaccel.ini create mode 100644 SDAccel/examples/aws/helloworld_ocl_runtime/sdaccel.ini diff --git a/README.md b/README.md index aaf8a448..e6e95ea9 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,8 @@ The AWS EC2 FPGA Development Kit is provided by AWS to support development and r | Tool | Development/Runtime | Tool location | Description | | --------|---------|---------|---------| -| SDx 2017.4 & 2018.2 | Development | [FPGA developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Software Defined Accelerator Development](SDAccel/README.md) | -| Vivado 2017.4 & 2018.2 | Development | [FPGA developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Hardware Accelerator Development](hdk/README.md) | +| SDx 2017.4, 2018.2 & 2018.3 | Development | [FPGA developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Software Defined Accelerator Development](SDAccel/README.md) | +| Vivado 2017.4, 2018.2 & 2018.3 | Development | [FPGA developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Hardware Accelerator Development](hdk/README.md) | | FPGA AFI Management Tools | Runtime | [SDK - fpga\_mgmt\_tools](sdk/userspace/fpga_mgmt_tools) | Command-line tools used for FPGA management while running on the F1 instance | | Virtual JTAG | Development (Debug) | [FPGA developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Runtime debug waveform | | wait\_for\_afi | Development | [wait\_for\_afi.py](shared/bin/scripts/wait_for_afi.py) | Helper script that notifies via email on AFI generation completion | @@ -95,7 +95,7 @@ Before you start your first AWS FPGA design, we recommend that you go through on ### In-depth training and resources Once you have completed your hello world examples, we recommend diving deeper into a training workshop or application notes - * Software-defined [re:Invent 2017 Workshop](https://github.com/awslabs/aws-fpga-app-notes/blob/master/reInvent17_Developer_Workshop/README.md) demonstrates a video encoder acceleration and how to debug and optimize your accelerator. + * Software-defined [re:Invent 2018 Workshop](https://github.com/awslabs/aws-fpga-app-notes/blob/master/reInvent18_Developer_Workshop/README.md) demonstrates a 2D Filter acceleration and how to debug and optimize your accelerator. * Custom hardware developers need to learn about how the hardware accelerator interfaces to the F1 Shell * [Shell Interface](hdk/docs/AWS_Shell_Interface_Specification.md) * [Shell Address Map](hdk/docs/AWS_Fpga_Pcie_Memory_Map.md) @@ -108,13 +108,14 @@ Once you have completed your hello world examples, we recommend diving deeper in The [FPGA developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) is available on the AWS marketplace without a software charge and includes free tools and drivers needed for FPGA development on EC2 instances. FPGA development runs on several [EC2 instance types](https://aws.amazon.com/ec2/instance-types/). Given the large size of the FPGA used inside the AWS FPGA instances, the implementation tools require 32GiB Memory (ex: z1d.xlarge, z1d.2xlarge, c5.4xlarge, m5.2xlarge, r5.xlarge, t2.2xlarge). z1d.xlarge/c5.4xlarge and z1d.2xlarge/c5.8xlarge would provide the fastest execution time with 30GiB+ and 60GiB+ of memory respectively. Developers who want to save on cost, could start coding and run simulations on low-cost instances, like t2.2xlarge, and move to the aforementioned larger instances to run the synthesis of their acceleration code. -Currently, AWS marketplace includes multiple versions of the FPGA developer AMI, supporting Xilinx SDx 2017.4 and 2018.2 toolchain versions. The following compatibility table describes the mapping of currently supported developer kit versions to AMI versions: +Currently, AWS marketplace includes multiple versions of the FPGA developer AMI, supporting Xilinx SDx 2017.4, 2018.2 and 2018.3 toolchain versions. The following compatibility table describes the mapping of currently supported developer kit versions to AMI versions: | Developer Kit Version | Tool Version Supported | Compatible FPGA developer AMI Version | |-----------|-----------|------| | 1.3.7-1.3.X | 2017.4 | v1.4.0-v1.4.X (Xilinx Vivado/SDx 2017.4) | | 1.4.X | 2017.4 | v1.4.0-v1.4.X (Xilinx Vivado/SDx 2017.4) | | 1.4.3+ | 2018.2 | v1.5.0-v1.5.X (Xilinx Vivado/SDx 2018.2) | +| 1.4.8+ | 2018.3 | v1.6.0-v1.6.X (Xilinx Vivado/SDx 2018.3) | Developer kit versions prior to v1.3.7 and Developer AMI prior to v1.4 (2017.1) reached end-of-life. See [AWS forum announcement](https://forums.aws.amazon.com/ann.jspa?annID=6068) for additional details. diff --git a/SDAccel/docs/XRT_installation_instructions.md b/SDAccel/docs/XRT_installation_instructions.md index c0125c13..0ed1bd17 100644 --- a/SDAccel/docs/XRT_installation_instructions.md +++ b/SDAccel/docs/XRT_installation_instructions.md @@ -31,12 +31,12 @@ ### Install on Centos/RedHat Linux using prebuilt RPM ``` - curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.6.0/Patches/XRT_2018_3_RC3_Patch1/xrt_201803.2.1.0_7.5.1804-xrt.rpm -o xrt_201803.2.1.0_7.5.1804-xrt.rpm - curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.6.0/Patches/XRT_2018_3_RC3_Patch1/xrt_201803.2.1.0_7.5.1804-aws.rpm -o xrt_201803.2.1.0_7.5.1804-aws.rpm + curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.6.0/Patches/XRT_2018_3_RC3_Patch1/xrt_201830.2.1.0_7.6.1810-xrt.rpm -o xrt_201830.2.1.0_7.6.1810-xrt.rpm + curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.6.0/Patches/XRT_2018_3_RC3_Patch1/xrt_201830.2.1.0_7.6.1810-aws.rpm -o xrt_201830.2.1.0_7.6.1810-aws.rpm sudo yum remove -y xrt-aws sudo yum remove -y xrt - sudo yum install -y xrt_201803.2.1.0_7.5.1804-xrt.rpm - sudo yum install -y xrt_201803.2.1.0_7.5.1804-aws.rpm + sudo yum install -y xrt_201830.2.1.0_7.6.1810-xrt.rpm + sudo yum install -y xrt_201830.2.1.0_7.6.1810-aws.rpm ``` diff --git a/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/helloworld b/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/helloworld old mode 100644 new mode 100755 diff --git a/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/sdaccel.ini b/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/sdaccel.ini new file mode 100644 index 00000000..c75131c1 --- /dev/null +++ b/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/sdaccel.ini @@ -0,0 +1,2 @@ +[Debug] +profile=true diff --git a/SDAccel/examples/aws/helloworld_ocl_runtime/sdaccel.ini b/SDAccel/examples/aws/helloworld_ocl_runtime/sdaccel.ini new file mode 100644 index 00000000..c75131c1 --- /dev/null +++ b/SDAccel/examples/aws/helloworld_ocl_runtime/sdaccel.ini @@ -0,0 +1,2 @@ +[Debug] +profile=true diff --git a/shared/lib/check_src_headers.py b/shared/lib/check_src_headers.py index c307caae..d3c229ed 100755 --- a/shared/lib/check_src_headers.py +++ b/shared/lib/check_src_headers.py @@ -558,8 +558,10 @@ def check_headers(dir): "SDAccel/userspace/src/test", "SDAccel/examples/aws/kernel_3ddr_bandwidth/description.json", "SDAccel/examples/aws/helloworld_ocl_runtime/helloworld", + "SDAccel/examples/aws/helloworld_ocl_runtime/sdaccel.ini", "SDAccel/examples/aws/helloworld_ocl_runtime/vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin", "SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/helloworld", + "SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/sdaccel.ini", "SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin" ]) From ed564e7a87be1ad75b629d628b6e933f27b5bf26 Mon Sep 17 00:00:00 2001 From: AWSaalluri Date: Mon, 13 May 2019 17:50:32 -0500 Subject: [PATCH 02/31] RELEASE V1.4.9 * New functionality: * Improved AFI load times for pipelined accelerator designs. For more details please see [Amazon FPGA image (AFI) pre-fetch and caching features](./hdk/docs/load_times.md). * Ease of Use features: * [Improved SDK Error messaging](./sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c) * [Improved documentation](./hdk/docs/IPI_GUI_Vivado_Setup.md#switching-between-hdk-and-hlx-flows) to help with transition from [HLX to HDK command line flows](https://forums.aws.amazon.com/thread.jspa?threadID=302718&tstart=0) and vice versa * Incorporates feedback from [aws-fpga Issue 458](https://github.com/aws/aws-fpga/issues/458) by making the ```init_ddr``` function, used in design simulations to initialize DDR, more generic by moving out ATG deselection logic to a new ```deselect_atg_hw``` task * Bug Fixes: * Fixed Shell simulation model (sh_bfm) issue on PCIM AXI read data channel back pressure which was described in HDK 1.4.8 Errata. * Fixed HDK simulation example which [demonstrates DMA and PCIM traffic in parallel](./hdk/cl/examples/cl_dram_dma/verif/tests/test_dma_pcim_concurrent.sv). --- ERRATA.md | 11 +- Jenkinsfile | 2 +- RELEASE_NOTES.md | 27 +- hdk/cl/CHECKLIST_BEFORE_BUILDING_CL.md | 2 + .../runtime/test_dram_dma_hwsw_cosim.c | 1 + .../cl_dram_dma/verif/scripts/Makefile.questa | 2 +- .../verif/tests/test_dma_pcim_concurrent.sv | 36 ++- .../cl_dram_dma/verif/tests/test_host_pcim.sv | 250 ++++++++++++++++++ .../cl_dram_dma/verif/tests/test_peek_poke.sv | 33 ++- .../verif/tests/test_peek_poke_len.sv | 33 ++- .../verif/tests/test_gl_cntr.sv | 12 +- .../verif/tests/test_hello_world.sv | 8 +- .../verif/scripts/Makefile.questa | 2 +- .../cl_sde/verif/scripts/Makefile.ies | 43 +++ .../examples/cl_sde/verif/scripts/top.ies.f | 113 ++++++++ .../software/runtime/test_uram_example.c | 4 +- .../verif/scripts/Makefile.questa | 2 +- .../verif/tests/test_uram_example.sv | 14 +- .../design/sh_ddr/sim/axi4_slave_bfm.sv | 24 +- .../design/sh_ddr/sim/axi_bfm_defines.svh | 4 +- hdk/common/verif/include/sh_dpi_tasks.svh | 17 +- .../verif/models/sh_bfm/axi_bfm_defines.svh | 4 +- hdk/common/verif/models/sh_bfm/sh_bfm.sv | 7 +- hdk/docs/IPI_GUI_Vivado_Setup.md | 13 +- hdk/docs/load_times.md | 39 +++ hdk/hdk_version.txt | 2 +- hdk/tests/simulation_tests/test_sims.py | 8 + sdk/tests/test_fpga_tools.py | 15 +- .../fpga_libs/fpga_dma/fpga_dma_utils.c | 6 +- .../fpga_libs/fpga_mgmt/afi_cmd_api.h | 2 +- sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c | 6 +- .../fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c | 2 +- .../fpga_libs/fpga_mgmt/fpga_mgmt_internal.h | 4 +- .../fpga_libs/fpga_pci/fpga_pci_sysfs.c | 130 +++++---- .../fpga_mgmt_tools/src/fpga_local_cmd.c | 172 ++++++------ .../fpga_mgmt_tools/src/fpga_local_cmd.h | 6 +- .../src/fpga_local_cmd_parse.c | 166 ++++++------ sdk/userspace/include/fpga_pci.h | 18 +- sdk/userspace/include/hal/fpga_common.h | 46 ++-- sdk/userspace/include/utils/sh_dpi_tasks.h | 1 + sdk/userspace/python_bindings/fpga_dma.py | 65 +++-- sdk/userspace/python_bindings/fpga_mgmt.py | 178 +++++++------ sdk/userspace/python_bindings/fpga_pci.py | 139 +++++++--- 43 files changed, 1201 insertions(+), 468 deletions(-) create mode 100644 hdk/cl/examples/cl_dram_dma/verif/tests/test_host_pcim.sv create mode 100644 hdk/cl/examples/cl_sde/verif/scripts/Makefile.ies create mode 100644 hdk/cl/examples/cl_sde/verif/scripts/top.ies.f create mode 100644 hdk/docs/load_times.md diff --git a/ERRATA.md b/ERRATA.md index a56958a4..2dd87370 100644 --- a/ERRATA.md +++ b/ERRATA.md @@ -8,7 +8,7 @@ * Multiple SDE instances per CL is not supported in this release. Support planned for future release. * DRAM Data retention is not supported for CL designs with less than 4 DDRs enabled * Combinatorial loops in CL designs are not supported. -* Shell Model (sh_bfm) provided with testbench for design simulations, continues to drive read data on PCIM AXI rdata channel even when rready is de-asserted. Will be fixed in future release. +* [Automatic Traffic Generator (ATG)](./hdk/cl/examples/cl_dram_dma/design/cl_tst.sv) in SYNC mode does not wait for write response transaction before issuing read transactions. The fix for this issue is planned in a future release. ## SDK @@ -16,3 +16,12 @@ * Virtual Ethernet is not supported when using SDAccel * DRAM Data retention is not supported for kernels that provision less than 4 DDRs * Combinatorial loops in CL designs are not supported. +* When using [Xilinx runtime(XRT) version 2018.3.3.1](https://github.com/Xilinx/XRT/releases/tag/2018.3.3.1) or [AWS FPGA Developer AMI Version 1.6.0](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) your host application could fail with following error: + + ``` + : symbol lookup error: /opt/xilinx/xrt/lib/libxrt_aws.so: undefined symbol: uuid_parse! + + ``` + The SDAccel examples included in the developer kit use a SDAccel configuration file [sdaccel.ini]. To workaround this error please copy the SDAccel configuration file [sdaccel.ini](SDAccel/examples/aws/helloworld_ocl_runtime/sdaccel.ini) to your executable directory and try executing your application again. + AWS is working with Xilinx to release a XRT patch to fix this issue. + diff --git a/Jenkinsfile b/Jenkinsfile index 05a558f3..11da24a6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -505,7 +505,7 @@ if (test_sims) { String xilinx_version = y String cl_name = x String simulator = z - String node_name = "Sim ${cl_name} ${xilinx_version}" + String node_name = "Sim ${cl_name} ${xilinx_version} ${simulator}" String key = "test_${cl_name}__" String report_file = "test_sims_${cl_name}_${xilinx_version}.xml" def tool_module_map = simulator_tool_default_map.get(xilinx_version) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 86f06856..2f82e873 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -26,8 +26,30 @@ * 1 DDR controller implemented in the SH (always available) * 3 DDR controllers implemented in the CL (configurable number of implemented controllers allowed) +## Release 1.4.9 (See [ERRATA](./ERRATA.md) for unsupported features) + * New functionality: + * Improved AFI load times for pipelined accelerator designs. For more details please see [Amazon FPGA image (AFI) pre-fetch and caching features](./hdk/docs/load_times.md). + + * Ease of Use features: + * [Improved SDK Error messaging](./sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c) + * [Improved documentation](./hdk/docs/IPI_GUI_Vivado_Setup.md#switching-between-hdk-and-hlx-flows) to help with transition from [HLX to HDK command line flows](https://forums.aws.amazon.com/thread.jspa?threadID=302718&tstart=0) and vice versa + * Incorporates feedback from [aws-fpga Issue 458](https://github.com/aws/aws-fpga/issues/458) by making the ```init_ddr``` function, used in design simulations to initialize DDR, more generic by moving out ATG deselection logic to a new ```deselect_atg_hw``` task + + * Bug Fixes: + * Fixed Shell simulation model (sh_bfm) issue on PCIM AXI read data channel back pressure which was described in HDK 1.4.8 Errata. + * Fixed HDK simulation example which [demonstrates DMA and PCIM traffic in parallel](./hdk/cl/examples/cl_dram_dma/verif/tests/test_dma_pcim_concurrent.sv). + + * Package versions used for validation + + | Package | AMI 1.6.0 [2018.3] |AMI 1.5.0 [2018.2] | AMI 1.4.0 [2017.4] | + |---------|------------------------|------------------------|-----------------------| + | OS | Centos 7.6 | Centos 7.5, 7.6 | Centos 7.4 | + | kernel | 3.10.0-957.5.1.el7.x86_64 | 3.10.0-862.11.6.el7.x86_64, 3.10.0-957.1.3.el7.x86_64 | 3.10.0-693.21.1.el7.x86_64 | + | kernel-devel | 3.10.0-957.5.1.el7.x86_64 | 3.10.0-862.11.6.el7.x86_64, 3.10.0-957.1.3.el7.x86_64 | 3.10.0-693.21.1.el7.x86_64 | + | LIBSTDC++ | libstdc++-4.8.5-36.el7.x86_64 | libstdc++-4.8.5-36.el7.x86_64 | libstdc++-4.8.5-16.el7_4.2.x86_64 | + ## Release 1.4.8 (See [ERRATA](./ERRATA.md) for unsupported features) - * FPGA developer kit supports Xilinx SDx/Vivado 2018.3 + * FPGA developer kit supports Xilinx SDx/Vivado 2018.3 * We recommend developers upgrade to v1.4.8 to benefit from the new features, bug fixes, and optimizations. To upgrade, use [Developer AMI v1.6.0](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) on AWS Marketplace. The Developer Kit scripts (hdk_setup.sh or sdaccel_setup.sh) will detect the tool version and update the environment based on requirements needed for Xilinx 2018.3 tools. * Ease of Use features: * Support for importing results into SDx GUI - By importing results from a script-based flow into SDx IDE, developers can leverage the tools for debug/profiling while keeping flexibility of the script-based flow @@ -58,9 +80,6 @@ | LIBSTDC++ | libstdc++-4.8.5-36.el7.x86_64 | libstdc++-4.8.5-36.el7.x86_64 | libstdc++-4.8.5-16.el7_4.2.x86_64 | - - - ## Release 1.4.7 (See [ERRATA](./ERRATA.md) for unsupported features) * Adds [Xilinx Runtime (XRT)](https://github.com/Xilinx/XRT/releases/tag/2018.2_XDF.RC5) Support for Linux kernel 3.10.0-957.1.3.el7.x86_64 & Centos 7.6 diff --git a/hdk/cl/CHECKLIST_BEFORE_BUILDING_CL.md b/hdk/cl/CHECKLIST_BEFORE_BUILDING_CL.md index 0d8b0127..6913b9d1 100644 --- a/hdk/cl/CHECKLIST_BEFORE_BUILDING_CL.md +++ b/hdk/cl/CHECKLIST_BEFORE_BUILDING_CL.md @@ -11,3 +11,5 @@ This checklist includes important items that the developer should check before c 5. Update the timing and placement constraints under `$CL_DIR/build/constraints` for your design specific changes. 6. Update `$CL_DIR/build/scripts/create_dcp_from_cl.tcl` for your design specific changes, specifically around IP sources and xdc files, and your specific design xdc files. + +7. If you ran the HLx flow before, make sure you [follow the steps to switch between HLx and HDK flows](../docs/IPI_GUI_Vivado_Setup.md#hlxhdk_switch) \ No newline at end of file diff --git a/hdk/cl/examples/cl_dram_dma/software/runtime/test_dram_dma_hwsw_cosim.c b/hdk/cl/examples/cl_dram_dma/software/runtime/test_dram_dma_hwsw_cosim.c index 91c9e661..5444622a 100644 --- a/hdk/cl/examples/cl_dram_dma/software/runtime/test_dram_dma_hwsw_cosim.c +++ b/hdk/cl/examples/cl_dram_dma/software/runtime/test_dram_dma_hwsw_cosim.c @@ -167,6 +167,7 @@ int dma_example_hwsw_cosim(int slot_id, size_t buffer_size) setup_send_rdbuf_to_c(read_buffer, buffer_size); printf("Starting DDR init...\n"); init_ddr(); + deselect_atg_hw(); printf("Done DDR init...\n"); #endif printf("filling buffer with random data...\n") ; diff --git a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa index bf14b3d3..f8c9d391 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa +++ b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa @@ -26,7 +26,7 @@ compile: $(COMPLIB_DIR) mkdir -p $(SIM_DIR) cd ${SIM_DIR} && ln -s -f ../questa_complib/modelsim.ini cd $(SIM_DIR) && vlog $(C_FILES) -ccflags "-I$(C_SDK_USR_INC_DIR)" -ccflags "-I$(C_SDK_USR_UTILS_DIR)" -ccflags "-I$(C_COMMON_DIR)/include" -ccflags "-I$(C_COMMON_DIR)/src" -ccflags "-DSV_TEST" -ccflags "-DSCOPE" -ccflags "-DQUESTA_SIM" -ccflags "-DINT_MAIN" -ccflags "-I$(C_INC_DIR)" - cd $(SIM_DIR) && vlog -suppress 2732 +define+DMA_TEST $(DEFAULT_DEFINES) -mfcu -sv -64 -timescale 1ps/1ps -93 -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/secureip -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f + cd $(SIM_DIR) && vlog +define+DMA_TEST $(DEFAULT_DEFINES) -mfcu -sv -64 -timescale 1ps/1ps -93 -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/secureip -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f run: ifeq ($(VIVADO_TOOL_VERSION), v2017.4) diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dma_pcim_concurrent.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dma_pcim_concurrent.sv index da1193ed..c0bb77ad 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dma_pcim_concurrent.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dma_pcim_concurrent.sv @@ -213,13 +213,31 @@ module test_dma_pcim_concurrent(); // Number of instructions, zero based ([31:16] for read, [15:0] for write) tb.poke_ocl(.addr(`NUM_INST), .data(32'h0000_0000)); - + // Start writes and reads - tb.poke_ocl(.addr(`CNTL_REG), .data(`WR_START_BIT | `RD_START_BIT)); - - $display("[%t] : Waiting for PCIe write and read activity to complete", $realtime); + tb.poke_ocl(.addr(`CNTL_REG), .data(`WR_START_BIT)); + //Even in SYNC mode ATG doesn't wait for write response before issuing read transactions. + // adding 500ns wait to account for random back pressure from sh_bfm on write address & write data channels. + $display("[%t] : Waiting for PCIe write activity to complete", $realtime); #500ns; + timeout_count = 0; + do begin + tb.peek_ocl(.addr(`CNTL_REG), .data(read_data)); + timeout_count++; + end while ((read_data[2:0] !== 3'b000) && (timeout_count < 100)); + + if ((timeout_count == 100) && (read_data[2:0] !== 3'b000)) begin + $error("[%t] : *** ERROR *** Timeout waiting for writes to complete.", $realtime); + error_count++; + end + + tb.poke_ocl(.addr(`CNTL_REG), .data(`RD_START_BIT)); + // adding 500ns wait to account for random back pressure from sh_bfm on read request channel. + + $display("[%t] : Waiting for PCIe read activity to complete", $realtime); + #500ns; + timeout_count = 0; do begin tb.peek_ocl(.addr(`CNTL_REG), .data(read_data)); @@ -227,7 +245,7 @@ module test_dma_pcim_concurrent(); end while ((read_data[2:0] !== 3'b000) && (timeout_count < 100)); if ((timeout_count == 100) && (read_data[2:0] !== 3'b000)) begin - $display("[%t] : *** ERROR *** Timeout waiting for writes and reads to complete.", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for reads to complete.", $realtime); error_count++; end else begin // Stop reads and writes ([1] for reads, [0] for writes) @@ -242,7 +260,7 @@ module test_dma_pcim_concurrent(); tb.peek_ocl(.addr(`WR_CYCLE_CNT_HIGH), .data(read_data)); cycle_count[63:32] = read_data; if (cycle_count == 64'h0) begin - $display("[%t] : *** ERROR *** Write Timer value was 0x0 at end of test.", $realtime); + $error("[%t] : *** ERROR *** Write Timer value was 0x0 at end of test.", $realtime); error_count++; end @@ -253,7 +271,7 @@ module test_dma_pcim_concurrent(); tb.peek_ocl(.addr(`RD_CYCLE_CNT_HIGH), .data(read_data)); cycle_count[63:32] = read_data; if (cycle_count == 64'h0) begin - $display("[%t] : *** ERROR *** Read Timer value was 0x0 at end of test.", $realtime); + $error("[%t] : *** ERROR *** Read Timer value was 0x0 at end of test.", $realtime); error_count++; end @@ -268,7 +286,7 @@ module test_dma_pcim_concurrent(); error_addr[63:32] = read_data; tb.peek_ocl(.addr(`RD_ERR_INDEX), .data(read_data)); error_index = read_data[3:0]; - $display("[%t] : *** ERROR *** Read compare error from address 0x%016x, index 0x%1x", $realtime, error_addr, error_index); + $error("[%t] : *** ERROR *** Read compare error from address 0x%016x, index 0x%1x", $realtime, error_addr, error_index); error_count++; end end // else: !if((timeout_count == 100) && (read_data[2:0] !== 3'b000)) @@ -288,7 +306,7 @@ module test_dma_pcim_concurrent(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail || (tb.chk_prot_err_stat())) begin - $display("[%t] : *** TEST FAILED ***", $realtime); + $error("[%t] : *** TEST FAILED ***", $realtime); end else begin $display("[%t] : *** TEST PASSED ***", $realtime); end diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_host_pcim.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_host_pcim.sv new file mode 100644 index 00000000..2f44855d --- /dev/null +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_host_pcim.sv @@ -0,0 +1,250 @@ +// Amazon FPGA Hardware Development Kit +// +// Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Amazon Software License (the "License"). You may not use +// this file except in compliance with the License. A copy of the License is +// located at +// +// http://aws.amazon.com/asl/ +// +// or in the "license" file accompanying this file. This file is distributed on +// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +// implied. See the License for the specific language governing permissions and +// limitations under the License. + +// This test initiates dma and pcim traffic in parallel. + +module test_host_pcim(); + +`define CFG_REG 64'h00 +`define CNTL_REG 64'h08 +`define NUM_INST 64'h10 +`define MAX_RD_REQ 64'h14 + +`define WR_INSTR_INDEX 64'h1c +`define WR_ADDR_LOW 64'h20 +`define WR_ADDR_HIGH 64'h24 +`define WR_DATA 64'h28 +`define WR_LEN 64'h2c + +`define RD_INSTR_INDEX 64'h3c +`define RD_ADDR_LOW 64'h40 +`define RD_ADDR_HIGH 64'h44 +`define RD_DATA 64'h48 +`define RD_LEN 64'h4c + +`define RD_ERR 64'hb0 +`define RD_ERR_ADDR_LOW 64'hb4 +`define RD_ERR_ADDR_HIGH 64'hb8 +`define RD_ERR_INDEX 64'hbc + +`define WR_CYCLE_CNT_LOW 64'hf0 +`define WR_CYCLE_CNT_HIGH 64'hf4 +`define RD_CYCLE_CNT_LOW 64'hf8 +`define RD_CYCLE_CNT_HIGH 64'hfc + +`define WR_START_BIT 32'h00000001 +`define RD_START_BIT 32'h00000002 + + import tb_type_defines_pkg::*; + + int error_count; + int timeout_count; + + logic [3:0] status; + + //transfer1 - length less than 64 byte. + int len0 = 17; + //transfer2 - length between 64 and 256 bytes. + int len1 = 128; + //transfer3 - length greater than 4k bytes. + int len2 = 6000; + //transfer4 - length between 256 and 512 bytes. + int len3 = 300; + + logic ddr_ready; + logic rdata; + + logic [63:0] pcim_addr; + logic [31:0] pcim_data; + + logic [31:0] read_data; + + logic [63:0] cycle_count; + logic [63:0] error_addr; + + logic [3:0] error_index; + + int fail; + + int wr_len; + int rd_len; + + initial begin + + logic [63:0] host_memory_buffer_address; + + + tb.power_up(.clk_recipe_a(ClockRecipe::A1), + .clk_recipe_b(ClockRecipe::B0), + .clk_recipe_c(ClockRecipe::C0)); + + tb.nsec_delay(1000); + tb.poke_stat(.addr(8'h0c), .ddr_idx(0), .data(32'h0000_0000)); + tb.poke_stat(.addr(8'h0c), .ddr_idx(1), .data(32'h0000_0000)); + tb.poke_stat(.addr(8'h0c), .ddr_idx(2), .data(32'h0000_0000)); + + // de-select the ATG hardware + + tb.poke_ocl(.addr(64'h130), .data(0)); + tb.poke_ocl(.addr(64'h230), .data(0)); + tb.poke_ocl(.addr(64'h330), .data(0)); + tb.poke_ocl(.addr(64'h430), .data(0)); + + // AXI_MEMORY_MODEL is used to bypass DDR micron models and run with AXI memory models. More information can be found in the readme.md + +`ifndef AXI_MEMORY_MODEL + // allow memory to initialize + tb.nsec_delay(27000); +`endif + + $display("[%t] : Initializing buffers", $realtime); + + host_memory_buffer_address = 64'h0; + + #100ns; + + //PCIM test + + $display("[%t] : Programming cl_tst registers for PCIe", $realtime); + + pcim_addr = 64'h0000_0000_1234_0000; + pcim_data = 32'h6c93_af50; + + // Enable Incr ID mode, Sync mode, and Read Compare + tb.poke_ocl(.addr(`CFG_REG), .data(32'h0100_0018)); + + // Set the max number of read requests + tb.poke_ocl(.addr(`MAX_RD_REQ), .data(32'h0000_000f)); + + tb.poke_ocl(.addr(`WR_INSTR_INDEX), .data(32'h0000_0000)); // write index + tb.poke_ocl(.addr(`WR_ADDR_LOW), .data(pcim_addr[31:0])); // write address low + tb.poke_ocl(.addr(`WR_ADDR_HIGH), .data(pcim_addr[63:32])); // write address high + tb.poke_ocl(.addr(`WR_DATA), .data(pcim_data[31:0])); // write data + tb.poke_ocl(.addr(`WR_LEN), .data(32'h0000_0001)); // write 128 bytes + + pcim_addr = 64'h0000_0000_1234_0000; + pcim_data = 32'h6c93_af50; + + tb.poke_ocl(.addr(`RD_INSTR_INDEX), .data(32'h0000_0000)); // read index + tb.poke_ocl(.addr(`RD_ADDR_LOW), .data(pcim_addr[31:0])); // read address low + tb.poke_ocl(.addr(`RD_ADDR_HIGH), .data(pcim_addr[63:32])); // read address high + tb.poke_ocl(.addr(`RD_DATA), .data(pcim_data[31:0])); // read data + tb.poke_ocl(.addr(`RD_LEN), .data(32'h0000_0001)); // read 128*16 bytes + + // Number of instructions, zero based ([31:16] for read, [15:0] for write) + tb.poke_ocl(.addr(`NUM_INST), .data(32'h0000_0000)); + + // Start writes and reads + tb.poke_ocl(.addr(`CNTL_REG), .data(`WR_START_BIT)); + //Even in SYNC mode ATG doesn't wait for write response before issuing read transactions. + // adding 500ns wait to account for random back pressure from sh_bfm on write address & write data channels. + $display("[%t] : Waiting for PCIe write activity to complete", $realtime); + #500ns; + timeout_count = 0; + + do begin + tb.peek_ocl(.addr(`CNTL_REG), .data(read_data)); + timeout_count++; + end while ((read_data[2:0] !== 3'b000) && (timeout_count < 100)); + + if ((timeout_count == 100) && (read_data[2:0] !== 3'b000)) begin + $error("[%t] : *** ERROR *** Timeout waiting for writes to complete.", $realtime); + error_count++; + end + + tb.poke_ocl(.addr(`CNTL_REG), .data(`RD_START_BIT)); + // adding 500ns wait to account for random back pressure from sh_bfm on read request channel. + $display("[%t] : Waiting for PCIe read activity to complete", $realtime); + #500ns; + + timeout_count = 0; + do begin + tb.peek_ocl(.addr(`CNTL_REG), .data(read_data)); + timeout_count++; + end while ((read_data[2:0] !== 3'b000) && (timeout_count < 100)); + + if ((timeout_count == 100) && (read_data[2:0] !== 3'b000)) begin + $error("[%t] : *** ERROR *** Timeout waiting for reads to complete.", $realtime); + error_count++; + end else begin + // Stop reads and writes ([1] for reads, [0] for writes) + tb.poke_ocl(.addr(`CNTL_REG), .data(32'h0000_0000)); + + $display("[%t] : Checking some register values", $realtime); + + cycle_count = 64'h0; + // Check that the write timer value is non-zero + tb.peek_ocl(.addr(`WR_CYCLE_CNT_LOW), .data(read_data)); + cycle_count[31:0] = read_data; + tb.peek_ocl(.addr(`WR_CYCLE_CNT_HIGH), .data(read_data)); + cycle_count[63:32] = read_data; + $display("[%t] :[INFO]:Write Timer Value is 0x%016x", $realtime, cycle_count); + if (cycle_count == 64'h0) begin + $error("[%t] : *** ERROR *** Write Timer value was 0x0 at end of test.", $realtime); + error_count++; + end + + cycle_count = 64'h0; + // Check that the read timer value is non-zero + tb.peek_ocl(.addr(`RD_CYCLE_CNT_LOW), .data(read_data)); + cycle_count[31:0] = read_data; + tb.peek_ocl(.addr(`RD_CYCLE_CNT_HIGH), .data(read_data)); + cycle_count[63:32] = read_data; + $display("[%t] :[INFO]:Read Timer Value is 0x%016x", $realtime, cycle_count); + if (cycle_count == 64'h0) begin + $error("[%t] : *** ERROR *** Read Timer value was 0x0 at end of test.", $realtime); + error_count++; + end + + $display("[%t] : Checking for read compare errors", $realtime); + + // Check for compare error + tb.peek_ocl(.addr(`RD_ERR), .data(read_data)); + $display("[%t] :[INFO]:RD_ERR register is 0x%016x", $realtime, read_data); + if (read_data != 32'h0000_0000) begin + tb.peek_ocl(.addr(`RD_ERR_ADDR_LOW), .data(read_data)); + error_addr[31:0] = read_data; + tb.peek_ocl(.addr(`RD_ERR_ADDR_HIGH), .data(read_data)); + error_addr[63:32] = read_data; + $display("[%t] :[INFO]:Error Addr Register Value is 0x%016x", $realtime, error_addr); + tb.peek_ocl(.addr(`RD_ERR_INDEX), .data(read_data)); + error_index = read_data[3:0]; + $error("[%t] : *** ERROR *** Read compare error from address 0x%016x, index 0x%1x", $realtime, error_addr, error_index); + error_count++; + end + end // else: !if((timeout_count == 100) && (read_data[2:0] !== 3'b000)) + // Power down + #500ns; + tb.power_down(); + + //--------------------------- + // Report pass/fail status + //--------------------------- + $display("[%t] : Checking total error count...", $realtime); + if (error_count > 0) begin + fail = 1; + end + $display("[%t] : Detected %3d errors during this test", $realtime, error_count); + + if (fail || (tb.chk_prot_err_stat())) begin + $error("[%t] : *** TEST FAILED ***", $realtime); + end else begin + $display("[%t] : *** TEST PASSED ***", $realtime); + end + + $finish; + end // initial begin + +endmodule // test_host_pcim diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke.sv index a53a653b..bfcee265 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke.sv @@ -106,11 +106,28 @@ module test_peek_poke(); tb.poke_ocl(.addr(`NUM_INST), .data(32'h0000_0000)); // Start writes and reads - tb.poke_ocl(.addr(`CNTL_REG), .data(`WR_START_BIT | `RD_START_BIT)); + tb.poke_ocl(.addr(`CNTL_REG), .data(`WR_START_BIT)); - $display("[%t] : Waiting for PCIe write and read activity to complete", $realtime); + $display("[%t] : Waiting for PCIe write activity to complete", $realtime); #500ns; - + timeout_count = 0; + //Even in SYNC mode ATG doesn't wait for write response before issuing read transactions. + //adding 500ns wait to account for random back pressure from sh_bfm on write address & write data channels. + do begin + tb.peek_ocl(.addr(`CNTL_REG), .data(read_data)); + timeout_count++; + end while ((read_data[2:0] !== 3'b000) && (timeout_count < 100)); + + if ((timeout_count == 100) && (read_data[2:0] !== 3'b000)) begin + $error("[%t] : *** ERROR *** Timeout waiting for writes to complete.", $realtime); + error_count++; + end + + tb.poke_ocl(.addr(`CNTL_REG), .data(`RD_START_BIT)); + // adding 500ns wait to account for random back pressure from sh_bfm on read request channel. + $display("[%t] : Waiting for PCIe read activity to complete", $realtime); + #500ns; + timeout_count = 0; do begin tb.peek_ocl(.addr(`CNTL_REG), .data(read_data)); @@ -118,7 +135,7 @@ module test_peek_poke(); end while ((read_data[2:0] !== 3'b000) && (timeout_count < 100)); if ((timeout_count == 100) && (read_data[2:0] !== 3'b000)) begin - $display("[%t] : *** ERROR *** Timeout waiting for writes and reads to complete.", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for reads to complete.", $realtime); error_count++; end else begin // Stop reads and writes ([1] for reads, [0] for writes) @@ -133,7 +150,7 @@ module test_peek_poke(); tb.peek_ocl(.addr(`WR_CYCLE_CNT_HIGH), .data(read_data)); cycle_count[63:32] = read_data; if (cycle_count == 64'h0) begin - $display("[%t] : *** ERROR *** Write Timer value was 0x0 at end of test.", $realtime); + $error("[%t] : *** ERROR *** Write Timer value was 0x0 at end of test.", $realtime); error_count++; end @@ -144,7 +161,7 @@ module test_peek_poke(); tb.peek_ocl(.addr(`RD_CYCLE_CNT_HIGH), .data(read_data)); cycle_count[63:32] = read_data; if (cycle_count == 64'h0) begin - $display("[%t] : *** ERROR *** Read Timer value was 0x0 at end of test.", $realtime); + $error("[%t] : *** ERROR *** Read Timer value was 0x0 at end of test.", $realtime); error_count++; end @@ -159,7 +176,7 @@ module test_peek_poke(); error_addr[63:32] = read_data; tb.peek_ocl(.addr(`RD_ERR_INDEX), .data(read_data)); error_index = read_data[3:0]; - $display("[%t] : *** ERROR *** Read compare error from address 0x%016x, index 0x%1x", $realtime, error_addr, error_index); + $error("[%t] : *** ERROR *** Read compare error from address 0x%016x, index 0x%1x", $realtime, error_addr, error_index); error_count++; end end @@ -177,7 +194,7 @@ module test_peek_poke(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail || (tb.chk_prot_err_stat())) begin - $display("[%t] : *** TEST FAILED ***", $realtime); + $error("[%t] : *** TEST FAILED ***", $realtime); end else begin $display("[%t] : *** TEST PASSED ***", $realtime); end diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke_len.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke_len.sv index f50794a3..8c6168a7 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke_len.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke_len.sv @@ -114,11 +114,28 @@ module test_peek_poke_len(); tb.poke_ocl(.addr(`NUM_INST), .data(32'h0000_0000)); // Start writes and reads - tb.poke_ocl(.addr(`CNTL_REG), .data(`WR_START_BIT | `RD_START_BIT)); - - $display("[%t] : Waiting for PCIe write and read activity to complete", $realtime); + tb.poke_ocl(.addr(`CNTL_REG), .data(`WR_START_BIT)); + //Even in SYNC mode ATG doesn't wait for write response before issuing read transactions. + // adding 500ns wait to account for random back pressure from sh_bfm on write address & write data channels. + $display("[%t] : Waiting for PCIe write activity to complete", $realtime); #500ns; + timeout_count = 0; + do begin + tb.peek_ocl(.addr(`CNTL_REG), .data(read_data)); + timeout_count++; + end while ((read_data[2:0] !== 3'b000) && (timeout_count < 100)); + + if ((timeout_count == 100) && (read_data[2:0] !== 3'b000)) begin + $error("[%t] : *** ERROR *** Timeout waiting for writes to complete.", $realtime); + error_count++; + end + + tb.poke_ocl(.addr(`CNTL_REG), .data(`RD_START_BIT)); + // adding 500ns wait to account for random back pressure from sh_bfm on read request channel. + $display("[%t] : Waiting for PCIe read activity to complete", $realtime); + #500ns; + timeout_count = 0; do begin tb.peek_ocl(.addr(`CNTL_REG), .data(read_data)); @@ -126,7 +143,7 @@ module test_peek_poke_len(); end while ((read_data[2:0] !== 3'b000) && (timeout_count < 100)); if ((timeout_count == 100) && (read_data[2:0] !== 3'b000)) begin - $display("[%t] : *** ERROR *** Timeout waiting for writes and reads to complete.", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for reads to complete.", $realtime); error_count++; end else begin // Stop reads and writes ([1] for reads, [0] for writes) @@ -141,7 +158,7 @@ module test_peek_poke_len(); tb.peek_ocl(.addr(`WR_CYCLE_CNT_HIGH), .data(read_data)); cycle_count[63:32] = read_data; if (cycle_count == 64'h0) begin - $display("[%t] : *** ERROR *** Write Timer value was 0x0 at end of test.", $realtime); + $error("[%t] : *** ERROR *** Write Timer value was 0x0 at end of test.", $realtime); error_count++; end @@ -152,7 +169,7 @@ module test_peek_poke_len(); tb.peek_ocl(.addr(`RD_CYCLE_CNT_HIGH), .data(read_data)); cycle_count[63:32] = read_data; if (cycle_count == 64'h0) begin - $display("[%t] : *** ERROR *** Read Timer value was 0x0 at end of test.", $realtime); + $error("[%t] : *** ERROR *** Read Timer value was 0x0 at end of test.", $realtime); error_count++; end @@ -167,7 +184,7 @@ module test_peek_poke_len(); error_addr[63:32] = read_data; tb.peek_ocl(.addr(`RD_ERR_INDEX), .data(read_data)); error_index = read_data[3:0]; - $display("[%t] : *** ERROR *** Read compare error from address 0x%016x, index 0x%1x", $realtime, error_addr, error_index); + $error("[%t] : *** ERROR *** Read compare error from address 0x%016x, index 0x%1x", $realtime, error_addr, error_index); error_count++; end end @@ -185,7 +202,7 @@ module test_peek_poke_len(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail || (tb.chk_prot_err_stat())) begin - $display("[%t] : *** TEST FAILED ***", $realtime); + $error("[%t] : *** TEST FAILED ***", $realtime); end else begin $display("[%t] : *** TEST PASSED ***", $realtime); end diff --git a/hdk/cl/examples/cl_hello_world/verif/tests/test_gl_cntr.sv b/hdk/cl/examples/cl_hello_world/verif/tests/test_gl_cntr.sv index 2f218188..0c7ee941 100644 --- a/hdk/cl/examples/cl_hello_world/verif/tests/test_gl_cntr.sv +++ b/hdk/cl/examples/cl_hello_world/verif/tests/test_gl_cntr.sv @@ -13,7 +13,10 @@ // implied. See the License for the specific language governing permissions and // limitations under the License. - +//------------------------------------------------------------------------------- +// Description: This test is a heartbeat check and checks the global counters values +// before and after a poke & peek operation on CL register. +//-------------------------------------------------------------------------------- module test_gl_cntr(); import tb_type_defines_pkg::*; @@ -37,6 +40,7 @@ import tb_type_defines_pkg::*; $display ("Global counter 0 value before poke is 0x%x \n", glcntr0); $display ("Global counter 1 value before poke is 0x%x \n", glcntr1); +// write to cl register. when read back we should see byte swap on this register. tb.poke(.addr(`HELLO_WORLD_REG_ADDR), .data(32'hDEAD_BEEF), .id(AXI_ID), .size(DataSize::UINT16), .intf(AxiPort::PORT_OCL)); // write register glcntr0 = tb.get_global_counter_0(); @@ -54,13 +58,17 @@ import tb_type_defines_pkg::*; tb.peek(.addr(`HELLO_WORLD_REG_ADDR), .data(rdata), .id(AXI_ID), .size(DataSize::UINT16), .intf(AxiPort::PORT_OCL)); // start read & write $display ("Reading 0x%x from address 0x%x", rdata, `HELLO_WORLD_REG_ADDR); + if (rdata == 32'hEFBE_ADDE) // Check for byte swap in register read + $display ("TEST PASSED"); + else + $error ("TEST FAILED"); + glcntr0 = tb.get_global_counter_0(); glcntr1 = tb.get_global_counter_1(); $display ("Global counter 0 value after peek is 0x%x \n", glcntr0); $display ("Global counter 1 value after peek is 0x%x \n", glcntr1); - $display ("*** TEST PASSED ***"); $finish; end // initial begin diff --git a/hdk/cl/examples/cl_hello_world/verif/tests/test_hello_world.sv b/hdk/cl/examples/cl_hello_world/verif/tests/test_hello_world.sv index 6401b30b..dd0f749b 100644 --- a/hdk/cl/examples/cl_hello_world/verif/tests/test_hello_world.sv +++ b/hdk/cl/examples/cl_hello_world/verif/tests/test_hello_world.sv @@ -13,6 +13,10 @@ // implied. See the License for the specific language governing permissions and // limitations under the License. +//------------------------------------------------------------------------------ +// Description: This test checks the byte swap feature of the hello_world CL. It also checks +// if the upper word of the CL register is written to Vdip +//------------------------------------------------------------------------------- module test_hello_world(); @@ -46,7 +50,7 @@ logic [15:0] vled_value; if (rdata == 32'hEFBE_ADDE) // Check for byte swap in register read $display ("TEST PASSED"); else - $display ("TEST FAILED"); + $error ("TEST FAILED"); tb.peek_ocl(.addr(`VLED_REG_ADDR), .data(rdata)); // start read $display ("Reading 0x%x from address 0x%x", rdata, `VLED_REG_ADDR); @@ -54,7 +58,7 @@ logic [15:0] vled_value; if (rdata == 32'h0000_BEEF) // Check for LED register read $display ("*** TEST PASSED ***"); else - $display ("*** TEST FAILED ***"); + $error ("*** TEST FAILED ***"); vled_value = tb.get_virtual_led(); diff --git a/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.questa index 1307e4e4..46ff2e70 100644 --- a/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.questa +++ b/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.questa @@ -33,7 +33,7 @@ run: ifeq ($(VIVADO_TOOL_VERSION), v2017.4) cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_15 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_16 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_14 -L $(COMPLIB_DIR)/fifo_generator_v13_2_1 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_14 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -do "run -all; quit -f" tb glbl $(TEST) else ifeq ($(VIVADO_TOOL_VERSION), v2018.3) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_2_3 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -do "run -all; quit -f" tb glbl $(TEST) + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_2_3 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -do "run -all; quit -f" tb glbl $(TEST) else cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_2_2 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -do "run -all; quit -f" tb glbl $(TEST) endif diff --git a/hdk/cl/examples/cl_sde/verif/scripts/Makefile.ies b/hdk/cl/examples/cl_sde/verif/scripts/Makefile.ies new file mode 100644 index 00000000..59da02e6 --- /dev/null +++ b/hdk/cl/examples/cl_sde/verif/scripts/Makefile.ies @@ -0,0 +1,43 @@ +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + + +################################################################## +## Makefile For IES compiles and simulations +## Step to run : +## 1. make create_libs IES=1 -> To generate xilinx compile +## libraries. This is a one time step +## 2. make all IES=1 -> Runs the test +################################################################## + +compile: $(COMPLIB_DIR) + mkdir -p $(SIM_DIR) + cd $(SIM_DIR) && ln -s -f ../ies_complib/cds.lib + cd $(SIM_DIR) && ln -s -f ../ies_complib/hdl.var + cd $(SIM_DIR) && gcc -fPIC -g -shared -I$(C_SDK_USR_INC_DIR) -I$(C_SDK_USR_UTILS_DIR) -I$(C_COMMON_DIR)/include -I$(C_COMMON_DIR)/src -I$(C_INC_DIR) -DSV_TEST -DSCOPE -DIES_SIM -DINT_MAIN -o libdpi.so $(C_FILES) -I/`ncroot`/tools/include + cd $(SIM_DIR) && irun -64bit -elaborate +libext+.v+.sv -disable_sem2009 -l compile.ies.log -I$(C_SDK_USR_INC_DIR) -I$(C_SDK_USR_UTILS_DIR) -I$(C_COMMON_DIR) -define SV_TEST -define DMA_TEST -define SCOPE -define IES_SIM $(DEFAULT_DEFINES) -I$(C_INC_DIR)/include -I$(C_INC_DIR)/src -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f -top tb -top glbl -top $(TEST) $(DEFINES) $(TEST_NAME) -timescale 1ps/1ps + +run: + +ifeq ($(TEST),test_null) + cd $(SIM_DIR) && irun -R -access +rwc -timescale 1ps/1ps -l $(C_TEST).log $(PLUSARGS) +vpdfile+$(TEST).vpd +else + cd $(SIM_DIR) && irun -R -access +rwc -timescale 1ps/1ps -l $(TEST).log $(PLUSARGS) +vpdfile+$(TEST).vpd +endif + +$(COMPLIB_DIR): + cd $(SIM_ROOT) && echo "compile_simlib -language all -dir $(COMPLIB_DIR) -simulator $(SIMULATOR) -library all -family all" > create_libs.tcl + cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl + cd $(SIM_ROOT) && rm -rf create_libs.tcl diff --git a/hdk/cl/examples/cl_sde/verif/scripts/top.ies.f b/hdk/cl/examples/cl_sde/verif/scripts/top.ies.f new file mode 100644 index 00000000..3071ce0b --- /dev/null +++ b/hdk/cl/examples/cl_sde/verif/scripts/top.ies.f @@ -0,0 +1,113 @@ +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + ++define+IES_SIM ++define+CARD_1=card ++define+CL_NAME=cl_sde ++define+SIMULATION ++define+NO_SDE_DEBUG_ILA ++define+DISABLE_VJTAG_DEBUG + ++libext+.v ++libext+.sv ++libext+.svh + +-y ${CL_ROOT}/../common/design +-y ${CL_ROOT}/design +-y ${SH_LIB_DIR} +-y ${SH_INF_DIR} +-y ${HDK_SHELL_DESIGN_DIR}/sh_ddr/sim +-y ${HDK_SHELL_DESIGN_DIR}/ip/cl_debug_bridge/bd_0/hdl +-y ${HDK_SHELL_DESIGN_DIR}/ip/cl_debug_bridge/sim + ++incdir+${CL_ROOT}/../common/design ++incdir+${CL_ROOT}/design ++incdir+${CL_ROOT}/verif/tests ++incdir+${SH_LIB_DIR} ++incdir+${SH_INF_DIR} ++incdir+${SH_SH_DIR} ++incdir+${HDK_COMMON_DIR}/verif/include ++incdir+${HDK_SHELL_DESIGN_DIR}/ip/cl_debug_bridge/bd_0/ip/ip_0/hdl/verilog ++incdir+${HDK_SHELL_DESIGN_DIR}/ip/axi_register_slice_light/hdl ++incdir+${HDK_SHELL_DESIGN_DIR}/sh_ddr/sim ++incdir+${HDK_SHELL_DESIGN_DIR}/interfaces + +${CL_ROOT}/../common/design/cl_common_defines.vh +${CL_ROOT}/design/cl_sde_defines.vh +${HDK_SHELL_DESIGN_DIR}/ip/ila_vio_counter/sim/ila_vio_counter.v +${HDK_SHELL_DESIGN_DIR}/ip/ila_0/sim/ila_0.v +${HDK_SHELL_DESIGN_DIR}/ip/cl_debug_bridge/bd_0/sim/bd_a493.v +${HDK_SHELL_DESIGN_DIR}/ip/cl_debug_bridge/bd_0/ip/ip_0/sim/bd_a493_xsdbm_0.v +${HDK_SHELL_DESIGN_DIR}/ip/cl_debug_bridge/bd_0/ip/ip_0/hdl/xsdbm_v3_0_vl_rfs.v +${HDK_SHELL_DESIGN_DIR}/ip/cl_debug_bridge/bd_0/ip/ip_0/hdl/ltlib_v1_0_vl_rfs.v +${HDK_SHELL_DESIGN_DIR}/ip/cl_debug_bridge/bd_0/ip/ip_1/sim/bd_a493_lut_buffer_0.v +${HDK_SHELL_DESIGN_DIR}/ip/cl_debug_bridge/bd_0/ip/ip_1/hdl/lut_buffer_v2_0_vl_rfs.v +${HDK_SHELL_DESIGN_DIR}/ip/cl_debug_bridge/bd_0/hdl/bd_a493_wrapper.v +${HDK_SHELL_DESIGN_DIR}/ip/cl_debug_bridge/sim/cl_debug_bridge.v +${HDK_SHELL_DESIGN_DIR}/ip/vio_0/sim/vio_0.v +${HDK_SHELL_DESIGN_DIR}/ip/axi_register_slice_light/sim/axi_register_slice_light.v +${HDK_SHELL_DESIGN_DIR}/ip/axi_register_slice/sim/axi_register_slice.v +${HDK_SHELL_DESIGN_DIR}/ip/axi_register_slice_light/hdl/axi_register_slice_v2_1_vl_rfs.v +${HDK_SHELL_DESIGN_DIR}/ip/axi_register_slice_light/hdl/axi_infrastructure_v1_1_vl_rfs.v +${HDK_SHELL_DESIGN_DIR}/ip/axi_clock_converter_0/simulation/fifo_generator_vlog_beh.v +${HDK_SHELL_DESIGN_DIR}/ip/axi_clock_converter_0/hdl/fifo_generator_v13_2_rfs.v +${HDK_SHELL_DESIGN_DIR}/ip/axi_clock_converter_0/hdl/axi_clock_converter_v2_1_vl_rfs.v +${HDK_SHELL_DESIGN_DIR}/ip/axi_clock_converter_0/sim/axi_clock_converter_0.v +${CL_ROOT}/ip/ila_axi4/sim/ila_axi4.v +${CL_ROOT}/ip/ila_axi4_512/sim/ila_axi4_512.v +${CL_ROOT}/ip/ila_axis/sim/ila_axis.v +${CL_ROOT}/ip/ila_sde_c2h_buf/sim/ila_sde_c2h_buf.v +${CL_ROOT}/ip/ila_sde_c2h_dm/sim/ila_sde_c2h_dm.v +${CL_ROOT}/ip/ila_sde_h2c_buf/sim/ila_sde_h2c_buf.v +${CL_ROOT}/ip/ila_sde_h2c_dm/sim/ila_sde_h2c_dm.v +${CL_ROOT}/ip/ila_sde_ps/sim/ila_sde_ps.v +${CL_ROOT}/ip/ila_sde_wb/sim/ila_sde_wb.v +${CL_ROOT}/lib/axis_flop_fifo.sv +${CL_ROOT}/lib/bram_1w1r.sv +${CL_ROOT}/lib/flop_fifo_in.sv +${CL_ROOT}/lib/ft_fifo_p.v +${CL_ROOT}/lib/ft_fifo.v +${CL_ROOT}/lib/ram_fifo_ft.sv +${CL_ROOT}/lib/rr_arb.sv +${CL_ROOT}/design/cl_id_defines.vh +${CL_ROOT}/design/sde_pkg.sv +${CL_ROOT}/design/cl_pkt_tst.sv +${CL_ROOT}/design/ila_axi4_wrapper.sv +${CL_ROOT}/design/axi_prot_chk.sv +${CL_ROOT}/design/cl_tst.sv +${CL_ROOT}/design/cl_sde_srm.sv +${CL_ROOT}/design/sde_c2h_axis.sv +${CL_ROOT}/design/sde_c2h_buf.sv +${CL_ROOT}/design/sde_c2h_cfg.sv +${CL_ROOT}/design/sde_c2h_data.sv +${CL_ROOT}/design/sde_c2h.sv +${CL_ROOT}/design/sde_h2c_axis.sv +${CL_ROOT}/design/sde_h2c_buf.sv +${CL_ROOT}/design/sde_h2c_cfg.sv +${CL_ROOT}/design/sde_h2c_data.sv +${CL_ROOT}/design/sde_h2c.sv +${CL_ROOT}/design/sde_pm.sv +${CL_ROOT}/design/sde_ps_acc.sv +${CL_ROOT}/design/sde_ps.sv +${CL_ROOT}/design/sde_wb.sv +${CL_ROOT}/design/sde_desc.sv +${CL_ROOT}/design/sde.sv +${HDK_COMMON_DIR}/verif/models/base/gen_buf_t.sv +${HDK_COMMON_DIR}/verif/models/stream_bfm/stream_bfm.sv +${CL_ROOT}/design/cl_sde.sv + +-f ${HDK_COMMON_DIR}/verif/tb/filelists/tb.${SIMULATOR}.f +${HDK_COMMON_DIR}/verif/tb/sv/dma_classes.sv +${TEST_NAME} diff --git a/hdk/cl/examples/cl_uram_example/software/runtime/test_uram_example.c b/hdk/cl/examples/cl_uram_example/software/runtime/test_uram_example.c index 81a3a0f9..7a072173 100644 --- a/hdk/cl/examples/cl_uram_example/software/runtime/test_uram_example.c +++ b/hdk/cl/examples/cl_uram_example/software/runtime/test_uram_example.c @@ -142,7 +142,7 @@ uint32_t glb_value; printf("Enter your command followed by your 32 bits hexadecimal value (without 0x)\n"); printf("Note that only the [28:0] bits will be stored in the URAM\n"); -#ifndef VIVADO_SIM +#ifndef SV_TEST printf("Example: find CAFE4B1D\n"); printf("Example: del CAFE4B1D\n"); scanf("%s %x", command, &value); @@ -162,7 +162,7 @@ uint32_t glb_value; printf("After setting command value \n"); -#ifndef VIVADO_SIM +#ifndef SV_TEST // The 3 MSB are used to encode {find, add, del} when writing to the CL // On a read they indicate {find_ok, del_ok, busy} diff --git a/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.questa index 2a86de74..0cb6d70e 100644 --- a/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.questa +++ b/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.questa @@ -36,7 +36,7 @@ ifeq ($(TEST),test_null) else cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_15 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_16 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_14 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_14 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) endif -else ifeq($(VIVADO_TOOL_VERSION),v2018.3) +else ifeq ($(VIVADO_TOOL_VERSION),v2018.3) ifeq ($(TEST),test_null) cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) else diff --git a/hdk/cl/examples/cl_uram_example/verif/tests/test_uram_example.sv b/hdk/cl/examples/cl_uram_example/verif/tests/test_uram_example.sv index 9731efe5..21220a73 100644 --- a/hdk/cl/examples/cl_uram_example/verif/tests/test_uram_example.sv +++ b/hdk/cl/examples/cl_uram_example/verif/tests/test_uram_example.sv @@ -14,6 +14,10 @@ // limitations under the License. // This test tests add, delete and find operations of a URAM. +//------------------------------------------------------------------------------------------ +// Description: This test checks if Find, Add & Del commands implemented by the uram_example CL work accurately. +//------------------------------------------------------------------------------------------- + module test_uram_example(); import tb_type_defines_pkg::*; @@ -41,22 +45,23 @@ logic [31:0] glb_value; tb.poke(.addr(64'h500), .data(value), .intf(AxiPort::PORT_OCL)); - // Wait for the busy status to be cleared + // Wait for the busy status to be cleared. busy = 1; do begin if (timeout == 10) begin - $display("Timeout - Something went wrong with the HW. Please do\n"); + $display("Timeout - Command not finished after 100ns."); + $error("TEST FAILED") ; $finish; end if (timeout) begin - $display("Please wait, it may take time ...\n"); + $display("Please wait, Command in execution ...\n"); end // Wait for the HW to process tb.nsec_delay(10000); timeout++; - // Read + // Read CL register to determine if the command is done. bit 29 indicates command done. tb.peek(.addr(64'h500), .data(value), .intf(AxiPort::PORT_OCL)); find_ok = value[31]; @@ -80,6 +85,7 @@ logic [31:0] glb_value; end else begin $display("The value 0x%x has been added to the URAM successfully\n", value); + $display("TEST PASSED"); end end // if (find_ok == 1) endtask // uram_task diff --git a/hdk/common/shell_v04261818/design/sh_ddr/sim/axi4_slave_bfm.sv b/hdk/common/shell_v04261818/design/sh_ddr/sim/axi4_slave_bfm.sv index 39de4053..8ff2f925 100644 --- a/hdk/common/shell_v04261818/design/sh_ddr/sim/axi4_slave_bfm.sv +++ b/hdk/common/shell_v04261818/design/sh_ddr/sim/axi4_slave_bfm.sv @@ -13,7 +13,7 @@ // implied. See the License for the specific language governing permissions and // limitations under the License. -module axi4_slave_bfm +module axi4_slave_bfm #( parameter ECC_EN = 0, parameter ECC_ADDR_HI = 'h410, parameter ECC_ADDR_LO = 'h400, parameter RND_ECC_EN = 0, parameter RND_ECC_WEIGHT = 100) ( input clk_core, @@ -29,19 +29,19 @@ module axi4_slave_bfm input[1:0] cl_sh_ddr_awburst, //Note only INCR/WRAP supported. If un-supported mode on this signal, will default to INCR //input[10:0] cl_sh_ddr_awuser, input cl_sh_ddr_awvalid, - output logic[2:0] sh_cl_ddr_awready, + output logic sh_cl_ddr_awready, input[15:0] cl_sh_ddr_wid, input[511:0] cl_sh_ddr_wdata, input[63:0] cl_sh_ddr_wstrb, - input[2:0] cl_sh_ddr_wlast, - input[2:0] cl_sh_ddr_wvalid, - output logic[2:0] sh_cl_ddr_wready, + input cl_sh_ddr_wlast, + input cl_sh_ddr_wvalid, + output logic sh_cl_ddr_wready, output logic[15:0] sh_cl_ddr_bid, output logic[1:0] sh_cl_ddr_bresp, - output logic[2:0] sh_cl_ddr_bvalid, - input[2:0] cl_sh_ddr_bready, + output logic sh_cl_ddr_bvalid, + input cl_sh_ddr_bready, input[15:0] cl_sh_ddr_arid, input[63:0] cl_sh_ddr_araddr, @@ -49,15 +49,15 @@ module axi4_slave_bfm input[2:0] cl_sh_ddr_arsize, //input[10:0] cl_sh_ddr_aruser, input[1:0] cl_sh_ddr_arburst, //Note only INCR/WRAP supported. If un-supported mode on this signal, will default to INCR - input[2:0] cl_sh_ddr_arvalid, - output logic[2:0] sh_cl_ddr_arready, + input cl_sh_ddr_arvalid, + output logic sh_cl_ddr_arready, output logic[15:0] sh_cl_ddr_rid, output logic[511:0] sh_cl_ddr_rdata, output logic[1:0] sh_cl_ddr_rresp, - output logic[2:0] sh_cl_ddr_rlast, - output logic[2:0] sh_cl_ddr_rvalid, - input[2:0] cl_sh_ddr_rready + output logic sh_cl_ddr_rlast, + output logic sh_cl_ddr_rvalid, + input cl_sh_ddr_rready ); `include "axi_bfm_defines.svh" diff --git a/hdk/common/shell_v04261818/design/sh_ddr/sim/axi_bfm_defines.svh b/hdk/common/shell_v04261818/design/sh_ddr/sim/axi_bfm_defines.svh index 4c15afe5..ec92932a 100644 --- a/hdk/common/shell_v04261818/design/sh_ddr/sim/axi_bfm_defines.svh +++ b/hdk/common/shell_v04261818/design/sh_ddr/sim/axi_bfm_defines.svh @@ -19,7 +19,7 @@ typedef struct { logic [63:0] addr; logic [7:0] len; logic [2:0] size; - logic [5:0] id; + logic [15:0] id; logic [1:0] resp; logic last; } AXI_Command; @@ -27,7 +27,7 @@ typedef struct { typedef struct { logic [511:0] data; logic [63:0] strb; - logic [5:0] id; + logic [15:0] id; logic last; } AXI_Data; diff --git a/hdk/common/verif/include/sh_dpi_tasks.svh b/hdk/common/verif/include/sh_dpi_tasks.svh index 7f845e90..15996beb 100755 --- a/hdk/common/verif/include/sh_dpi_tasks.svh +++ b/hdk/common/verif/include/sh_dpi_tasks.svh @@ -45,6 +45,7 @@ import tb_type_defines_pkg::*; export "DPI-C" task sv_fpga_start_cl_to_buffer; `endif export "DPI-C" task init_ddr; + export "DPI-C" task deselect_atg_hw; static int h2c_desc_index = 0; static int c2h_desc_index = 0; @@ -208,16 +209,22 @@ end poke_stat(.addr(8'h0c), .ddr_idx(1), .data(32'h0000_0000)); poke_stat(.addr(8'h0c), .ddr_idx(2), .data(32'h0000_0000)); - //de-select the ATG hardware + + // allow memory to initialize + nsec_delay(27000); + endtask // initialize_sh_model + + + task deselect_atg_hw(); + + //de-select the ATG hardware poke_ocl(.addr(64'h130), .data(0)); poke_ocl(.addr(64'h230), .data(0)); poke_ocl(.addr(64'h330), .data(0)); poke_ocl(.addr(64'h430), .data(0)); - - // allow memory to initialize - nsec_delay(27000); - endtask // initialize_sh_model + nsec_delay(1000); + endtask `ifdef DMA_TEST //DPI task to transfer HOST to CL data. diff --git a/hdk/common/verif/models/sh_bfm/axi_bfm_defines.svh b/hdk/common/verif/models/sh_bfm/axi_bfm_defines.svh index 4c15afe5..ec92932a 100644 --- a/hdk/common/verif/models/sh_bfm/axi_bfm_defines.svh +++ b/hdk/common/verif/models/sh_bfm/axi_bfm_defines.svh @@ -19,7 +19,7 @@ typedef struct { logic [63:0] addr; logic [7:0] len; logic [2:0] size; - logic [5:0] id; + logic [15:0] id; logic [1:0] resp; logic last; } AXI_Command; @@ -27,7 +27,7 @@ typedef struct { typedef struct { logic [511:0] data; logic [63:0] strb; - logic [5:0] id; + logic [15:0] id; logic last; } AXI_Data; diff --git a/hdk/common/verif/models/sh_bfm/sh_bfm.sv b/hdk/common/verif/models/sh_bfm/sh_bfm.sv index 3d9e5938..846bdf81 100644 --- a/hdk/common/verif/models/sh_bfm/sh_bfm.sv +++ b/hdk/common/verif/models/sh_bfm/sh_bfm.sv @@ -1233,7 +1233,10 @@ module sh_bfm #( first_rd_beat = 1'b0; end - beat = {512{1'b1}}; + beat = {512{1'b1}}; + + if (cl_sh_pcim_rready) begin + for(int i=rd_addr[5:2]; i<16; i++) begin logic [31:0] c; @@ -1262,7 +1265,7 @@ module sh_bfm #( $display("[%t] : DEBUG beat 0x%0128x", $realtime, beat); end sh_cl_pcim_rdata <= beat; - + end //if(cl_sh_pcim_rready) end else begin sh_cl_pcim_rvalid <= 1'b0; diff --git a/hdk/docs/IPI_GUI_Vivado_Setup.md b/hdk/docs/IPI_GUI_Vivado_Setup.md index d5f5c803..0d1d628d 100644 --- a/hdk/docs/IPI_GUI_Vivado_Setup.md +++ b/hdk/docs/IPI_GUI_Vivado_Setup.md @@ -26,19 +26,22 @@ Open the following file in a text editor ~/.Xilinx/Vivado/init.tcl or ~/.Xilinx/ If either of these files does not exist, change directories into ~/.Xilinx/Vivado and use the following command to create the file. -touch Vivado_init.tcl +`touch Vivado_init.tcl` Get the absolute path of the $HDK\_SHELL\_DIR with the following command. -echo $HDK\_SHELL\_DIR +`echo $HDK_SHELL_DIR` -If your $HDK\_SHELL\_DIR is empty or does not list /$HDK\_SHELL\_DIR/, then you may need to source the [hdk_setup](../README.md). +**NOTE: If your $HDK\_SHELL\_DIR is empty or does not list /$HDK\_SHELL\_DIR/, then you may need to source the [hdk_setup](../README.md).** In init.tcl or Vivado\_init.tcl, add the following line based upon the $HDK\_SHELL\_DIR path. -source /hlx/hlx_setup.tcl +`source $::env(HDK_SHELL_DIR)/hlx/hlx_setup.tcl` -Everytime Vivado is loaded, this script will always be sourced and IP integrator features will be automatically loaded. Remove this line if you no longer wish to use HLx Flow. + +### Switching between HDK and HLx flows +* ~/.Xilinx/Vivado/init.tcl or ~/.Xilinx/Vivado/Vivado_init.tcl scripts are sourced when Vivado starts up. Once you go through the Linux Install setup, IP integrator features will be automatically loaded every time. +* If you wish to switch to the HDK flow, Please remove the `source $::env(HDK_SHELL_DIR)/hlx/hlx_setup.tcl` line from your init.tcl or Vivado\_init.tcl file # Windows Install diff --git a/hdk/docs/load_times.md b/hdk/docs/load_times.md new file mode 100644 index 00000000..2d458dc4 --- /dev/null +++ b/hdk/docs/load_times.md @@ -0,0 +1,39 @@ +# Reducing AFI load times + +To support customers using multiple FPGA images in sequence, AWS strives to minimize the time to load an Amazon FPGA image (AFI). +Many of these improvements will be available to users with no action required through automatic improvements to Amazon systems, but customers can use AWS F1 features like caching and [data retention](data_retention.md) to maximize AFI pipeline performance. +Data retention (the -D flag) is especially valuable because it significantly reduces AFI load times, and can eliminate the time consumption of copying and reloading data from FPGA DRAM. + +Customers can view locally cached AFIs via fpga-describe-local-image, and request AFIs be cached without actually modifying the FPGA with the -p flag in fpga-describe-local-image. + +## Caching recently used AFIs +AWS will automatically cache the most recent 16 AFIs used on that FPGA slot. If more than 16 AFIs are loaded, the least recently used AFI will be removed from the cache. The cache will also be cleared when an FPGA slot is cleared with fpga-clear-local-image, or when an instance is stopped or terminated. + +## Prefetching an upcoming AFI +If more than 16 AFIs are needed for an AFI pipeline, customers will need to prefetch AFIs into the cache to maximize performance. Prefetching an AFI doesn't affect currently running FPGA images, so it is safe to prefetch an AFI while the currently running AFI is processing data. Prefetching just returns 0 without printing if the prefetch was successful, since it doesn't change the FPGA state. If the cache is already full of 16 AFIs, prefetching an AFI will remove the least recently used AFI from the cache. + +To prefetch an AFI into the cache, use fpga-load-local-image with the -P flag, for example: +``` +sudo fpga-load-local-image -S 0 -I agfi-0fcf87119b8e97bf3 -P +``` + +## Viewing cached AFIs +To see which AGFIs are cached on an FPGA slot, use fpga-describe-local-image with the -M flag: + +``` +sudo fpga-describe-local-image -S 0 -M +AFI 0 agfi-01dc2520aaf357e86 loaded 0 ok 0 0x04261818 +AFIDEVICE 0 0x1d0f 0xf001 0000:00:1d.0 +.... +Cached agfis: + agfi-0fcf87119b8e97bf3 + agfi-01dc2520aaf357e86 +``` + +## Other load time considerations + +To minimize AFI load time, in addition to caching the AGFI and using data retention (-D flag), also ensure: + +* The AFI being loaded is on the same shell as the previous AFI +* The AFI being loaded is using a new shell, especially shell 1.4 or above +* The FPGA image tools are up to date from Github diff --git a/hdk/hdk_version.txt b/hdk/hdk_version.txt index 960d4ed1..a1664e02 100644 --- a/hdk/hdk_version.txt +++ b/hdk/hdk_version.txt @@ -1 +1 @@ -HDK_VERSION=1.4.8 +HDK_VERSION=1.4.9 diff --git a/hdk/tests/simulation_tests/test_sims.py b/hdk/tests/simulation_tests/test_sims.py index dada6e34..158038e2 100644 --- a/hdk/tests/simulation_tests/test_sims.py +++ b/hdk/tests/simulation_tests/test_sims.py @@ -300,6 +300,14 @@ def test_cl_dram_dma__dma_pcis_concurrent__sv_fast_ecc_rnd(self, simulator): self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + def test_cl_dram_dma__host_pcim__sv(self, simulator): + + test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' + test_name = 'test_host_pcim' + test_type = 'sv' + + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + def test_cl_dram_dma__dma_pcim_concurrent__sv(self, simulator): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' diff --git a/sdk/tests/test_fpga_tools.py b/sdk/tests/test_fpga_tools.py index def4a6ca..95bbae4d 100644 --- a/sdk/tests/test_fpga_tools.py +++ b/sdk/tests/test_fpga_tools.py @@ -104,17 +104,18 @@ def test_describe_local_image(self): # Test -M (Return FPGA image hardware metrics.) (rc, stdout, stderr) = self.run_cmd("sudo fpga-describe-local-image -M -S {}".format(slot), echo=True) - assert len(stdout) == 57 + assert len(stdout) == 58 assert len(stderr) == 1 assert stdout[0] == 'AFI {} none cleared 1 ok 0 {}'.format(slot, self.shell_version) assert stdout[1] == 'AFIDEVICE {} 0x1d0f 0x1042 {}'.format(slot, self.slot2device[slot]) assert stdout[2] == 'sdacl-slave-timeout=0' assert stdout[50] == 'Clock Group C Frequency (Mhz)' assert stdout[51] == '0 0 ' + assert stdout[-2].startswith('Cached agfis:') # Test -C (Return FPGA image hardware metrics (clear on read).) - (rc, stdout, stderr) = self.run_cmd("sudo fpga-describe-local-image -M -S {}".format(slot), echo=True) - assert len(stdout) == 57 + (rc, stdout, stderr) = self.run_cmd("sudo fpga-describe-local-image -C -M -S {}".format(slot), echo=True) + assert len(stdout) == 58 assert len(stderr) == 1 assert stdout[0] == 'AFI {} none cleared 1 ok 0 {}'.format(slot, self.shell_version) assert stdout[1] == 'AFIDEVICE {} 0x1d0f 0x1042 {}'.format(slot, self.slot2device[slot]) @@ -204,6 +205,14 @@ def test_clear_local_image(self): assert stdout[1] == 'AFIDEVICE {} 0x1d0f 0x1042 {}'.format(slot, self.slot2device[slot]) break + def test_afi_caching(self): + for slot in range(self.num_slots): + self.fpga_clear_local_image(slot) + (rc, stdout, stderr) = self.run_cmd("sudo fpga-load-local-image --request-timeout {} -S {} -I {} -P".format(self.DEFAULT_REQUEST_TIMEOUT, slot, self.cl_dram_dma_agfi), echo=True) + assert rc == 0 + (rc, stdout, stderr) = self.run_cmd("sudo fpga-describe-local-image -M -S {}".format(slot), echo=True) + assert re.match(self.cl_dram_dma_agfi, stdout[-2].strip()) + @pytest.mark.skip(reason="No way to test right now.") def test_start_virtual_jtag(self): assert False diff --git a/sdk/userspace/fpga_libs/fpga_dma/fpga_dma_utils.c b/sdk/userspace/fpga_libs/fpga_dma/fpga_dma_utils.c index ca3de9a8..75c6a7d8 100644 --- a/sdk/userspace/fpga_libs/fpga_dma/fpga_dma_utils.c +++ b/sdk/userspace/fpga_libs/fpga_dma/fpga_dma_utils.c @@ -221,7 +221,7 @@ int fpga_pci_get_dma_device_num(enum fpga_dma_driver which_driver, * this function, which always reads from the same directory. The man page * for readdir says the POSIX spec does not require threadsafety. */ - pthread_mutex_lock(&fpga_pci_readdir_mutex); + fpga_acquire_readdir_lock(); #endif while (true) { @@ -263,7 +263,7 @@ int fpga_pci_get_dma_device_num(enum fpga_dma_driver which_driver, /* continue... */ } #if !defined(FPGA_PCI_USE_READDIR_R) - pthread_mutex_unlock(&fpga_pci_readdir_mutex); + fpga_release_readdir_lock(); #endif fail_on_with_code(_device_num == -1, err, rc, FPGA_ERR_PCI_MISSING, "Unable to find device num"); @@ -275,7 +275,7 @@ int fpga_pci_get_dma_device_num(enum fpga_dma_driver which_driver, err_unlock: #if !defined(FPGA_PCI_USE_READDIR_R) - pthread_mutex_unlock(&fpga_pci_readdir_mutex); + fpga_release_readdir_lock(); #endif err: diff --git a/sdk/userspace/fpga_libs/fpga_mgmt/afi_cmd_api.h b/sdk/userspace/fpga_libs/fpga_mgmt/afi_cmd_api.h index dc0f0508..262b7eff 100644 --- a/sdk/userspace/fpga_libs/fpga_mgmt/afi_cmd_api.h +++ b/sdk/userspace/fpga_libs/fpga_mgmt/afi_cmd_api.h @@ -23,7 +23,7 @@ #include -#define AFI_CMD_DATA_LEN 512 +#define AFI_CMD_DATA_LEN 4096 #define AFI_CMD_API_MAJOR_VERSION 0x2 diff --git a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c index 530b1a3d..87110d4c 100644 --- a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c +++ b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c @@ -24,8 +24,8 @@ #include "fpga_mgmt_internal.h" /** Synchronous API (load/clear) default timeout and delay msecs */ -#define FPGA_MGMT_SYNC_TIMEOUT 3000 -#define FPGA_MGMT_SYNC_DELAY_MSEC 20 +#define FPGA_MGMT_SYNC_TIMEOUT 30000 +#define FPGA_MGMT_SYNC_DELAY_MSEC 2 struct fgpa_mgmt_state_s fpga_mgmt_state = { .timeout = FPGA_MGMT_TIMEOUT_DFLT, @@ -414,7 +414,7 @@ int fpga_mgmt_load_local_image_with_options(union fpga_mgmt_load_local_image_opt memset(&rsp, 0, sizeof(union afi_cmd)); /* mask off any unsupported flags */ - opt->flags &= FPGA_CMD_DRAM_DATA_RETENTION | FPGA_CMD_FORCE_SHELL_RELOAD; + opt->flags &= FPGA_CMD_ALL_FLAGS; /* initialize the command structure */ fpga_mgmt_cmd_init_load(&cmd, &len, opt); diff --git a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c index 54e9b175..acdc5155 100644 --- a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c +++ b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c @@ -177,7 +177,7 @@ fpga_mgmt_cmd_init_metrics(union afi_cmd *cmd, uint32_t *len, uint32_t flags) afi_cmd_hdr_set_flags(cmd, 0); /** Fill in cmd body; only allow specific flags to be set */ - req->fpga_cmd_flags = flags & + req->fpga_cmd_flags = FPGA_CMD_EXTENDED_METRICS_SIZE | flags & (FPGA_CMD_GET_HW_METRICS | FPGA_CMD_CLEAR_HW_METRICS); *len = sizeof(struct afi_cmd_hdr) + payload_len; diff --git a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_internal.h b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_internal.h index a0713966..bf5aaa13 100644 --- a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_internal.h +++ b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_internal.h @@ -17,8 +17,8 @@ * Default timeout: * CLI_TIMEOUT_DFLT * CLI_DELAY_MSEC_DFLT */ -#define FPGA_MGMT_TIMEOUT_DFLT 250 -#define FPGA_MGMT_DELAY_MSEC_DFLT 20 +#define FPGA_MGMT_TIMEOUT_DFLT 2500 +#define FPGA_MGMT_DELAY_MSEC_DFLT 2 /** First flag bit, @see afi_cmd_hdr#len_flags */ #define AFI_CMD_HDR_FLAGS_SHIFT 24 diff --git a/sdk/userspace/fpga_libs/fpga_pci/fpga_pci_sysfs.c b/sdk/userspace/fpga_libs/fpga_pci/fpga_pci_sysfs.c index 95808c3a..ef3829e2 100644 --- a/sdk/userspace/fpga_libs/fpga_pci/fpga_pci_sysfs.c +++ b/sdk/userspace/fpga_libs/fpga_pci/fpga_pci_sysfs.c @@ -30,10 +30,16 @@ #include static int fpga_pci_rescan(void); -static int fpga_pci_check_app_pf(struct fpga_pci_resource_map *app_map, +static int fpga_pci_check_app_pf(struct fpga_pci_resource_map *app_map, bool exists); static int fpga_pci_check_app_pf_sysfs(char *dir_name, bool exists); +#if !defined(_BSD_SOURCE) && !defined(_SVID_SOURCE) +pthread_mutex_t fpga_pci_readdir_mutex = PTHREAD_MUTEX_INITIALIZER; +#else +#define FPGA_PCI_USE_READDIR_R +#endif + /** * Return the ID from the given sysfs file (e.g. Vendor ID, Device ID). * @@ -143,7 +149,7 @@ fpga_pci_get_dbdf(char *dir_name, struct fpga_pci_resource_map *map) * @param[in] dir_name the PCI device directory name * @param[in] resource_num the resource number * @param[in,out] resource_size the returned resource size - * @param[in,out] burstable the returned resource burstable flag + * @param[in,out] burstable the returned resource burstable flag * * @returns * 0 on success @@ -206,7 +212,7 @@ fpga_pci_get_pci_resource_info(char *dir_name, * Return the PCI resources for the given sysfs directory name. * * @param[in] dir_name the PCI device directory name - * @param[in,out] map the PCI resource map + * @param[in,out] map the PCI resource map * * @returns * 0 on success @@ -247,7 +253,7 @@ fpga_pci_get_resources(char *dir_name, struct fpga_pci_resource_map *map) * Return the PCI resource map identifiers for the given sysfs directory name. * * @param[in] dir_name the PCI device directory name - * @param[in,out] map the PCI resource map + * @param[in,out] map the PCI resource map * * @returns * 0 on success @@ -345,7 +351,7 @@ fpga_pci_get_resource_map_ids(char *dir_name, struct fpga_pci_resource_map *map) * -1 on failure */ static int -fpga_pci_mbox2app(struct fpga_pci_resource_map *mbox_map, +fpga_pci_mbox2app(struct fpga_pci_resource_map *mbox_map, struct fpga_pci_resource_map *app_map, char *app_dir_name, size_t app_dir_name_size) { @@ -356,7 +362,7 @@ fpga_pci_mbox2app(struct fpga_pci_resource_map *mbox_map, /** Construct the app dir name based on the mbox_map */ ret = snprintf(app_dir_name, app_dir_name_size, PCI_DEV_FMT, - mbox_map->domain, mbox_map->bus, + mbox_map->domain, mbox_map->bus, F1_MBOX_DEV2APP_DEV(mbox_map->dev), mbox_map->func); fail_on_with_code(ret < 0, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, @@ -364,28 +370,28 @@ fpga_pci_mbox2app(struct fpga_pci_resource_map *mbox_map, fail_on_with_code((size_t) ret >= app_dir_name_size, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "app_dir_name too long"); - /** - * Check that the app_pf exists. If not found, make a minimal attempt to + /** + * Check that the app_pf exists. If not found, make a minimal attempt to * recover it. */ ret = fpga_pci_check_app_pf_sysfs(app_dir_name, true); /** exists==true*/ fail_on(ret != 0, err, "fpga_pci_check_app_pf_sysfs failed"); /** - * Fill in the app_map for the given app_dir_name. If the app_dir_name is - * not yet ready (e.g. sysfs files are in the process of being recreated + * Fill in the app_map for the given app_dir_name. If the app_dir_name is + * not yet ready (e.g. sysfs files are in the process of being recreated * due to a remove/rescan) make a minimal retry attempt. */ bool done = false; uint32_t retries = 0; while (!done) { - ret = fpga_pci_get_resource_map_ids(app_dir_name, app_map); + ret = fpga_pci_get_resource_map_ids(app_dir_name, app_map); if (ret == 0) { done = true; - } else { + } else { fail_on_with_code(retries >= F1_CHECK_APP_PF_MAX_RETRIES, err, ret, FPGA_ERR_UNRESPONSIVE, - "fpga_pci_get_resource_map_ids failed for app_dir_name=%s", + "fpga_pci_get_resource_map_ids failed for app_dir_name=%s", app_dir_name); msleep(F1_CHECK_APP_PF_DELAY_MSEC); retries++; @@ -397,9 +403,21 @@ fpga_pci_mbox2app(struct fpga_pci_resource_map *mbox_map, return ret; } +int fpga_acquire_readdir_lock() { #if !defined(FPGA_PCI_USE_READDIR_R) -pthread_mutex_t fpga_pci_readdir_mutex = PTHREAD_MUTEX_INITIALIZER; + return pthread_mutex_lock(&fpga_pci_readdir_mutex); +#else + return 0; #endif +} + +int fpga_release_readdir_lock() { +#if !defined(FPGA_PCI_USE_READDIR_R) + return pthread_mutex_unlock(&fpga_pci_readdir_mutex); +#else + return 0; +#endif +} int fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) @@ -421,7 +439,7 @@ fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) * this function, which always reads from the same directory. The man page * for readdir says the POSIX spec does not require threadsafety. */ - pthread_mutex_lock(&fpga_pci_readdir_mutex); + fpga_acquire_readdir_lock(); #endif int slot_dev_index = 0; @@ -431,10 +449,10 @@ fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) memset(&search_spec, 0, sizeof(struct fpga_slot_spec)); - /** + /** * Loop through the sysfs device directories * -we first find the mbox dev then handle the app dev as a fixed - * mapping based off of the mbox dev's pci resource map + * mapping based off of the mbox dev's pci resource map * (see fpga_pci_mbox2app). * -this approach is simple and more efficient than the * alternative of requiring an additional sort of the dirent entries by @@ -464,7 +482,7 @@ fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) continue; } - if (search_map.vendor_id == F1_MBOX_VENDOR_ID && + if (search_map.vendor_id == F1_MBOX_VENDOR_ID && search_map.device_id == F1_MBOX_DEVICE_ID) { /* mbox resources */ ret = fpga_pci_get_resources(entry->d_name, &search_map); @@ -473,7 +491,7 @@ fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) /* app resources */ memset(&app_map, 0, sizeof(struct fpga_pci_resource_map)); app_dir_name[0] = 0; - ret = fpga_pci_mbox2app(&search_map, &app_map, + ret = fpga_pci_mbox2app(&search_map, &app_map, app_dir_name, sizeof(app_dir_name)); fail_on(ret != 0, err_unlock, "Error retrieving app pf information"); @@ -492,7 +510,7 @@ fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) } } #if !defined(FPGA_PCI_USE_READDIR_R) - pthread_mutex_unlock(&fpga_pci_readdir_mutex); + fpga_release_readdir_lock(); #endif fail_on_with_code(!found_afi_slot, err, ret, FPGA_ERR_PCI_MISSING, "No fpga-image-slots found"); @@ -504,7 +522,7 @@ fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) err_unlock: #if !defined(FPGA_PCI_USE_READDIR_R) - pthread_mutex_unlock(&fpga_pci_readdir_mutex); + fpga_release_readdir_lock(); #endif err: @@ -623,16 +641,16 @@ fpga_pci_check_app_pf_driver(struct fpga_pci_resource_map *app_map, } /** - * Check that the application PF exists or not based on the dir_name and + * Check that the application PF exists or not based on the dir_name and * exists flag. If the application PF is supposed to exist but was not * found, perform a minimal attempt at recovery be performing a PCI rescan. - * - * @param[in] dir_name the application PF device directory name - * @param[in] exists flag to check existence or non-existence - * + * + * @param[in] dir_name the application PF device directory name + * @param[in] exists flag to check existence or non-existence + * * @returns * 0 on success, non-zero on error - */ + */ static int fpga_pci_check_app_pf_sysfs(char *dir_name, bool exists) { @@ -658,7 +676,7 @@ fpga_pci_check_app_pf_sysfs(char *dir_name, bool exists) ret = stat(sysfs_name, &file_stat); if (!!ret == !exists) { done = true; - } else { + } else { fail_on_with_code(retries >= F1_CHECK_APP_PF_MAX_RETRIES, err, ret, FPGA_ERR_UNRESPONSIVE, "exists=%u, failed for path=%s", exists, sysfs_name); @@ -678,16 +696,16 @@ fpga_pci_check_app_pf_sysfs(char *dir_name, bool exists) } /** - * Check that the application PF exists or not based on the app_map and + * Check that the application PF exists or not based on the app_map and * exists flag. If the application PF is supposed to exist but was not * found, perform a minimal attempt at recovery be performing a PCI rescan. - * + * * @param[in] app_map the application device resource map - * @param[in] exists flag to check existence or non-existence - * + * @param[in] exists flag to check existence or non-existence + * * @returns * 0 on success, non-zero on error - */ + */ static int fpga_pci_check_app_pf(struct fpga_pci_resource_map *app_map, bool exists) { @@ -695,12 +713,12 @@ fpga_pci_check_app_pf(struct fpga_pci_resource_map *app_map, bool exists) fail_on_with_code(!app_map, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "app_map is NULL"); - + /** Construct the PCI device directory name using the PCI_DEV_FMT */ char dir_name[NAME_MAX + 1]; ret = snprintf(dir_name, sizeof(dir_name), PCI_DEV_FMT, app_map->domain, app_map->bus, app_map->dev, app_map->func); - + fail_on(ret < 0, err, "Error building the dir_name"); fail_on((size_t) ret >= sizeof(dir_name), err, "dir_name too long"); @@ -714,24 +732,24 @@ fpga_pci_check_app_pf(struct fpga_pci_resource_map *app_map, bool exists) /** * Remove the application PF for the given app map. - * - * @param[out] app_map the application device resource map to remove - * + * + * @param[out] app_map the application device resource map to remove + * * @returns * 0 on success, non-zero on error - */ + */ static int fpga_pci_remove_app_pf(struct fpga_pci_resource_map *app_map) -{ +{ int ret = 0; fail_on_with_code(!app_map, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "app_map is NULL"); - + /** Construct the PCI device directory name using the PCI_DEV_FMT */ char dir_name[NAME_MAX + 1]; ret = snprintf(dir_name, sizeof(dir_name), PCI_DEV_FMT, app_map->domain, app_map->bus, app_map->dev, app_map->func); - + fail_on_with_code(ret < 0, err, ret, FPGA_ERR_SOFTWARE_PROBLEM, "Error building the dir_name"); fail_on_with_code((size_t) ret >= sizeof(dir_name), err, ret, @@ -752,13 +770,13 @@ fpga_pci_remove_app_pf(struct fpga_pci_resource_map *app_map) fail_on_with_code(ret != 0, err, ret, FPGA_ERR_UNRESPONSIVE, "cli_write_one2file failed"); -#if 0 +#if 0 /** Check that the app_pf does not exist */ - /** + /** * NOTE: - * A concurrent (remove)+rescan action on another FPGA slot will make this + * A concurrent (remove)+rescan action on another FPGA slot will make this * FPGA's app_pf visible again, so we should not error out here if we see - * that the app_pf is still present. + * that the app_pf is still present. */ ret = fpga_pci_check_app_pf_sysfs(dir_name, false); /** exists==false */ fail_on(ret != 0, err, "fpga_pci_check_app_pf_sysfs failed"); @@ -770,9 +788,9 @@ fpga_pci_remove_app_pf(struct fpga_pci_resource_map *app_map) return ret; } -/** +/** * PCI rescan. - * + * * @returns * 0 on success, non-zero on error */ @@ -802,8 +820,8 @@ int fpga_pci_rescan_slot_app_pfs(int slot_id) { /** Get the slot spec */ - struct fpga_slot_spec spec; - int ret = fpga_pci_get_slot_spec(slot_id, &spec); + struct fpga_slot_spec spec; + int ret = fpga_pci_get_slot_spec(slot_id, &spec); fail_on(ret != 0, err, "fpga_pci_get_slot_spec failed"); /** Check if there is a driver attached to the given app_map */ @@ -812,21 +830,21 @@ fpga_pci_rescan_slot_app_pfs(int slot_id) ret = fpga_pci_check_app_pf_driver(app_map, &attached); fail_on(ret != 0, err, "fpga_pci_check_app_pf_driver failed"); - /** Remove the app_pf */ - ret = fpga_pci_remove_app_pf(app_map); + /** Remove the app_pf */ + ret = fpga_pci_remove_app_pf(app_map); fail_on(ret != 0, err, "fpga_pci_remove_app_pf failed"); - /** + /** * If we found a driver attached to the given app_map, increase * the wait time between remove and rescan. * Note that if the driver takes a long time to complete the - * PCI remove fuction (e.g. longer than the below wait time), + * PCI remove fuction (e.g. longer than the below wait time), * we may still fail to expose the changed PCI IDs in the rescan step. */ - uint32_t delay_msec = (attached) ? + uint32_t delay_msec = (attached) ? F1_REMOVE_APP_PF_LONG_DELAY_MSEC : F1_REMOVE_APP_PF_SHORT_DELAY_MSEC; - log_info("Driver for " PCI_DEV_FMT " %s attached, waiting %u msec before rescan", + log_info("Driver for " PCI_DEV_FMT " %s attached, waiting %u msec before rescan", app_map->domain, app_map->bus, app_map->dev, app_map->func, (attached) ? "is" : "is not", delay_msec); diff --git a/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.c b/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.c index c0b37b8c..1b51a6d5 100644 --- a/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.c +++ b/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.c @@ -36,11 +36,11 @@ #define TYPE_FMT "%-10s" /** - * Globals + * Globals */ struct ec2_fpga_cmd f1; -/** +/** * Use dmesg as the default logger, stdout is available for debug. */ #if defined(FPGA_ALLOW_NON_ROOT) @@ -58,14 +58,14 @@ const struct logger *logger = &logger_kmsg; * @returns * 0 on success, non-zero on failure */ -static int +static int cli_show_slot_app_pfs(int slot_id, struct fpga_slot_spec *spec) { - fail_on(slot_id >= FPGA_SLOT_MAX, err, "slot_id(%d) >= %d", + fail_on(slot_id >= FPGA_SLOT_MAX, err, "slot_id(%d) >= %d", slot_id, FPGA_SLOT_MAX); if (f1.show_headers) { - printf("Type FpgaImageSlot VendorId DeviceId DBDF\n"); + printf("Type FpgaImageSlot VendorId DeviceId DBDF\n"); } /** Retrieve and display associated application PFs (if any) */ @@ -80,12 +80,12 @@ cli_show_slot_app_pfs(int slot_id, struct fpga_slot_spec *spec) } printf(TYPE_FMT " %2u 0x%04x 0x%04x " PCI_DEV_FMT "\n", - "AFIDEVICE", slot_id, app_map->vendor_id, app_map->device_id, + "AFIDEVICE", slot_id, app_map->vendor_id, app_map->device_id, app_map->domain, app_map->bus, app_map->dev, app_map->func); found_app_pf = true; } if (!found_app_pf) { - printf(TYPE_FMT " unknown unknown unknown\n", "AFIDEVICE"); + printf(TYPE_FMT " unknown unknown unknown\n", "AFIDEVICE"); } return 0; @@ -96,12 +96,12 @@ cli_show_slot_app_pfs(int slot_id, struct fpga_slot_spec *spec) /** * Display the FPGA image information. * - * @param[in] info the fpga info + * @param[in] info the fpga info * * @returns * 0 on success, non-zero on failure */ -static int +static int cli_show_image_info(struct fpga_mgmt_image_info *info) { assert(info); @@ -118,9 +118,9 @@ cli_show_image_info(struct fpga_mgmt_image_info *info) char *afi_id = (!info->ids.afi_id[0]) ? "none" : info->ids.afi_id; printf(TYPE_FMT " %2u %-22s", "AFI", f1.afi_slot, afi_id); - printf(" %-8s %2d %-8s %2d 0x%08x\n", - FPGA_STATUS2STR(info->status), info->status, - FPGA_ERR2STR(info->status_q), info->status_q, + printf(" %-8s %2d %-8s %2d 0x%08x\n", + FPGA_STATUS2STR(info->status), info->status, + FPGA_ERR2STR(info->status_q), info->status_q, info->sh_version); if (f1.rescan) { @@ -141,114 +141,114 @@ cli_show_image_info(struct fpga_mgmt_image_info *info) } struct fpga_metrics_common *fmc = &info->metrics; - printf("sdacl-slave-timeout=%u\n", + printf("sdacl-slave-timeout=%u\n", (fmc->int_status & FPGA_INT_STATUS_SDACL_SLAVE_TIMEOUT) ? 1 : 0); - printf("virtual-jtag-slave-timeout=%u\n", + printf("virtual-jtag-slave-timeout=%u\n", (fmc->int_status & FPGA_INT_STATUS_VIRTUAL_JTAG_SLAVE_TIMEOUT) ? 1 : 0); - printf("ocl-slave-timeout=%u\n", + printf("ocl-slave-timeout=%u\n", (fmc->int_status & FPGA_INT_STATUS_OCL_SLAVE_TIMEOUT) ? - 1 : 0); + 1 : 0); - printf("bar1-slave-timeout=%u\n", + printf("bar1-slave-timeout=%u\n", (fmc->int_status & FPGA_INT_STATUS_BAR1_SLAVE_TIMEOUT) ? - 1 : 0); + 1 : 0); - printf("dma-pcis-timeout=%u\n", + printf("dma-pcis-timeout=%u\n", (fmc->int_status & FPGA_INT_STATUS_DMA_PCI_SLAVE_TIMEOUT) ? - 1 : 0); + 1 : 0); - printf("pcim-range-error=%u\n", - (fmc->int_status & FPGA_INT_STATUS_PCI_MASTER_RANGE_ERROR) ? - 1 : 0); + printf("pcim-range-error=%u\n", + (fmc->int_status & FPGA_INT_STATUS_PCI_MASTER_RANGE_ERROR) ? + 1 : 0); - printf("pcim-axi-protocol-error=%u\n", + printf("pcim-axi-protocol-error=%u\n", (fmc->int_status & FPGA_INT_STATUS_PCI_MASTER_AXI_PROTOCOL_ERROR) ? - 1 : 0); + 1 : 0); - printf("pcim-axi-protocol-4K-cross-error=%u\n", + printf("pcim-axi-protocol-4K-cross-error=%u\n", (fmc->pcim_axi_protocol_error_status & FPGA_PAP_4K_CROSS_ERROR) ? - 1 : 0); + 1 : 0); - printf("pcim-axi-protocol-bus-master-enable-error=%u\n", + printf("pcim-axi-protocol-bus-master-enable-error=%u\n", (fmc->pcim_axi_protocol_error_status & FPGA_PAP_BM_EN_ERROR) ? - 1 : 0); + 1 : 0); - printf("pcim-axi-protocol-request-size-error=%u\n", + printf("pcim-axi-protocol-request-size-error=%u\n", (fmc->pcim_axi_protocol_error_status & FPGA_PAP_REQ_SIZE_ERROR) ? - 1 : 0); + 1 : 0); - printf("pcim-axi-protocol-write-incomplete-error=%u\n", + printf("pcim-axi-protocol-write-incomplete-error=%u\n", (fmc->pcim_axi_protocol_error_status & FPGA_PAP_WR_INCOMPLETE_ERROR) ? - 1 : 0); + 1 : 0); - printf("pcim-axi-protocol-first-byte-enable-error=%u\n", + printf("pcim-axi-protocol-first-byte-enable-error=%u\n", (fmc->pcim_axi_protocol_error_status & FPGA_PAP_FIRST_BYTE_EN_ERROR) ? - 1 : 0); + 1 : 0); - printf("pcim-axi-protocol-last-byte-enable-error=%u\n", + printf("pcim-axi-protocol-last-byte-enable-error=%u\n", (fmc->pcim_axi_protocol_error_status & FPGA_PAP_LAST_BYTE_EN_ERROR) ? - 1 : 0); + 1 : 0); - printf("pcim-axi-protocol-bready-error=%u\n", + printf("pcim-axi-protocol-bready-error=%u\n", (fmc->pcim_axi_protocol_error_status & FPGA_PAP_BREADY_TIMEOUT_ERROR) ? - 1 : 0); + 1 : 0); - printf("pcim-axi-protocol-rready-error=%u\n", + printf("pcim-axi-protocol-rready-error=%u\n", (fmc->pcim_axi_protocol_error_status & FPGA_PAP_RREADY_TIMEOUT_ERROR) ? - 1 : 0); + 1 : 0); - printf("pcim-axi-protocol-wchannel-error=%u\n", + printf("pcim-axi-protocol-wchannel-error=%u\n", (fmc->pcim_axi_protocol_error_status & FPGA_PAP_WCHANNEL_TIMEOUT_ERROR) ? - 1 : 0); + 1 : 0); - printf("sdacl-slave-timeout-addr=0x%" PRIx32 "\n", fmc->sdacl_slave_timeout_addr); - printf("sdacl-slave-timeout-count=%u\n", fmc->sdacl_slave_timeout_count); + printf("sdacl-slave-timeout-addr=0x%" PRIx32 "\n", fmc->sdacl_slave_timeout_addr); + printf("sdacl-slave-timeout-count=%u\n", fmc->sdacl_slave_timeout_count); - printf("virtual-jtag-slave-timeout-addr=0x%" PRIx32 "\n", fmc->virtual_jtag_slave_timeout_addr); - printf("virtual-jtag-slave-timeout-count=%u\n", fmc->virtual_jtag_slave_timeout_count); + printf("virtual-jtag-slave-timeout-addr=0x%" PRIx32 "\n", fmc->virtual_jtag_slave_timeout_addr); + printf("virtual-jtag-slave-timeout-count=%u\n", fmc->virtual_jtag_slave_timeout_count); - printf("ocl-slave-timeout-addr=0x%" PRIx64 "\n", fmc->ocl_slave_timeout_addr); - printf("ocl-slave-timeout-count=%u\n", fmc->ocl_slave_timeout_count); + printf("ocl-slave-timeout-addr=0x%" PRIx64 "\n", fmc->ocl_slave_timeout_addr); + printf("ocl-slave-timeout-count=%u\n", fmc->ocl_slave_timeout_count); - printf("bar1-slave-timeout-addr=0x%" PRIx64 "\n", fmc->bar1_slave_timeout_addr); - printf("bar1-slave-timeout-count=%u\n", fmc->bar1_slave_timeout_count); + printf("bar1-slave-timeout-addr=0x%" PRIx64 "\n", fmc->bar1_slave_timeout_addr); + printf("bar1-slave-timeout-count=%u\n", fmc->bar1_slave_timeout_count); - printf("dma-pcis-timeout-addr=0x%" PRIx64 "\n", fmc->dma_pcis_timeout_addr); - printf("dma-pcis-timeout-count=%u\n", fmc->dma_pcis_timeout_count); + printf("dma-pcis-timeout-addr=0x%" PRIx64 "\n", fmc->dma_pcis_timeout_addr); + printf("dma-pcis-timeout-count=%u\n", fmc->dma_pcis_timeout_count); - printf("pcim-range-error-addr=0x%" PRIx64 "\n", fmc->pcim_range_error_addr); - printf("pcim-range-error-count=%u\n", fmc->pcim_range_error_count); + printf("pcim-range-error-addr=0x%" PRIx64 "\n", fmc->pcim_range_error_addr); + printf("pcim-range-error-count=%u\n", fmc->pcim_range_error_count); - printf("pcim-axi-protocol-error-addr=0x%" PRIx64 "\n", fmc->pcim_axi_protocol_error_addr); - printf("pcim-axi-protocol-error-count=%u\n", fmc->pcim_axi_protocol_error_count); + printf("pcim-axi-protocol-error-addr=0x%" PRIx64 "\n", fmc->pcim_axi_protocol_error_addr); + printf("pcim-axi-protocol-error-count=%u\n", fmc->pcim_axi_protocol_error_count); - printf("pcim-write-count=%" PRIu64 "\n", fmc->pcim_write_count); - printf("pcim-read-count=%" PRIu64 "\n", fmc->pcim_read_count); + printf("pcim-write-count=%" PRIu64 "\n", fmc->pcim_write_count); + printf("pcim-read-count=%" PRIu64 "\n", fmc->pcim_read_count); for (i = 0; i < sizeof_array(fmc->ddr_ifs); i++) { struct fpga_ddr_if_metrics_common *ddr_if = &fmc->ddr_ifs[i]; printf("DDR%u\n", i); - printf(" write-count=%" PRIu64 "\n", ddr_if->write_count); - printf(" read-count=%" PRIu64 "\n", ddr_if->read_count); + printf(" write-count=%" PRIu64 "\n", ddr_if->write_count); + printf(" read-count=%" PRIu64 "\n", ddr_if->read_count); } printf("Clock Group A Frequency (Mhz)\n"); for (i = 0; i < CLOCK_COUNT_A; i++) { frequency = fmc->clocks[0].frequency[i] / 1000000; - printf("%" PRIu64 " ", frequency); + printf("%" PRIu64 " ", frequency); } printf("\nClock Group B Frequency (Mhz)\n"); for (i = 0; i < CLOCK_COUNT_B; i++) { frequency = fmc->clocks[1].frequency[i] / 1000000; - printf("%" PRIu64 " ", frequency); + printf("%" PRIu64 " ", frequency); } printf("\nClock Group C Frequency (Mhz)\n"); for (i = 0; i < CLOCK_COUNT_C; i++) { frequency = fmc->clocks[2].frequency[i] / 1000000; - printf("%" PRIu64 " ", frequency); + printf("%" PRIu64 " ", frequency); } printf("\n"); @@ -256,6 +256,13 @@ cli_show_image_info(struct fpga_mgmt_image_info *info) printf(" Last measured: %" PRIu64 " watts\n",fmc->power); printf(" Average: %" PRIu64 " watts\n",fmc->power_mean); printf(" Max measured: %" PRIu64 " watts\n",fmc->power_max); + printf("Cached agfis:\n"); + for (i = 0; i < sizeof_array(fmc->cached_agfis); i++) { + if (fmc->cached_agfis[i] == 0) { + break; + } + printf(" agfi-0%016" PRIx64 "\n", fmc->cached_agfis[i]); + } } return 0; @@ -275,9 +282,9 @@ cli_attach(void) int ret = FPGA_ERR_FAIL; if (f1.opcode == CLI_CMD_DESCRIBE_SLOTS) { - /** + /** * ec2-afi-describe-slots does not use the Mbox logic, local - * information only + * information only */ goto out; } @@ -321,6 +328,7 @@ static int command_load(void) uint32_t flags = 0; flags |= (f1.force_shell_reload ) ? FPGA_CMD_FORCE_SHELL_RELOAD : 0; flags |= (f1.dram_data_retention) ? FPGA_CMD_DRAM_DATA_RETENTION : 0; + flags |= (f1.prefetch) ? FPGA_CMD_PREFETCH : 0; fpga_mgmt_init_load_local_image_options(&opt); opt.slot_id = f1.afi_slot; @@ -354,7 +362,7 @@ static int command_load(void) * @returns * 0 on success, non-zero on failure */ -static int +static int command_clear(void) { int ret; @@ -366,7 +374,7 @@ command_clear(void) struct fpga_mgmt_image_info info; memset(&info, 0, sizeof(struct fpga_mgmt_image_info)); - ret = fpga_mgmt_clear_local_image_sync(f1.afi_slot, + ret = fpga_mgmt_clear_local_image_sync(f1.afi_slot, f1.sync_timeout, f1.sync_delay_msec, &info); fail_on(ret != 0, err, "fpga_mgmt_clear_local_image_sync failed"); @@ -444,7 +452,7 @@ command_describe_slots(void) * @returns * 0 on success, non-zero on failure */ -static int +static int command_start_virtual_jtag(void) { printf("Starting Virtual JTAG XVC Server for FPGA slot id %u, listening to TCP port %s.\n", @@ -457,7 +465,7 @@ command_start_virtual_jtag(void) /** * Display the virtual status from the get virtual led or dip command. * - * @param[in] status the virtual led or dip status to display. + * @param[in] status the virtual led or dip status to display. * * @returns * 0 on success, non-zero on failure @@ -487,7 +495,7 @@ cli_show_virtual_led_dip_status(uint16_t status) * @returns * 0 on success, non-zero on failure */ -static int +static int command_get_virtual_led(void) { uint16_t status; @@ -508,7 +516,7 @@ command_get_virtual_led(void) * @returns * 0 on success, non-zero on failure */ -static int +static int command_get_virtual_dip(void) { uint16_t status; @@ -529,7 +537,7 @@ command_get_virtual_dip(void) * @returns * 0 on success, non-zero on failure */ -static int +static int command_set_virtual_dip(void) { int ret; @@ -553,7 +561,7 @@ static const command_func_t command_table[CLI_CMD_END] = { }; /** - * Main CLI cmd/rsp processing engine. + * Main CLI cmd/rsp processing engine. * * @returns * 0 on success, non-zero on failure @@ -576,7 +584,7 @@ cli_main(void) * @returns * 0 on success, non-zero on failure */ -static int +static int cli_init_f1(void) { memset(&f1, 0, sizeof(f1)); @@ -599,7 +607,7 @@ cli_init_f1(void) * @returns * 0 on success, non-zero on failure */ -static int +static int cli_create(void) { return cli_init_f1(); @@ -611,7 +619,7 @@ cli_create(void) * @returns * 0 on success, non-zero on failure */ -static int +static int cli_destroy(void) { return cli_init_f1(); @@ -620,13 +628,13 @@ cli_destroy(void) /** * CLI main * - * @param[in] argc argument count + * @param[in] argc argument count * @param[in] argv argument vector * * @returns * 0 on success, non-zero on failure */ -int +int main(int argc, char *argv[]) { int ret = cli_create(); @@ -637,7 +645,7 @@ main(int argc, char *argv[]) ret = log_attach(logger, NULL, 0); fail_on_user(ret != 0, err, "%s", CLI_ROOT_ACCESS_ERR_STR); - + ret = parse_args(argc, argv); fail_on(ret != 0, err, "parse_args failed"); @@ -647,8 +655,8 @@ main(int argc, char *argv[]) ret = cli_main(); fail_on(ret != 0, err, "cli_main failed"); err: - /** - * f1.parser_completed may be set by parse_args when it internally + /** + * f1.parser_completed may be set by parse_args when it internally * completes the command without error due to help or version output. * In this case a non-zero error is returned by parse_args and we do not * want to print the "Error" below. diff --git a/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.h b/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.h index 52887fb5..06f5235f 100644 --- a/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.h +++ b/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.h @@ -60,8 +60,8 @@ enum { * e.g. load + describe multi-AFI command sequences. * timeout * delay_msec */ -#define CLI_SYNC_TIMEOUT_DFLT 3000 -#define CLI_SYNC_DELAY_MSEC_DFLT 20 +#define CLI_SYNC_TIMEOUT_DFLT 30000 +#define CLI_SYNC_DELAY_MSEC_DFLT 2 /** * Request timeout: timeout * delay_msec @@ -109,6 +109,8 @@ struct ec2_fpga_cmd { bool force_shell_reload; /** Attempt dram data retention on load */ bool dram_data_retention; + /** Don't actually load the FPGA, just cache the files for a later load */ + bool prefetch; /** Virtual DIP switch */ uint16_t v_dip_switch; /** Virtual JTAG TCP port */ diff --git a/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd_parse.c b/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd_parse.c index 446086db..aaebceb5 100644 --- a/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd_parse.c +++ b/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd_parse.c @@ -99,10 +99,10 @@ static const char *describe_afi_usage[] = { " Rescan the AFIDEVICE to update the per-AFI PCI VendorId and", " DeviceId that may be dynamically modified due to a", " fpga-load-local-image or fpga-clear-local-image command.", - " NOTE1: this option removes the AFIDEVICE from the sysfs PCI", + " NOTE1: this option removes the AFIDEVICE from the sysfs PCI", " subsystem and then rescans the PCI subsystem in order for", " the modified AFI PCI IDs to be refreshed.", - " NOTE2: it is the developer's responsibility to remove any", + " NOTE2: it is the developer's responsibility to remove any", " driver previously installed on the older PCIe VendorId", " and DeviceId before fpga-clear-local-image,", " fpga-load-local-image, or re-scan.", @@ -130,10 +130,10 @@ static const char *load_afi_usage[] = { " NOTE: By default, this command automatically rescans the AFIDEVICE", " to update the per-AFI PCI VendorId and DeviceId that may be", " dynamically modified during each FPGA image load.", - " The rescan operation removes the AFIDEVICE from the sysfs PCI", + " The rescan operation removes the AFIDEVICE from the sysfs PCI", " subsystem and then rescans the PCI subsystem in order for", " the modified AFI PCI IDs to be refreshed.", - " It is the developer's responsibility to remove any", + " It is the developer's responsibility to remove any", " driver previously installed on the older PCIe VendorId", " and DeviceId before the FPGA image is loaded.", " GENERAL OPTIONS", @@ -176,6 +176,10 @@ static const char *load_afi_usage[] = { " This will try to detect if retention is possible and reject the", " load if it is not. To use, call load with another afi already", " loaded.", + " -P, --prefetch-image", + " Prefetch the indicated AFI and store it in the cache for faster loading.", + " Fastest load times can be achieved by using cached AFIs and enabling data retention (-D).", + " See Reducing AFI load times documentation.", }; static const char *clear_afi_usage[] = { @@ -193,10 +197,10 @@ static const char *clear_afi_usage[] = { " NOTE: By default, this command automatically rescans the AFIDEVICE", " to update the default AFI PCI VendorId and DeviceId that are", " dynamically modified during each FPGA image clear.", - " The rescan operation removes the AFIDEVICE from the sysfs PCI", + " The rescan operation removes the AFIDEVICE from the sysfs PCI", " subsystem and then rescans the PCI subsystem in order for", " the modified AFI PCI IDs to be refreshed.", - " It is the developer's responsibility to remove any", + " It is the developer's responsibility to remove any", " driver previously installed on the older PCIe VendorId", " and DeviceId before the FPGA image is cleared.", " GENERAL OPTIONS", @@ -263,7 +267,7 @@ static const char *get_virtual_led_usage[] = { " Example: fpga-get-virtual-led -S 0", " DESCRIPTION", " Returns the current status of the virtual LED exposed by the AFI, a", - " series of 0 (zeros) and 1 (ones), first digit from the righti maps", + " series of 0 (zeros) and 1 (ones), first digit from the righti maps", " to cl_sh_vled[0]. For example, a return value 0000000001000000", " indicates that cl_sh_vled[6] is set(on)", " GENERAL OPTIONS", @@ -327,15 +331,15 @@ static const char *set_virtual_dip_usage[] = { }; /** - * Generic usage printing engine. + * Generic usage printing engine. * * @param[in] prog_name program name * @param[in] usage usage array of strings * @param[in] num_entries number of entries in the usage array of strings */ -static void +static void print_usage(const char *prog_name, const char *usage[], size_t num_entries) -{ +{ (void)prog_name; size_t i; @@ -345,27 +349,27 @@ print_usage(const char *prog_name, const char *usage[], size_t num_entries) } /** - * Print the version number of this program. + * Print the version number of this program. */ -static void +static void print_version(void) -{ +{ printf("AFI Management Tools Version: %s\n", CLI_VERSION); } /** * Check the given option and set the f1.parser_completed flag. * - * -parser_completed is set when the parser will complete the option - * (help or version output) and no further command processing is necessary, + * -parser_completed is set when the parser will complete the option + * (help or version output) and no further command processing is necessary, * though a non-zero return value is still returned from parse_args. * -the parser_completed flag may then be used to skip the "Error" output - * that is generically used for parsing or other errors beyond the parsing + * that is generically used for parsing or other errors beyond the parsing * stage. * * @param[in] opt the option to check */ -static void +static void get_parser_completed(char opt) { if ((opt == 'h') || (opt == 'V')) { @@ -379,19 +383,19 @@ get_parser_completed(char opt) * @param[in] timeout timeout in seconds * * @returns - * 0 on success + * 0 on success * -1 on failure */ static int config_request_timeout(uint32_t timeout) { - size_t timeout_tmp = + size_t timeout_tmp = CLI_REQUEST_TIMEOUT_DFLT * CLI_REQUEST_DELAY_MSEC_DFLT / MSEC_PER_SEC; - size_t timeout_max = + size_t timeout_max = ((size_t)(uint32_t)-1) * CLI_REQUEST_DELAY_MSEC_DFLT / MSEC_PER_SEC; /** Check min and max values */ - fail_on_user((timeout < timeout_tmp) || (timeout > timeout_max), err, + fail_on_user((timeout < timeout_tmp) || (timeout > timeout_max), err, "Error: The timeout must be between %zu and %zu seconds", timeout_tmp, timeout_max); @@ -404,7 +408,7 @@ config_request_timeout(uint32_t timeout) f1.request_timeout = timeout_tmp; f1.request_delay_msec = CLI_REQUEST_DELAY_MSEC_DFLT; - log_debug("Setting timeout to %u secs, request_timeout=%u, request_delay_msec=%u", + log_debug("Setting timeout to %u secs, request_timeout=%u, request_delay_msec=%u", timeout, f1.request_timeout, f1.request_delay_msec); return 0; err: @@ -417,19 +421,19 @@ config_request_timeout(uint32_t timeout) * @param[in] timeout timeout in seconds * * @returns - * 0 on success + * 0 on success * -1 on failure */ static int config_sync_timeout(uint32_t timeout) { - size_t timeout_tmp = + size_t timeout_tmp = CLI_SYNC_TIMEOUT_DFLT * CLI_SYNC_DELAY_MSEC_DFLT / MSEC_PER_SEC; - size_t timeout_max = + size_t timeout_max = ((size_t)(uint32_t)-1) * CLI_SYNC_DELAY_MSEC_DFLT / MSEC_PER_SEC; /** Check min and max values */ - fail_on_user((timeout < timeout_tmp) || (timeout > timeout_max), err, + fail_on_user((timeout < timeout_tmp) || (timeout > timeout_max), err, "Error: The timeout must be between %zu and %zu seconds", timeout_tmp, timeout_max); @@ -442,7 +446,7 @@ config_sync_timeout(uint32_t timeout) f1.sync_timeout = timeout_tmp; f1.sync_delay_msec = CLI_SYNC_DELAY_MSEC_DFLT; - log_debug("Setting timeout to %u secs, sync_timeout=%u, sync_delay_msec=%u", + log_debug("Setting timeout to %u secs, sync_timeout=%u, sync_delay_msec=%u", timeout, f1.sync_timeout, f1.sync_delay_msec); return 0; err: @@ -455,7 +459,7 @@ config_sync_timeout(uint32_t timeout) * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ -static int +static int parse_args_load_afi(int argc, char *argv[]) { int opt = 0; @@ -474,16 +478,17 @@ parse_args_load_afi(int argc, char *argv[]) {"version", no_argument, 0, 'V' }, {"force-shell-reload", no_argument, 0, 'F' }, {"dram-data-retention", no_argument, 0, 'D' }, + {"prefetch-image", no_argument, 0, 'P' }, {0, 0, 0, 0 }, }; int long_index = 0; - while ((opt = getopt_long(argc, argv, "S:I:r:s:a:b:c:AH?hVFD", + while ((opt = getopt_long(argc, argv, "S:I:r:s:a:b:c:AH?hVFDP", long_options, &long_index)) != -1) { switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); - fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", + fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } @@ -491,8 +496,8 @@ parse_args_load_afi(int argc, char *argv[]) fail_on_user(strnlen(optarg, AFI_ID_STR_MAX) == AFI_ID_STR_MAX, err, "fpga-image-id must be less than %u bytes", AFI_ID_STR_MAX); - strncpy(f1.afi_id, optarg, sizeof(f1.afi_id)); - f1.afi_id[sizeof(f1.afi_id) - 1] = 0; + strncpy(f1.afi_id, optarg, sizeof(f1.afi_id)); + f1.afi_id[sizeof(f1.afi_id) - 1] = 0; break; } case 'a': { @@ -545,13 +550,18 @@ parse_args_load_afi(int argc, char *argv[]) f1.dram_data_retention = true; break; } + case 'P': { + f1.prefetch = true; + f1.async = true; + break; + } default: { get_parser_completed(opt); - goto err; + goto err; } } } - + if ((f1.afi_slot == (uint32_t) -1) || (f1.afi_id[0] == 0)) { goto err; @@ -570,7 +580,7 @@ parse_args_load_afi(int argc, char *argv[]) * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ -static int +static int parse_args_clear_afi(int argc, char *argv[]) { int opt = 0; @@ -592,7 +602,7 @@ parse_args_clear_afi(int argc, char *argv[]) switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); - fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", + fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } @@ -625,12 +635,12 @@ parse_args_clear_afi(int argc, char *argv[]) } default: { get_parser_completed(opt); - goto err; + goto err; } } } - - if (f1.afi_slot == (uint32_t) -1) { + + if (f1.afi_slot == (uint32_t) -1) { goto err; } @@ -647,7 +657,7 @@ parse_args_clear_afi(int argc, char *argv[]) * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ -static int +static int parse_args_describe_afi(int argc, char *argv[]) { int opt = 0; @@ -670,7 +680,7 @@ parse_args_describe_afi(int argc, char *argv[]) switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); - fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, + fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } @@ -705,12 +715,12 @@ parse_args_describe_afi(int argc, char *argv[]) } default: { get_parser_completed(opt); - goto err; + goto err; } } } - - if (f1.afi_slot == (uint32_t) -1) { + + if (f1.afi_slot == (uint32_t) -1) { goto err; } @@ -728,7 +738,7 @@ parse_args_describe_afi(int argc, char *argv[]) * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ -static int +static int parse_args_describe_afi_slots(int argc, char *argv[]) { int opt = 0; @@ -768,14 +778,14 @@ parse_args_describe_afi_slots(int argc, char *argv[]) } default: { get_parser_completed(opt); - goto err; + goto err; } } } - + return 0; err: - print_usage(argv[0], describe_afi_slots_usage, + print_usage(argv[0], describe_afi_slots_usage, sizeof_array(describe_afi_slots_usage)); out_ver: return -EINVAL; @@ -789,7 +799,7 @@ static char default_tcp_port[5] = "10201"; * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ -static int +static int parse_args_start_virtual_jtag(int argc, char *argv[]) { int opt = 0; @@ -813,7 +823,7 @@ parse_args_start_virtual_jtag(int argc, char *argv[]) switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); - fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, + fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } @@ -838,16 +848,16 @@ parse_args_start_virtual_jtag(int argc, char *argv[]) } default: { get_parser_completed(opt); - goto err; + goto err; } } } - - if (f1.afi_slot == (uint32_t) -1) { + + if (f1.afi_slot == (uint32_t) -1) { printf("Error: Invalid Slot Id !"); goto err; } - + return 0; err: @@ -862,7 +872,7 @@ parse_args_start_virtual_jtag(int argc, char *argv[]) * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ -static int +static int parse_args_get_virtual_led(int argc, char *argv[]) { int opt; @@ -881,7 +891,7 @@ parse_args_get_virtual_led(int argc, char *argv[]) switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); - fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, + fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } @@ -897,12 +907,12 @@ parse_args_get_virtual_led(int argc, char *argv[]) } default: { get_parser_completed(opt); - goto err; + goto err; } } } - - if (f1.afi_slot == (uint32_t) -1) { + + if (f1.afi_slot == (uint32_t) -1) { printf("Error: Invalid Slot Id !"); goto err; } @@ -919,7 +929,7 @@ parse_args_get_virtual_led(int argc, char *argv[]) * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ -static int +static int parse_args_get_virtual_dip(int argc, char *argv[]) { int opt; @@ -938,7 +948,7 @@ parse_args_get_virtual_dip(int argc, char *argv[]) switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); - fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, + fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } @@ -954,16 +964,16 @@ parse_args_get_virtual_dip(int argc, char *argv[]) } default: { get_parser_completed(opt); - goto err; + goto err; } } } - - if (f1.afi_slot == (uint32_t) -1) { + + if (f1.afi_slot == (uint32_t) -1) { printf("Error: Invalid Slot Id !"); goto err; } - + return 0; err: print_usage(argv[0], get_virtual_dip_usage, sizeof_array(get_virtual_dip_usage)); @@ -977,7 +987,7 @@ parse_args_get_virtual_dip(int argc, char *argv[]) * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ -static int +static int parse_args_set_virtual_dip(int argc, char *argv[]) { int opt; @@ -1000,20 +1010,20 @@ parse_args_set_virtual_dip(int argc, char *argv[]) switch (opt) { case 'S': { string_to_uint(&f1.afi_slot, optarg); - fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, + fail_on_user(f1.afi_slot >= FPGA_SLOT_MAX, err, "fpga-image-slot must be less than %u", FPGA_SLOT_MAX); break; } case 'D': { - fail_on_user(strlen(optarg) != 16, err, + fail_on_user(strlen(optarg) != 16, err, "virtual-dip must be 16 digits of zero or one"); for (i=0;i<16;i++) { if (optarg[i] == '1') status = status | 0x1; else if (optarg[i] == '0') status = status; - else - fail_on_user(1, err, + else + fail_on_user(1, err, "illegal digit for virtual-dip %c", optarg[i]); if (i!=15) status = status << 1; @@ -1035,12 +1045,12 @@ parse_args_set_virtual_dip(int argc, char *argv[]) default: { get_parser_completed(opt); - goto err; + goto err; } } } - - if (f1.afi_slot == (uint32_t) -1) { + + if (f1.afi_slot == (uint32_t) -1) { printf("Error: Invalid Slot Id !"); goto err; } @@ -1048,14 +1058,14 @@ parse_args_set_virtual_dip(int argc, char *argv[]) printf("Error: Missing DIP Switch values !"); goto err; } - - return 0; + + return 0; err: print_usage(argv[0], set_virtual_dip_usage, sizeof_array(set_virtual_dip_usage)); out_ver: return -EINVAL; } - + typedef int (*parse_args_func_t)(int argc, char *argv[]); struct parse_args_str2func { @@ -1070,11 +1080,11 @@ struct parse_args_str2func { * @param[in] argc Argument count. * @param[in] argv Argument string vector. */ -int +int parse_args(int argc, char *argv[]) { fail_on(argc < 2, err, "Error: opcode string must be specified"); - fail_on_user(!argv[0] || !argv[1], err, + fail_on_user(!argv[0] || !argv[1], err, "Error: program name or opcode string is NULL"); static struct parse_args_str2func str2func[] = { diff --git a/sdk/userspace/include/fpga_pci.h b/sdk/userspace/include/fpga_pci.h index b60681fb..336b2aec 100644 --- a/sdk/userspace/include/fpga_pci.h +++ b/sdk/userspace/include/fpga_pci.h @@ -247,19 +247,17 @@ int fpga_pci_memset(pci_bar_handle_t handle, uint64_t offset, uint32_t value, * Glibc 2.19 and lower support readdir_r, a reentrant version of readdir. * Newer versions of glibc deprecate readdir_r and therefore require external * synchronization on readdir. - */ -#if !defined(_BSD_SOURCE) && !defined(_SVID_SOURCE) -/** - * This mutex is used internally in fpga_pci_get_all_slot_specs to provide - * synchronization for calls to readdir. The mutex is exported so that if - * software which links with this library also uses readdir in a threaded + * + * The mutex is used internally in fpga_pci_get_all_slot_specs to provide + * synchronization for calls to readdir. The calls to lock/unlock this mutex is exported + * so that if software which links with this library also uses readdir in a threaded * environment, it can use this lock to protect calls to readdir. */ -extern pthread_mutex_t fpga_pci_readdir_mutex; -#else -#define FPGA_PCI_USE_READDIR_R -#endif +__attribute__((visibility("hidden"))) extern pthread_mutex_t fpga_pci_readdir_mutex; + +int fpga_acquire_readdir_lock(void); +int fpga_release_readdir_lock(void); #ifdef __cplusplus } diff --git a/sdk/userspace/include/hal/fpga_common.h b/sdk/userspace/include/hal/fpga_common.h index 0bb1e321..7cd18971 100644 --- a/sdk/userspace/include/hal/fpga_common.h +++ b/sdk/userspace/include/hal/fpga_common.h @@ -14,7 +14,7 @@ */ /** @file - * FPGA common header + * FPGA common header */ #pragma once @@ -25,6 +25,7 @@ #define FPGA_SLOT_MAX 8 #define AFI_ID_STR_MAX 64 #define FPGA_DDR_IFS_MAX 4 +#define FPGA_CACHED_AGFIS_MAX 16 /** * FPGA Mixed Mode Clock Manager (MMCM) config. @@ -43,30 +44,34 @@ enum { /** reserved */ FPGA_CMD_RSVD = 1 << 0, - /** return FPGA image hardware metrics */ + /** return FPGA image hardware metrics */ FPGA_CMD_GET_HW_METRICS = 1 << 1, - /** return FPGA image hardware metrics (clear on read */ + /** return FPGA image hardware metrics (clear on read */ FPGA_CMD_CLEAR_HW_METRICS = 1 << 2, FPGA_CMD_FORCE_SHELL_RELOAD = 1 << 3, - - /** request that ddr data retention is used during load */ FPGA_CMD_DRAM_DATA_RETENTION = 1 << 4, + FPGA_CMD_EXTENDED_METRICS_SIZE = 1 << 6, + FPGA_CMD_PREFETCH = 1 << 7, + + - FPGA_CMD_ALL_FLAGS = FPGA_CMD_GET_HW_METRICS | + FPGA_CMD_ALL_FLAGS = FPGA_CMD_GET_HW_METRICS | FPGA_CMD_CLEAR_HW_METRICS | FPGA_CMD_FORCE_SHELL_RELOAD | - FPGA_CMD_DRAM_DATA_RETENTION , + FPGA_CMD_DRAM_DATA_RETENTION | + FPGA_CMD_EXTENDED_METRICS_SIZE | + FPGA_CMD_PREFETCH, }; -/** +/** * FPGA specific errors * e.g. as returned by fpga-load-local-image, fpga-clear-local-image, * and fpga-describe-local-image. * * -note that these must fit into an int32_t and must be positive integers. - * -this is compatible with the standard errno values such as -EINVAL, -EIO, + * -this is compatible with the standard errno values such as -EINVAL, -EIO, * -EPERM, -ENOENT that are also used. * * Any additions should also be added to FPGA_ERR2STR (see below). @@ -91,7 +96,7 @@ enum { /** Reserved: 6-10 */ /** Invalid AFI_CMD_API_VERSION, see afi_cmd_api.h */ - FPGA_ERR_AFI_CMD_API_VERSION_INVALID = 11, + FPGA_ERR_AFI_CMD_API_VERSION_INVALID = 11, /** CL PCI IDs did not match (e.g. between LF and CL reported values */ FPGA_ERR_CL_ID_MISMATCH = 12, /** CL DDR calibration failed */ @@ -107,6 +112,8 @@ enum { * possible. This prevents the loss of data when retention cannot work. */ FPGA_ERR_DRAM_DATA_RETENTION_NOT_POSSIBLE = 18, + FPGA_ERR_HARDWARE_BUSY = 19, + /** Reserved: 19 */ /** Unable to locate PCI devices/resources */ @@ -141,7 +148,7 @@ enum { ((error) == FPGA_ERR_CL_ID_MISMATCH) ? "cl-id-mismatch" : \ ((error) == FPGA_ERR_CL_DDR_CALIB_FAILED) ? "cl-ddr-calib-failed" : \ ((error) == FPGA_ERR_FAIL) ? "unspecified-error" : \ - ((error) == FPGA_ERR_SHELL_MISMATCH) ? "afi-shell-version-mismatch" : \ + ((error) == FPGA_ERR_SHELL_MISMATCH) ? "shell-version-not-supported" : \ ((error) == FPGA_ERR_POWER_VIOLATION) ? "afi-power-violation" : \ ((error) == FPGA_ERR_DRAM_DATA_RETENTION_NOT_POSSIBLE) ? "dram-data-retention-not-possible" : \ ((error) == FPGA_ERR_DRAM_DATA_RETENTION_FAILED) ? "dram-data-retention-failed" : \ @@ -150,6 +157,7 @@ enum { ((error) == FPGA_ERR_SOFTWARE_PROBLEM) ? "software-problem": \ ((error) == FPGA_ERR_UNRESPONSIVE) ? "unresponsive": \ ((error) == FPGA_ERR_AFI_CMD_MALFORMED) ? "afi-command-malformed" : \ + ((error) == FPGA_ERR_HARDWARE_BUSY) ? "hardware-busy" : \ "internal-error" @@ -160,7 +168,7 @@ enum { * Any additions should also be added to FPGA_STATUS2STR (see below). */ enum { - /**< FPGA slot has an AFI loaded */ + /**< FPGA slot has an AFI loaded */ FPGA_STATUS_LOADED = 0, /**< FPGA slot is cleared */ FPGA_STATUS_CLEARED = 1, @@ -223,7 +231,7 @@ struct fpga_pci_resource_map { uint16_t device_id; uint16_t subsystem_device_id; uint16_t subsystem_vendor_id; - + /** e.g. PCI Domain:Bus:Device.Function */ uint16_t domain; uint8_t bus; @@ -290,7 +298,7 @@ struct fpga_metrics_common { uint64_t pcim_axi_protocol_error_addr; uint32_t pcim_axi_protocol_error_count; /** reserved */ - uint8_t reserved2[12]; + uint8_t reserved2[12]; /** FPGA_INT_STATUS_OCL_SLAVE_TIMEOUT: address and count */ uint64_t ocl_slave_timeout_addr; uint32_t ocl_slave_timeout_count; @@ -317,6 +325,8 @@ struct fpga_metrics_common { uint64_t power_mean; uint64_t power_max; uint64_t power; + uint64_t cached_agfis[FPGA_CACHED_AGFIS_MAX]; + uint64_t flags; } __attribute__((packed)); /** Common int_status */ @@ -336,11 +346,11 @@ enum { /** CL BAR1 did not respond to cycle from host */ FPGA_INT_STATUS_BAR1_SLAVE_TIMEOUT = 1 << 29, - FPGA_INT_STATUS_ALL = + FPGA_INT_STATUS_ALL = FPGA_INT_STATUS_SDACL_SLAVE_TIMEOUT | FPGA_INT_STATUS_VIRTUAL_JTAG_SLAVE_TIMEOUT | FPGA_INT_STATUS_DMA_PCI_SLAVE_TIMEOUT | - FPGA_INT_STATUS_PCI_MASTER_RANGE_ERROR | + FPGA_INT_STATUS_PCI_MASTER_RANGE_ERROR | FPGA_INT_STATUS_PCI_MASTER_AXI_PROTOCOL_ERROR | FPGA_INT_STATUS_OCL_SLAVE_TIMEOUT | FPGA_INT_STATUS_BAR1_SLAVE_TIMEOUT, @@ -358,11 +368,11 @@ enum { FPGA_PAP_RREADY_TIMEOUT_ERROR = 1 << 9, FPGA_PAP_WCHANNEL_TIMEOUT_ERROR = 1 << 10, - FPGA_PAP_ERROR_STATUS_ALL = + FPGA_PAP_ERROR_STATUS_ALL = FPGA_PAP_4K_CROSS_ERROR | FPGA_PAP_BM_EN_ERROR | FPGA_PAP_REQ_SIZE_ERROR | FPGA_PAP_WR_INCOMPLETE_ERROR | FPGA_PAP_FIRST_BYTE_EN_ERROR | FPGA_PAP_LAST_BYTE_EN_ERROR | FPGA_PAP_BREADY_TIMEOUT_ERROR | - FPGA_PAP_RREADY_TIMEOUT_ERROR | + FPGA_PAP_RREADY_TIMEOUT_ERROR | FPGA_PAP_WCHANNEL_TIMEOUT_ERROR, }; diff --git a/sdk/userspace/include/utils/sh_dpi_tasks.h b/sdk/userspace/include/utils/sh_dpi_tasks.h index 439dfe99..236ff0dd 100644 --- a/sdk/userspace/include/utils/sh_dpi_tasks.h +++ b/sdk/userspace/include/utils/sh_dpi_tasks.h @@ -38,6 +38,7 @@ extern void sv_pause(uint32_t x); extern void sv_fpga_start_buffer_to_cl(uint32_t slot_id, uint32_t chan, uint32_t buf_size, uint64_t wr_buffer_addr, uint64_t cl_addr); extern void sv_fpga_start_cl_to_buffer(uint32_t slot_id, uint32_t chan, uint32_t buf_size, uint64_t rd_buffer_addr, uint64_t cl_addr); extern void init_ddr(void); +extern void deselect_atg_hw(void); extern void hm_put_byte(uint64_t addr, uint8_t data); diff --git a/sdk/userspace/python_bindings/fpga_dma.py b/sdk/userspace/python_bindings/fpga_dma.py index 25e965f5..64f01a98 100644 --- a/sdk/userspace/python_bindings/fpga_dma.py +++ b/sdk/userspace/python_bindings/fpga_dma.py @@ -12,7 +12,6 @@ # express or implied. See the License for the specific language governing # permissions and limitations under the License. # - # Python bindings for dma library # -*- coding: utf-8 -*- # @@ -24,7 +23,7 @@ _libraries = {} -_libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'] = ctypes.CDLL('PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so') +_libraries['libfpga_mgmt.so'] = ctypes.CDLL('libfpga_mgmt.so') # if local wordsize is same as target, keep ctypes pointer function. if ctypes.sizeof(ctypes.c_void_p) == 8: POINTER_T = ctypes.POINTER @@ -75,19 +74,22 @@ def __init__(self, **args): FPGA_DMA_EDMA = 0 FPGA_DMA_XDMA = 1 fpga_dma_driver = ctypes.c_int # enum -fpga_dma_open_queue = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_dma_open_queue +fpga_dma_open_queue = _libraries['libfpga_mgmt.so'].fpga_dma_open_queue fpga_dma_open_queue.restype = ctypes.c_int32 fpga_dma_open_queue.argtypes = [fpga_dma_driver, ctypes.c_int32, ctypes.c_int32, ctypes.c_bool] -fpga_dma_device_id = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_dma_device_id +fpga_dma_device_id = _libraries['libfpga_mgmt.so'].fpga_dma_device_id fpga_dma_device_id.restype = ctypes.c_int32 fpga_dma_device_id.argtypes = [fpga_dma_driver, ctypes.c_int32, ctypes.c_int32, ctypes.c_bool, ctypes.c_char * 256] size_t = ctypes.c_uint64 -fpga_dma_burst_read = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_dma_burst_read +fpga_dma_burst_read = _libraries['libfpga_mgmt.so'].fpga_dma_burst_read fpga_dma_burst_read.restype = ctypes.c_int32 fpga_dma_burst_read.argtypes = [ctypes.c_int32, POINTER_T(ctypes.c_ubyte), size_t, size_t] -fpga_dma_burst_write = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_dma_burst_write +fpga_dma_burst_write = _libraries['libfpga_mgmt.so'].fpga_dma_burst_write fpga_dma_burst_write.restype = ctypes.c_int32 fpga_dma_burst_write.argtypes = [ctypes.c_int32, POINTER_T(ctypes.c_ubyte), size_t, size_t] +fpga_pci_get_dma_device_num = _libraries['libfpga_mgmt.so'].fpga_pci_get_dma_device_num +fpga_pci_get_dma_device_num.restype = ctypes.c_int32 +fpga_pci_get_dma_device_num.argtypes = [fpga_dma_driver, ctypes.c_int32, POINTER_T(ctypes.c_int32)] # values for enumeration 'c__Ea_FPGA_CMD_RSVD' c__Ea_FPGA_CMD_RSVD__enumvalues = { @@ -96,14 +98,18 @@ def __init__(self, **args): 4: 'FPGA_CMD_CLEAR_HW_METRICS', 8: 'FPGA_CMD_FORCE_SHELL_RELOAD', 16: 'FPGA_CMD_DRAM_DATA_RETENTION', - 30: 'FPGA_CMD_ALL_FLAGS', + 64: 'FPGA_CMD_EXTENDED_METRICS_SIZE', + 128: 'FPGA_CMD_PREFETCH', + 222: 'FPGA_CMD_ALL_FLAGS', } FPGA_CMD_RSVD = 1 FPGA_CMD_GET_HW_METRICS = 2 FPGA_CMD_CLEAR_HW_METRICS = 4 FPGA_CMD_FORCE_SHELL_RELOAD = 8 FPGA_CMD_DRAM_DATA_RETENTION = 16 -FPGA_CMD_ALL_FLAGS = 30 +FPGA_CMD_EXTENDED_METRICS_SIZE = 64 +FPGA_CMD_PREFETCH = 128 +FPGA_CMD_ALL_FLAGS = 222 c__Ea_FPGA_CMD_RSVD = ctypes.c_int # enum # values for enumeration 'c__Ea_FPGA_ERR_OK' @@ -118,9 +124,14 @@ def __init__(self, **args): 16: 'FPGA_ERR_SHELL_MISMATCH', 17: 'FPGA_ERR_POWER_VIOLATION', 18: 'FPGA_ERR_DRAM_DATA_RETENTION_NOT_POSSIBLE', + 19: 'FPGA_ERR_HARDWARE_BUSY', + 20: 'FPGA_ERR_PCI_MISSING', + 21: 'FPGA_ERR_AFI_CMD_MALFORMED', 22: 'FPGA_ERR_DRAM_DATA_RETENTION_FAILED', 23: 'FPGA_ERR_DRAM_DATA_RETENTION_SETUP_FAILED', - 24: 'FPGA_ERR_END', + 24: 'FPGA_ERR_SOFTWARE_PROBLEM', + 25: 'FPGA_ERR_UNRESPONSIVE', + 26: 'FPGA_ERR_END', } FPGA_ERR_OK = 0 FPGA_ERR_AFI_CMD_BUSY = 3 @@ -132,9 +143,14 @@ def __init__(self, **args): FPGA_ERR_SHELL_MISMATCH = 16 FPGA_ERR_POWER_VIOLATION = 17 FPGA_ERR_DRAM_DATA_RETENTION_NOT_POSSIBLE = 18 +FPGA_ERR_HARDWARE_BUSY = 19 +FPGA_ERR_PCI_MISSING = 20 +FPGA_ERR_AFI_CMD_MALFORMED = 21 FPGA_ERR_DRAM_DATA_RETENTION_FAILED = 22 FPGA_ERR_DRAM_DATA_RETENTION_SETUP_FAILED = 23 -FPGA_ERR_END = 24 +FPGA_ERR_SOFTWARE_PROBLEM = 24 +FPGA_ERR_UNRESPONSIVE = 25 +FPGA_ERR_END = 26 c__Ea_FPGA_ERR_OK = ctypes.c_int # enum # values for enumeration 'c__Ea_FPGA_STATUS_LOADED' @@ -273,6 +289,8 @@ class struct_fpga_metrics_common(ctypes.Structure): ('power_mean', ctypes.c_uint64), ('power_max', ctypes.c_uint64), ('power', ctypes.c_uint64), + ('cached_agfis', ctypes.c_uint64 * 16), + ('flags', ctypes.c_uint64), ] @@ -324,16 +342,19 @@ class struct_fpga_metrics_common(ctypes.Structure): __all__ = \ ['APP_PF_BAR0', 'APP_PF_BAR1', 'APP_PF_BAR4', 'APP_PF_BAR_MAX', 'FPGA_APP_PF', 'FPGA_CMD_ALL_FLAGS', 'FPGA_CMD_CLEAR_HW_METRICS', - 'FPGA_CMD_DRAM_DATA_RETENTION', 'FPGA_CMD_FORCE_SHELL_RELOAD', - 'FPGA_CMD_GET_HW_METRICS', 'FPGA_CMD_RSVD', 'FPGA_DMA_EDMA', + 'FPGA_CMD_DRAM_DATA_RETENTION', 'FPGA_CMD_EXTENDED_METRICS_SIZE', + 'FPGA_CMD_FORCE_SHELL_RELOAD', 'FPGA_CMD_GET_HW_METRICS', + 'FPGA_CMD_PREFETCH', 'FPGA_CMD_RSVD', 'FPGA_DMA_EDMA', 'FPGA_DMA_XDMA', 'FPGA_ERR_AFI_CMD_API_VERSION_INVALID', - 'FPGA_ERR_AFI_CMD_BUSY', 'FPGA_ERR_AFI_ID_INVALID', - 'FPGA_ERR_CL_DDR_CALIB_FAILED', 'FPGA_ERR_CL_ID_MISMATCH', - 'FPGA_ERR_DRAM_DATA_RETENTION_FAILED', + 'FPGA_ERR_AFI_CMD_BUSY', 'FPGA_ERR_AFI_CMD_MALFORMED', + 'FPGA_ERR_AFI_ID_INVALID', 'FPGA_ERR_CL_DDR_CALIB_FAILED', + 'FPGA_ERR_CL_ID_MISMATCH', 'FPGA_ERR_DRAM_DATA_RETENTION_FAILED', 'FPGA_ERR_DRAM_DATA_RETENTION_NOT_POSSIBLE', 'FPGA_ERR_DRAM_DATA_RETENTION_SETUP_FAILED', 'FPGA_ERR_END', - 'FPGA_ERR_FAIL', 'FPGA_ERR_OK', 'FPGA_ERR_POWER_VIOLATION', - 'FPGA_ERR_SHELL_MISMATCH', 'FPGA_INT_STATUS_ALL', + 'FPGA_ERR_FAIL', 'FPGA_ERR_HARDWARE_BUSY', 'FPGA_ERR_OK', + 'FPGA_ERR_PCI_MISSING', 'FPGA_ERR_POWER_VIOLATION', + 'FPGA_ERR_SHELL_MISMATCH', 'FPGA_ERR_SOFTWARE_PROBLEM', + 'FPGA_ERR_UNRESPONSIVE', 'FPGA_INT_STATUS_ALL', 'FPGA_INT_STATUS_BAR1_SLAVE_TIMEOUT', 'FPGA_INT_STATUS_DMA_PCI_SLAVE_TIMEOUT', 'FPGA_INT_STATUS_OCL_SLAVE_TIMEOUT', @@ -355,8 +376,8 @@ class struct_fpga_metrics_common(ctypes.Structure): 'c__Ea_FPGA_PAP_4K_CROSS_ERROR', 'c__Ea_FPGA_STATUS_LOADED', 'c__Ea_MGMT_PF_BAR0', 'fpga_dma_burst_read', 'fpga_dma_burst_write', 'fpga_dma_device_id', 'fpga_dma_driver', - 'fpga_dma_open_queue', 'size_t', 'struct_afi_device_ids', - 'struct_fpga_clocks_common', 'struct_fpga_common_cfg', - 'struct_fpga_ddr_if_metrics_common', 'struct_fpga_meta_ids', - 'struct_fpga_metrics_common', 'struct_fpga_pci_resource_map', - 'struct_fpga_slot_spec'] + 'fpga_dma_open_queue', 'fpga_pci_get_dma_device_num', 'size_t', + 'struct_afi_device_ids', 'struct_fpga_clocks_common', + 'struct_fpga_common_cfg', 'struct_fpga_ddr_if_metrics_common', + 'struct_fpga_meta_ids', 'struct_fpga_metrics_common', + 'struct_fpga_pci_resource_map', 'struct_fpga_slot_spec'] diff --git a/sdk/userspace/python_bindings/fpga_mgmt.py b/sdk/userspace/python_bindings/fpga_mgmt.py index ae42d906..feaff30f 100644 --- a/sdk/userspace/python_bindings/fpga_mgmt.py +++ b/sdk/userspace/python_bindings/fpga_mgmt.py @@ -12,8 +12,7 @@ # express or implied. See the License for the specific language governing # permissions and limitations under the License. # - -# Python bindings for management library +# Python bindings for mgmt library # -*- coding: utf-8 -*- # # WORD_SIZE is: 8 @@ -24,7 +23,7 @@ _libraries = {} -_libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'] = ctypes.CDLL('PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so') +_libraries['libfpga_mgmt.so'] = ctypes.CDLL('libfpga_mgmt.so') # if local wordsize is same as target, keep ctypes pointer function. if ctypes.sizeof(ctypes.c_void_p) == 8: POINTER_T = ctypes.POINTER @@ -74,25 +73,69 @@ def __init__(self, **args): -fpga_mgmt_init = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_init +fpga_mgmt_init = _libraries['libfpga_mgmt.so'].fpga_mgmt_init fpga_mgmt_init.restype = ctypes.c_int32 fpga_mgmt_init.argtypes = [] -fpga_mgmt_close = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_close +fpga_mgmt_close = _libraries['libfpga_mgmt.so'].fpga_mgmt_close fpga_mgmt_close.restype = ctypes.c_int32 fpga_mgmt_close.argtypes = [] -fpga_mgmt_strerror = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_strerror +fpga_mgmt_strerror = _libraries['libfpga_mgmt.so'].fpga_mgmt_strerror fpga_mgmt_strerror.restype = POINTER_T(ctypes.c_char) fpga_mgmt_strerror.argtypes = [ctypes.c_int32] +fpga_mgmt_strerror_long = _libraries['libfpga_mgmt.so'].fpga_mgmt_strerror_long +fpga_mgmt_strerror_long.restype = POINTER_T(ctypes.c_char) +fpga_mgmt_strerror_long.argtypes = [ctypes.c_int32] uint32_t = ctypes.c_uint32 -fpga_mgmt_set_cmd_timeout = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_set_cmd_timeout +fpga_mgmt_set_cmd_timeout = _libraries['libfpga_mgmt.so'].fpga_mgmt_set_cmd_timeout fpga_mgmt_set_cmd_timeout.restype = None fpga_mgmt_set_cmd_timeout.argtypes = [uint32_t] -fpga_mgmt_set_cmd_delay_msec = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_set_cmd_delay_msec +fpga_mgmt_set_cmd_delay_msec = _libraries['libfpga_mgmt.so'].fpga_mgmt_set_cmd_delay_msec fpga_mgmt_set_cmd_delay_msec.restype = None fpga_mgmt_set_cmd_delay_msec.argtypes = [uint32_t] class struct_fpga_mgmt_image_info(ctypes.Structure): pass +class struct_fpga_meta_ids(ctypes.Structure): + pass + +class struct_afi_device_ids(ctypes.Structure): + _pack_ = True # source:True + _fields_ = [ + ('vendor_id', ctypes.c_uint16), + ('device_id', ctypes.c_uint16), + ('svid', ctypes.c_uint16), + ('ssid', ctypes.c_uint16), + ] + +struct_fpga_meta_ids._pack_ = True # source:True +struct_fpga_meta_ids._fields_ = [ + ('afi_id', ctypes.c_char * 64), + ('afi_device_ids', struct_afi_device_ids), +] + +class struct_fpga_slot_spec(ctypes.Structure): + pass + +class struct_fpga_pci_resource_map(ctypes.Structure): + _pack_ = True # source:True + _fields_ = [ + ('vendor_id', ctypes.c_uint16), + ('device_id', ctypes.c_uint16), + ('subsystem_device_id', ctypes.c_uint16), + ('subsystem_vendor_id', ctypes.c_uint16), + ('domain', ctypes.c_uint16), + ('bus', ctypes.c_ubyte), + ('dev', ctypes.c_ubyte), + ('func', ctypes.c_ubyte), + ('resource_burstable', ctypes.c_bool * 5), + ('resource_size', ctypes.c_uint64 * 5), + ] + +struct_fpga_slot_spec._pack_ = True # source:True +struct_fpga_slot_spec._fields_ = [ + ('map', struct_fpga_pci_resource_map * 2), +] + class struct_fpga_metrics_common(ctypes.Structure): pass @@ -135,47 +178,8 @@ class struct_fpga_clocks_common(ctypes.Structure): ('power_mean', ctypes.c_uint64), ('power_max', ctypes.c_uint64), ('power', ctypes.c_uint64), -] - -class struct_fpga_slot_spec(ctypes.Structure): - pass - -class struct_fpga_pci_resource_map(ctypes.Structure): - _pack_ = True # source:True - _fields_ = [ - ('vendor_id', ctypes.c_uint16), - ('device_id', ctypes.c_uint16), - ('subsystem_device_id', ctypes.c_uint16), - ('subsystem_vendor_id', ctypes.c_uint16), - ('domain', ctypes.c_uint16), - ('bus', ctypes.c_ubyte), - ('dev', ctypes.c_ubyte), - ('func', ctypes.c_ubyte), - ('resource_burstable', ctypes.c_bool * 5), - ('resource_size', ctypes.c_uint64 * 5), - ] - -struct_fpga_slot_spec._pack_ = True # source:True -struct_fpga_slot_spec._fields_ = [ - ('map', struct_fpga_pci_resource_map * 2), -] - -class struct_fpga_meta_ids(ctypes.Structure): - pass - -class struct_afi_device_ids(ctypes.Structure): - _pack_ = True # source:True - _fields_ = [ - ('vendor_id', ctypes.c_uint16), - ('device_id', ctypes.c_uint16), - ('svid', ctypes.c_uint16), - ('ssid', ctypes.c_uint16), - ] - -struct_fpga_meta_ids._pack_ = True # source:True -struct_fpga_meta_ids._fields_ = [ - ('afi_id', ctypes.c_char * 64), - ('afi_device_ids', struct_afi_device_ids), + ('cached_agfis', ctypes.c_uint64 * 16), + ('flags', ctypes.c_uint64), ] struct_fpga_mgmt_image_info._pack_ = True # source:False @@ -189,25 +193,25 @@ class struct_afi_device_ids(ctypes.Structure): ('metrics', struct_fpga_metrics_common), ] -fpga_mgmt_describe_local_image = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_describe_local_image +fpga_mgmt_describe_local_image = _libraries['libfpga_mgmt.so'].fpga_mgmt_describe_local_image fpga_mgmt_describe_local_image.restype = ctypes.c_int32 fpga_mgmt_describe_local_image.argtypes = [ctypes.c_int32, POINTER_T(struct_fpga_mgmt_image_info), uint32_t] -fpga_mgmt_get_status = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_get_status +fpga_mgmt_get_status = _libraries['libfpga_mgmt.so'].fpga_mgmt_get_status fpga_mgmt_get_status.restype = ctypes.c_int32 fpga_mgmt_get_status.argtypes = [ctypes.c_int32, POINTER_T(ctypes.c_int32), POINTER_T(ctypes.c_int32)] -fpga_mgmt_get_status_name = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_get_status_name +fpga_mgmt_get_status_name = _libraries['libfpga_mgmt.so'].fpga_mgmt_get_status_name fpga_mgmt_get_status_name.restype = POINTER_T(ctypes.c_char) fpga_mgmt_get_status_name.argtypes = [ctypes.c_int32] -fpga_mgmt_clear_local_image = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_clear_local_image +fpga_mgmt_clear_local_image = _libraries['libfpga_mgmt.so'].fpga_mgmt_clear_local_image fpga_mgmt_clear_local_image.restype = ctypes.c_int32 fpga_mgmt_clear_local_image.argtypes = [ctypes.c_int32] -fpga_mgmt_clear_local_image_sync = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_clear_local_image_sync +fpga_mgmt_clear_local_image_sync = _libraries['libfpga_mgmt.so'].fpga_mgmt_clear_local_image_sync fpga_mgmt_clear_local_image_sync.restype = ctypes.c_int32 fpga_mgmt_clear_local_image_sync.argtypes = [ctypes.c_int32, uint32_t, uint32_t, POINTER_T(struct_fpga_mgmt_image_info)] -fpga_mgmt_load_local_image = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_load_local_image +fpga_mgmt_load_local_image = _libraries['libfpga_mgmt.so'].fpga_mgmt_load_local_image fpga_mgmt_load_local_image.restype = ctypes.c_int32 fpga_mgmt_load_local_image.argtypes = [ctypes.c_int32, POINTER_T(ctypes.c_char)] -fpga_mgmt_load_local_image_flags = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_load_local_image_flags +fpga_mgmt_load_local_image_flags = _libraries['libfpga_mgmt.so'].fpga_mgmt_load_local_image_flags fpga_mgmt_load_local_image_flags.restype = ctypes.c_int32 fpga_mgmt_load_local_image_flags.argtypes = [ctypes.c_int32, POINTER_T(ctypes.c_char), uint32_t] class union_fpga_mgmt_load_local_image_options(ctypes.Union): @@ -230,29 +234,29 @@ class struct_fpga_mgmt_load_local_image_options_0(ctypes.Structure): ('PADDING_0', ctypes.c_ubyte * 992), ] -fpga_mgmt_init_load_local_image_options = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_init_load_local_image_options +fpga_mgmt_init_load_local_image_options = _libraries['libfpga_mgmt.so'].fpga_mgmt_init_load_local_image_options fpga_mgmt_init_load_local_image_options.restype = ctypes.c_int32 fpga_mgmt_init_load_local_image_options.argtypes = [POINTER_T(union_fpga_mgmt_load_local_image_options)] -fpga_mgmt_load_local_image_with_options = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_load_local_image_with_options +fpga_mgmt_load_local_image_with_options = _libraries['libfpga_mgmt.so'].fpga_mgmt_load_local_image_with_options fpga_mgmt_load_local_image_with_options.restype = ctypes.c_int32 fpga_mgmt_load_local_image_with_options.argtypes = [POINTER_T(union_fpga_mgmt_load_local_image_options)] -fpga_mgmt_load_local_image_sync = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_load_local_image_sync +fpga_mgmt_load_local_image_sync = _libraries['libfpga_mgmt.so'].fpga_mgmt_load_local_image_sync fpga_mgmt_load_local_image_sync.restype = ctypes.c_int32 fpga_mgmt_load_local_image_sync.argtypes = [ctypes.c_int32, POINTER_T(ctypes.c_char), uint32_t, uint32_t, POINTER_T(struct_fpga_mgmt_image_info)] -fpga_mgmt_load_local_image_sync_flags = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_load_local_image_sync_flags +fpga_mgmt_load_local_image_sync_flags = _libraries['libfpga_mgmt.so'].fpga_mgmt_load_local_image_sync_flags fpga_mgmt_load_local_image_sync_flags.restype = ctypes.c_int32 fpga_mgmt_load_local_image_sync_flags.argtypes = [ctypes.c_int32, POINTER_T(ctypes.c_char), uint32_t, uint32_t, uint32_t, POINTER_T(struct_fpga_mgmt_image_info)] -fpga_mgmt_load_local_image_sync_with_options = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_load_local_image_sync_with_options +fpga_mgmt_load_local_image_sync_with_options = _libraries['libfpga_mgmt.so'].fpga_mgmt_load_local_image_sync_with_options fpga_mgmt_load_local_image_sync_with_options.restype = ctypes.c_int32 fpga_mgmt_load_local_image_sync_with_options.argtypes = [POINTER_T(union_fpga_mgmt_load_local_image_options), uint32_t, uint32_t, POINTER_T(struct_fpga_mgmt_image_info)] -fpga_mgmt_get_vLED_status = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_get_vLED_status +fpga_mgmt_get_vLED_status = _libraries['libfpga_mgmt.so'].fpga_mgmt_get_vLED_status fpga_mgmt_get_vLED_status.restype = ctypes.c_int32 fpga_mgmt_get_vLED_status.argtypes = [ctypes.c_int32, POINTER_T(ctypes.c_uint16)] uint16_t = ctypes.c_uint16 -fpga_mgmt_set_vDIP = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_set_vDIP +fpga_mgmt_set_vDIP = _libraries['libfpga_mgmt.so'].fpga_mgmt_set_vDIP fpga_mgmt_set_vDIP.restype = ctypes.c_int32 fpga_mgmt_set_vDIP.argtypes = [ctypes.c_int32, uint16_t] -fpga_mgmt_get_vDIP_status = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_mgmt_get_vDIP_status +fpga_mgmt_get_vDIP_status = _libraries['libfpga_mgmt.so'].fpga_mgmt_get_vDIP_status fpga_mgmt_get_vDIP_status.restype = ctypes.c_int32 fpga_mgmt_get_vDIP_status.argtypes = [ctypes.c_int32, POINTER_T(ctypes.c_uint16)] @@ -263,14 +267,18 @@ class struct_fpga_mgmt_load_local_image_options_0(ctypes.Structure): 4: 'FPGA_CMD_CLEAR_HW_METRICS', 8: 'FPGA_CMD_FORCE_SHELL_RELOAD', 16: 'FPGA_CMD_DRAM_DATA_RETENTION', - 30: 'FPGA_CMD_ALL_FLAGS', + 64: 'FPGA_CMD_EXTENDED_METRICS_SIZE', + 128: 'FPGA_CMD_PREFETCH', + 222: 'FPGA_CMD_ALL_FLAGS', } FPGA_CMD_RSVD = 1 FPGA_CMD_GET_HW_METRICS = 2 FPGA_CMD_CLEAR_HW_METRICS = 4 FPGA_CMD_FORCE_SHELL_RELOAD = 8 FPGA_CMD_DRAM_DATA_RETENTION = 16 -FPGA_CMD_ALL_FLAGS = 30 +FPGA_CMD_EXTENDED_METRICS_SIZE = 64 +FPGA_CMD_PREFETCH = 128 +FPGA_CMD_ALL_FLAGS = 222 c__Ea_FPGA_CMD_RSVD = ctypes.c_int # enum # values for enumeration 'c__Ea_FPGA_ERR_OK' @@ -285,9 +293,14 @@ class struct_fpga_mgmt_load_local_image_options_0(ctypes.Structure): 16: 'FPGA_ERR_SHELL_MISMATCH', 17: 'FPGA_ERR_POWER_VIOLATION', 18: 'FPGA_ERR_DRAM_DATA_RETENTION_NOT_POSSIBLE', + 19: 'FPGA_ERR_HARDWARE_BUSY', + 20: 'FPGA_ERR_PCI_MISSING', + 21: 'FPGA_ERR_AFI_CMD_MALFORMED', 22: 'FPGA_ERR_DRAM_DATA_RETENTION_FAILED', 23: 'FPGA_ERR_DRAM_DATA_RETENTION_SETUP_FAILED', - 24: 'FPGA_ERR_END', + 24: 'FPGA_ERR_SOFTWARE_PROBLEM', + 25: 'FPGA_ERR_UNRESPONSIVE', + 26: 'FPGA_ERR_END', } FPGA_ERR_OK = 0 FPGA_ERR_AFI_CMD_BUSY = 3 @@ -299,9 +312,14 @@ class struct_fpga_mgmt_load_local_image_options_0(ctypes.Structure): FPGA_ERR_SHELL_MISMATCH = 16 FPGA_ERR_POWER_VIOLATION = 17 FPGA_ERR_DRAM_DATA_RETENTION_NOT_POSSIBLE = 18 +FPGA_ERR_HARDWARE_BUSY = 19 +FPGA_ERR_PCI_MISSING = 20 +FPGA_ERR_AFI_CMD_MALFORMED = 21 FPGA_ERR_DRAM_DATA_RETENTION_FAILED = 22 FPGA_ERR_DRAM_DATA_RETENTION_SETUP_FAILED = 23 -FPGA_ERR_END = 24 +FPGA_ERR_SOFTWARE_PROBLEM = 24 +FPGA_ERR_UNRESPONSIVE = 25 +FPGA_ERR_END = 26 c__Ea_FPGA_ERR_OK = ctypes.c_int # enum # values for enumeration 'c__Ea_FPGA_STATUS_LOADED' @@ -412,15 +430,19 @@ class struct_fpga_common_cfg(ctypes.Structure): __all__ = \ ['APP_PF_BAR0', 'APP_PF_BAR1', 'APP_PF_BAR4', 'APP_PF_BAR_MAX', 'FPGA_APP_PF', 'FPGA_CMD_ALL_FLAGS', 'FPGA_CMD_CLEAR_HW_METRICS', - 'FPGA_CMD_DRAM_DATA_RETENTION', 'FPGA_CMD_FORCE_SHELL_RELOAD', - 'FPGA_CMD_GET_HW_METRICS', 'FPGA_CMD_RSVD', + 'FPGA_CMD_DRAM_DATA_RETENTION', 'FPGA_CMD_EXTENDED_METRICS_SIZE', + 'FPGA_CMD_FORCE_SHELL_RELOAD', 'FPGA_CMD_GET_HW_METRICS', + 'FPGA_CMD_PREFETCH', 'FPGA_CMD_RSVD', 'FPGA_ERR_AFI_CMD_API_VERSION_INVALID', 'FPGA_ERR_AFI_CMD_BUSY', - 'FPGA_ERR_AFI_ID_INVALID', 'FPGA_ERR_CL_DDR_CALIB_FAILED', - 'FPGA_ERR_CL_ID_MISMATCH', 'FPGA_ERR_DRAM_DATA_RETENTION_FAILED', + 'FPGA_ERR_AFI_CMD_MALFORMED', 'FPGA_ERR_AFI_ID_INVALID', + 'FPGA_ERR_CL_DDR_CALIB_FAILED', 'FPGA_ERR_CL_ID_MISMATCH', + 'FPGA_ERR_DRAM_DATA_RETENTION_FAILED', 'FPGA_ERR_DRAM_DATA_RETENTION_NOT_POSSIBLE', 'FPGA_ERR_DRAM_DATA_RETENTION_SETUP_FAILED', 'FPGA_ERR_END', - 'FPGA_ERR_FAIL', 'FPGA_ERR_OK', 'FPGA_ERR_POWER_VIOLATION', - 'FPGA_ERR_SHELL_MISMATCH', 'FPGA_INT_STATUS_ALL', + 'FPGA_ERR_FAIL', 'FPGA_ERR_HARDWARE_BUSY', 'FPGA_ERR_OK', + 'FPGA_ERR_PCI_MISSING', 'FPGA_ERR_POWER_VIOLATION', + 'FPGA_ERR_SHELL_MISMATCH', 'FPGA_ERR_SOFTWARE_PROBLEM', + 'FPGA_ERR_UNRESPONSIVE', 'FPGA_INT_STATUS_ALL', 'FPGA_INT_STATUS_BAR1_SLAVE_TIMEOUT', 'FPGA_INT_STATUS_DMA_PCI_SLAVE_TIMEOUT', 'FPGA_INT_STATUS_OCL_SLAVE_TIMEOUT', @@ -453,10 +475,10 @@ class struct_fpga_common_cfg(ctypes.Structure): 'fpga_mgmt_load_local_image_with_options', 'fpga_mgmt_set_cmd_delay_msec', 'fpga_mgmt_set_cmd_timeout', 'fpga_mgmt_set_vDIP', 'fpga_mgmt_strerror', - 'struct_afi_device_ids', 'struct_fpga_clocks_common', - 'struct_fpga_common_cfg', 'struct_fpga_ddr_if_metrics_common', - 'struct_fpga_meta_ids', 'struct_fpga_metrics_common', - 'struct_fpga_mgmt_image_info', + 'fpga_mgmt_strerror_long', 'struct_afi_device_ids', + 'struct_fpga_clocks_common', 'struct_fpga_common_cfg', + 'struct_fpga_ddr_if_metrics_common', 'struct_fpga_meta_ids', + 'struct_fpga_metrics_common', 'struct_fpga_mgmt_image_info', 'struct_fpga_mgmt_load_local_image_options_0', 'struct_fpga_pci_resource_map', 'struct_fpga_slot_spec', 'uint16_t', 'uint32_t', diff --git a/sdk/userspace/python_bindings/fpga_pci.py b/sdk/userspace/python_bindings/fpga_pci.py index d0748a2f..46bd8e88 100644 --- a/sdk/userspace/python_bindings/fpga_pci.py +++ b/sdk/userspace/python_bindings/fpga_pci.py @@ -12,7 +12,6 @@ # express or implied. See the License for the specific language governing # permissions and limitations under the License. # - # Python bindings for pci library # -*- coding: utf-8 -*- # @@ -24,7 +23,7 @@ _libraries = {} -_libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'] = ctypes.CDLL('PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so') +_libraries['libfpga_mgmt.so'] = ctypes.CDLL('libfpga_mgmt.so') # if local wordsize is same as target, keep ctypes pointer function. if ctypes.sizeof(ctypes.c_void_p) == 8: POINTER_T = ctypes.POINTER @@ -75,11 +74,11 @@ def __init__(self, **args): pci_bar_handle_t = ctypes.c_int32 -fpga_pci_init = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_init +fpga_pci_init = _libraries['libfpga_mgmt.so'].fpga_pci_init fpga_pci_init.restype = ctypes.c_int32 fpga_pci_init.argtypes = [] uint32_t = ctypes.c_uint32 -fpga_pci_attach = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_attach +fpga_pci_attach = _libraries['libfpga_mgmt.so'].fpga_pci_attach fpga_pci_attach.restype = ctypes.c_int32 fpga_pci_attach.argtypes = [ctypes.c_int32, ctypes.c_int32, ctypes.c_int32, uint32_t, POINTER_T(ctypes.c_int32)] @@ -91,36 +90,36 @@ def __init__(self, **args): BURST_CAPABLE = 1 FPGA_ATTACH_RESERVED = 4294967294 c__Ea_BURST_CAPABLE = ctypes.c_int # enum -fpga_pci_detach = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_detach +fpga_pci_detach = _libraries['libfpga_mgmt.so'].fpga_pci_detach fpga_pci_detach.restype = ctypes.c_int32 fpga_pci_detach.argtypes = [pci_bar_handle_t] uint64_t = ctypes.c_uint64 -fpga_pci_poke = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_poke +fpga_pci_poke = _libraries['libfpga_mgmt.so'].fpga_pci_poke fpga_pci_poke.restype = ctypes.c_int32 fpga_pci_poke.argtypes = [pci_bar_handle_t, uint64_t, uint32_t] uint8_t = ctypes.c_uint8 -fpga_pci_poke8 = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_poke8 +fpga_pci_poke8 = _libraries['libfpga_mgmt.so'].fpga_pci_poke8 fpga_pci_poke8.restype = ctypes.c_int32 fpga_pci_poke8.argtypes = [pci_bar_handle_t, uint64_t, uint8_t] -fpga_pci_poke64 = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_poke64 +fpga_pci_poke64 = _libraries['libfpga_mgmt.so'].fpga_pci_poke64 fpga_pci_poke64.restype = ctypes.c_int32 fpga_pci_poke64.argtypes = [pci_bar_handle_t, uint64_t, uint64_t] -fpga_pci_write_burst = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_write_burst +fpga_pci_write_burst = _libraries['libfpga_mgmt.so'].fpga_pci_write_burst fpga_pci_write_burst.restype = ctypes.c_int32 fpga_pci_write_burst.argtypes = [pci_bar_handle_t, uint64_t, POINTER_T(ctypes.c_uint32), uint64_t] -fpga_pci_peek = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_peek +fpga_pci_peek = _libraries['libfpga_mgmt.so'].fpga_pci_peek fpga_pci_peek.restype = ctypes.c_int32 fpga_pci_peek.argtypes = [pci_bar_handle_t, uint64_t, POINTER_T(ctypes.c_uint32)] -fpga_pci_peek8 = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_peek8 +fpga_pci_peek8 = _libraries['libfpga_mgmt.so'].fpga_pci_peek8 fpga_pci_peek8.restype = ctypes.c_int32 fpga_pci_peek8.argtypes = [pci_bar_handle_t, uint64_t, POINTER_T(ctypes.c_ubyte)] -fpga_pci_peek64 = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_peek64 +fpga_pci_peek64 = _libraries['libfpga_mgmt.so'].fpga_pci_peek64 fpga_pci_peek64.restype = ctypes.c_int32 fpga_pci_peek64.argtypes = [pci_bar_handle_t, uint64_t, POINTER_T(ctypes.c_uint64)] class struct_fpga_slot_spec(ctypes.Structure): pass -fpga_pci_get_slot_spec = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_get_slot_spec +fpga_pci_get_slot_spec = _libraries['libfpga_mgmt.so'].fpga_pci_get_slot_spec fpga_pci_get_slot_spec.restype = ctypes.c_int32 fpga_pci_get_slot_spec.argtypes = [ctypes.c_int32, POINTER_T(struct_fpga_slot_spec)] class struct_fpga_pci_resource_map(ctypes.Structure): @@ -143,21 +142,22 @@ class struct_fpga_pci_resource_map(ctypes.Structure): ('map', struct_fpga_pci_resource_map * 2), ] -fpga_pci_get_all_slot_specs = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_get_all_slot_specs +fpga_pci_get_all_slot_specs = _libraries['libfpga_mgmt.so'].fpga_pci_get_all_slot_specs fpga_pci_get_all_slot_specs.restype = ctypes.c_int32 fpga_pci_get_all_slot_specs.argtypes = [struct_fpga_slot_spec * 0, ctypes.c_int32] -fpga_pci_get_resource_map = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_get_resource_map +fpga_pci_get_resource_map = _libraries['libfpga_mgmt.so'].fpga_pci_get_resource_map fpga_pci_get_resource_map.restype = ctypes.c_int32 fpga_pci_get_resource_map.argtypes = [ctypes.c_int32, ctypes.c_int32, POINTER_T(struct_fpga_pci_resource_map)] -fpga_pci_rescan_slot_app_pfs = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_rescan_slot_app_pfs +fpga_pci_rescan_slot_app_pfs = _libraries['libfpga_mgmt.so'].fpga_pci_rescan_slot_app_pfs fpga_pci_rescan_slot_app_pfs.restype = ctypes.c_int32 fpga_pci_rescan_slot_app_pfs.argtypes = [ctypes.c_int32] -fpga_pci_get_address = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_get_address +fpga_pci_get_address = _libraries['libfpga_mgmt.so'].fpga_pci_get_address fpga_pci_get_address.restype = ctypes.c_int32 fpga_pci_get_address.argtypes = [pci_bar_handle_t, uint64_t, uint64_t, POINTER_T(POINTER_T(None))] -fpga_pci_memset = _libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'].fpga_pci_memset +fpga_pci_memset = _libraries['libfpga_mgmt.so'].fpga_pci_memset fpga_pci_memset.restype = ctypes.c_int32 fpga_pci_memset.argtypes = [pci_bar_handle_t, uint64_t, uint32_t, uint64_t] + class union_c__UA_pthread_mutex_t(ctypes.Union): pass @@ -193,7 +193,14 @@ class struct___pthread_internal_list(ctypes.Structure): ('PADDING_0', ctypes.c_ubyte * 32), ] -fpga_pci_readdir_mutex = (union_c__UA_pthread_mutex_t).in_dll(_libraries['PY_BIND_AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so'], 'fpga_pci_readdir_mutex') + +fpga_pci_readdir_mutex = None # Variable union_c__UA_pthread_mutex_t +fpga_acquire_readdir_lock = _libraries['libfpga_mgmt.so'].fpga_acquire_readdir_lock +fpga_acquire_readdir_lock.restype = ctypes.c_int32 +fpga_acquire_readdir_lock.argtypes = [] +fpga_release_readdir_lock = _libraries['libfpga_mgmt.so'].fpga_release_readdir_lock +fpga_release_readdir_lock.restype = ctypes.c_int32 +fpga_release_readdir_lock.argtypes = [] # values for enumeration 'c__Ea_FPGA_CMD_RSVD' c__Ea_FPGA_CMD_RSVD__enumvalues = { @@ -202,14 +209,18 @@ class struct___pthread_internal_list(ctypes.Structure): 4: 'FPGA_CMD_CLEAR_HW_METRICS', 8: 'FPGA_CMD_FORCE_SHELL_RELOAD', 16: 'FPGA_CMD_DRAM_DATA_RETENTION', - 30: 'FPGA_CMD_ALL_FLAGS', + 64: 'FPGA_CMD_EXTENDED_METRICS_SIZE', + 128: 'FPGA_CMD_PREFETCH', + 222: 'FPGA_CMD_ALL_FLAGS', } FPGA_CMD_RSVD = 1 FPGA_CMD_GET_HW_METRICS = 2 FPGA_CMD_CLEAR_HW_METRICS = 4 FPGA_CMD_FORCE_SHELL_RELOAD = 8 FPGA_CMD_DRAM_DATA_RETENTION = 16 -FPGA_CMD_ALL_FLAGS = 30 +FPGA_CMD_EXTENDED_METRICS_SIZE = 64 +FPGA_CMD_PREFETCH = 128 +FPGA_CMD_ALL_FLAGS = 222 c__Ea_FPGA_CMD_RSVD = ctypes.c_int # enum # values for enumeration 'c__Ea_FPGA_ERR_OK' @@ -224,9 +235,14 @@ class struct___pthread_internal_list(ctypes.Structure): 16: 'FPGA_ERR_SHELL_MISMATCH', 17: 'FPGA_ERR_POWER_VIOLATION', 18: 'FPGA_ERR_DRAM_DATA_RETENTION_NOT_POSSIBLE', + 19: 'FPGA_ERR_HARDWARE_BUSY', + 20: 'FPGA_ERR_PCI_MISSING', + 21: 'FPGA_ERR_AFI_CMD_MALFORMED', 22: 'FPGA_ERR_DRAM_DATA_RETENTION_FAILED', 23: 'FPGA_ERR_DRAM_DATA_RETENTION_SETUP_FAILED', - 24: 'FPGA_ERR_END', + 24: 'FPGA_ERR_SOFTWARE_PROBLEM', + 25: 'FPGA_ERR_UNRESPONSIVE', + 26: 'FPGA_ERR_END', } FPGA_ERR_OK = 0 FPGA_ERR_AFI_CMD_BUSY = 3 @@ -238,9 +254,14 @@ class struct___pthread_internal_list(ctypes.Structure): FPGA_ERR_SHELL_MISMATCH = 16 FPGA_ERR_POWER_VIOLATION = 17 FPGA_ERR_DRAM_DATA_RETENTION_NOT_POSSIBLE = 18 +FPGA_ERR_HARDWARE_BUSY = 19 +FPGA_ERR_PCI_MISSING = 20 +FPGA_ERR_AFI_CMD_MALFORMED = 21 FPGA_ERR_DRAM_DATA_RETENTION_FAILED = 22 FPGA_ERR_DRAM_DATA_RETENTION_SETUP_FAILED = 23 -FPGA_ERR_END = 24 +FPGA_ERR_SOFTWARE_PROBLEM = 24 +FPGA_ERR_UNRESPONSIVE = 25 +FPGA_ERR_END = 26 c__Ea_FPGA_ERR_OK = ctypes.c_int # enum # values for enumeration 'c__Ea_FPGA_STATUS_LOADED' @@ -358,6 +379,8 @@ class struct_fpga_metrics_common(ctypes.Structure): ('power_mean', ctypes.c_uint64), ('power_max', ctypes.c_uint64), ('power', ctypes.c_uint64), + ('cached_agfis', ctypes.c_uint64 * 16), + ('flags', ctypes.c_uint64), ] @@ -406,20 +429,63 @@ class struct_fpga_metrics_common(ctypes.Structure): FPGA_PAP_WCHANNEL_TIMEOUT_ERROR = 1024 FPGA_PAP_ERROR_STATUS_ALL = 1918 c__Ea_FPGA_PAP_4K_CROSS_ERROR = ctypes.c_int # enum +class union_c__UA_pthread_mutex_t(ctypes.Union): + pass + +class struct___pthread_mutex_s(ctypes.Structure): + pass + +class struct___pthread_internal_list(ctypes.Structure): + pass + +struct___pthread_internal_list._pack_ = True # source:False +struct___pthread_internal_list._fields_ = [ + ('__prev', POINTER_T(struct___pthread_internal_list)), + ('__next', POINTER_T(struct___pthread_internal_list)), +] + +struct___pthread_mutex_s._pack_ = True # source:False +struct___pthread_mutex_s._fields_ = [ + ('__lock', ctypes.c_int32), + ('__count', ctypes.c_uint32), + ('__owner', ctypes.c_int32), + ('__nusers', ctypes.c_uint32), + ('__kind', ctypes.c_int32), + ('__spins', ctypes.c_int16), + ('__elision', ctypes.c_int16), + ('__list', struct___pthread_internal_list), +] + +union_c__UA_pthread_mutex_t._pack_ = True # source:False +union_c__UA_pthread_mutex_t._fields_ = [ + ('__data', struct___pthread_mutex_s), + ('__size', ctypes.c_char * 40), + ('__align', ctypes.c_int64), + ('PADDING_0', ctypes.c_ubyte * 32), +] + __all__ = \ ['APP_PF_BAR0', 'APP_PF_BAR1', 'APP_PF_BAR4', 'APP_PF_BAR_MAX', 'BURST_CAPABLE', 'FPGA_APP_PF', 'FPGA_ATTACH_RESERVED', 'FPGA_CMD_ALL_FLAGS', 'FPGA_CMD_CLEAR_HW_METRICS', - 'FPGA_CMD_DRAM_DATA_RETENTION', 'FPGA_CMD_FORCE_SHELL_RELOAD', - 'FPGA_CMD_GET_HW_METRICS', 'FPGA_CMD_RSVD', + 'FPGA_CMD_DRAM_DATA_RETENTION', 'FPGA_CMD_EXTENDED_METRICS_SIZE', + 'FPGA_CMD_FORCE_SHELL_RELOAD', 'FPGA_CMD_GET_HW_METRICS', + 'FPGA_CMD_PREFETCH', 'FPGA_CMD_RSVD', 'FPGA_ERR_AFI_CMD_API_VERSION_INVALID', 'FPGA_ERR_AFI_CMD_BUSY', - 'FPGA_ERR_AFI_ID_INVALID', 'FPGA_ERR_CL_DDR_CALIB_FAILED', - 'FPGA_ERR_CL_ID_MISMATCH', 'FPGA_ERR_DRAM_DATA_RETENTION_FAILED', + 'FPGA_ERR_AFI_CMD_MALFORMED', 'FPGA_ERR_AFI_ID_INVALID', + 'FPGA_ERR_CL_DDR_CALIB_FAILED', 'FPGA_ERR_CL_ID_MISMATCH', + 'FPGA_ERR_DRAM_DATA_RETENTION_FAILED', 'FPGA_ERR_DRAM_DATA_RETENTION_NOT_POSSIBLE', 'FPGA_ERR_DRAM_DATA_RETENTION_SETUP_FAILED', 'FPGA_ERR_END', - 'FPGA_ERR_FAIL', 'FPGA_ERR_OK', 'FPGA_ERR_POWER_VIOLATION', - 'FPGA_ERR_SHELL_MISMATCH', 'FPGA_INT_STATUS_ALL', + 'FPGA_ERR_FAIL', 'FPGA_ERR_HARDWARE_BUSY', 'FPGA_ERR_OK', + 'FPGA_ERR_PCI_MISSING', 'FPGA_ERR_POWER_VIOLATION', + 'FPGA_ERR_SHELL_MISMATCH', 'FPGA_ERR_SOFTWARE_PROBLEM', + 'FPGA_ERR_UNRESPONSIVE', 'FPGA_INT_STATUS_ALL', 'FPGA_INT_STATUS_BAR1_SLAVE_TIMEOUT', + 'FPGA_ERR_FAIL', 'FPGA_ERR_OK', 'FPGA_ERR_PCI_MISSING', + 'FPGA_ERR_POWER_VIOLATION', 'FPGA_ERR_SHELL_MISMATCH', + 'FPGA_ERR_SOFTWARE_PROBLEM', 'FPGA_ERR_UNRESPONSIVE', + 'FPGA_INT_STATUS_ALL', 'FPGA_INT_STATUS_BAR1_SLAVE_TIMEOUT', 'FPGA_INT_STATUS_DMA_PCI_SLAVE_TIMEOUT', 'FPGA_INT_STATUS_OCL_SLAVE_TIMEOUT', 'FPGA_INT_STATUS_PCI_MASTER_AXI_PROTOCOL_ERROR', @@ -439,13 +505,14 @@ class struct_fpga_metrics_common(ctypes.Structure): 'c__Ea_FPGA_CMD_RSVD', 'c__Ea_FPGA_ERR_OK', 'c__Ea_FPGA_INT_STATUS_SDACL_SLAVE_TIMEOUT', 'c__Ea_FPGA_PAP_4K_CROSS_ERROR', 'c__Ea_FPGA_STATUS_LOADED', - 'c__Ea_MGMT_PF_BAR0', 'fpga_pci_attach', 'fpga_pci_detach', - 'fpga_pci_get_address', 'fpga_pci_get_all_slot_specs', - 'fpga_pci_get_resource_map', 'fpga_pci_get_slot_spec', - 'fpga_pci_init', 'fpga_pci_memset', 'fpga_pci_peek', - 'fpga_pci_peek64', 'fpga_pci_peek8', 'fpga_pci_poke', - 'fpga_pci_poke64', 'fpga_pci_poke8', 'fpga_pci_readdir_mutex', - 'fpga_pci_rescan_slot_app_pfs', 'fpga_pci_write_burst', + 'c__Ea_MGMT_PF_BAR0', 'fpga_acquire_readdir_lock', + 'fpga_pci_attach', 'fpga_pci_detach', 'fpga_pci_get_address', + 'fpga_pci_get_all_slot_specs', 'fpga_pci_get_resource_map', + 'fpga_pci_get_slot_spec', 'fpga_pci_init', 'fpga_pci_memset', + 'fpga_pci_peek', 'fpga_pci_peek64', 'fpga_pci_peek8', + 'fpga_pci_poke', 'fpga_pci_poke64', 'fpga_pci_poke8', + 'fpga_pci_readdir_mutex', 'fpga_pci_rescan_slot_app_pfs', + 'fpga_pci_write_burst', 'fpga_release_readdir_lock', 'pci_bar_handle_t', 'struct___pthread_internal_list', 'struct___pthread_mutex_s', 'struct_afi_device_ids', 'struct_fpga_clocks_common', 'struct_fpga_common_cfg', From 2fa6b0672de67d46d1ae21147c2fbaadceb34207 Mon Sep 17 00:00:00 2001 From: AWSaalluri <35272035+AWSaalluri@users.noreply.github.com> Date: Thu, 1 Aug 2019 10:05:15 -0500 Subject: [PATCH 03/31] Rc v1 4 10 (#463) Release V1.4.10 * New functionality: * SDK now sorts the slots in DBDF order. Any scripts or integration maintainers should note that the slot order will be different from previous versions and should make any updates accordingly. * Bug Fixes: * Fixes a bug in the [Automatic Traffic Generator (ATG)](./hdk/cl/examples/cl_dram_dma/design/cl_tst.sv). In SYNC mode, the ATG did not wait for write response transaction before issuing read transactions. * Released [Xilinx runtime(XRT) version 2018.3.3.2](https://github.com/Xilinx/XRT/releases/tag/2018.3.3.2) to fix the following error: `symbol lookup error: /opt/xilinx/xrt/lib/libxrt_aws.so: undefined symbol: uuid_parse!` discussed in this [forum post](https://forums.aws.amazon.com/thread.jspa?messageID=899474󛦒). * This release fixes a bug wherein concurrent AFI load requests on two or more slots resulted in a race condition which sometimes resulted in Error: `(20) pci-device-missing` * This release fixes a issue with coding style of logic which could infer a latch during synthesis in [sde_ps_acc module](./hdk/cl/examples/cl_sde/design/sde_ps_acc.sv) within cl_sde example --- .gitmodules | 2 +- ERRATA.md | 14 +- Jenkinsfile | 38 +- Jenkinsfile_int_sims | 1150 ++++++++++ README.md | 2 +- RELEASE_NOTES.md | 24 +- SDAccel/FAQ.md | 3 + SDAccel/Makefile | 4 +- SDAccel/docs/Create_Runtime_AMI.md | 4 +- SDAccel/docs/XRT_installation_instructions.md | 19 +- .../3rd_party/README.md} | 19 +- .../examples/3rd_party/matrix_mult/Makefile | 58 - .../examples/3rd_party/matrix_mult/README.md | 32 - .../matrix_mult/device/matrix_mult.cl | 165 -- .../matrix_mult/host/inc/matrixMult.h | 32 - .../3rd_party/matrix_mult/host/src/main.cpp | 549 ----- SDAccel/examples/xilinx_2018.2 | 2 +- SDAccel/sdaccel_xrt_version.txt | 3 +- SDAccel/tests/test_find_sdaccel_examples.py | 20 +- SDAccel/tools/awssak/Makefile | 11 +- SDAccel/tools/awssak/main.cpp | 922 +------- SDAccel/tools/awssak/memaccess.h | 159 -- SDAccel/tools/awssak2/LICENSE-2.0.txt | 202 -- SDAccel/tools/awssak2/Makefile | 71 - SDAccel/tools/awssak2/main.cpp | 24 - SDAccel/userspace/include/xcl_app_debug.h | 45 +- SDAccel/userspace/include/xcl_app_debug2.h | 102 - SDAccel/userspace/include/xclbin.h | 177 +- SDAccel/userspace/include/xclbin2.h | 273 --- SDAccel/userspace/include/xclhal.h | 1032 ++++++--- SDAccel/userspace/include/xclhal2.h | 836 -------- SDAccel/userspace/include/xclperf.h | 81 +- SDAccel/userspace/include/xclperf2.h | 369 ---- SDAccel/userspace/src/Makefile | 23 +- SDAccel/userspace/{src2 => src}/README.md | 2 +- SDAccel/userspace/{src2 => src}/awssak.cpp | 0 SDAccel/userspace/{src2 => src}/awssak.h | 2 +- .../userspace/{src2 => src}/awssak_debug.cpp | 2 +- .../userspace/{src2 => src}/awssak_utils.cpp | 0 .../userspace/{src2 => src}/awssak_utils.h | 0 SDAccel/userspace/src/datamover.h | 198 -- SDAccel/userspace/{src2 => src}/dd.cpp | 0 SDAccel/userspace/{src2 => src}/dd.h | 0 SDAccel/userspace/src/debug.cpp | 163 +- SDAccel/userspace/{src2 => src}/dmatest.h | 2 +- SDAccel/userspace/{src2 => src}/memaccess.h | 5 +- SDAccel/userspace/src/memorymanager.cpp | 220 -- SDAccel/userspace/src/memorymanager.h | 75 - SDAccel/userspace/src/perf.cpp | 554 ++--- SDAccel/userspace/src/perfmon_parameters.h | 60 +- SDAccel/userspace/{src2 => src}/scan.cpp | 0 SDAccel/userspace/{src2 => src}/scan.h | 0 SDAccel/userspace/src/shim.cpp | 1865 ++++++++++------- SDAccel/userspace/src/shim.h | 165 +- SDAccel/userspace/src/test | 1862 ---------------- SDAccel/userspace/src/xclbin.cpp | 1 + SDAccel/userspace/src2/LICENSE-2.0.txt | 202 -- SDAccel/userspace/src2/Makefile | 82 - SDAccel/userspace/src2/debug.cpp | 224 -- SDAccel/userspace/src2/perf.cpp | 766 ------- SDAccel/userspace/src2/perfmon_parameters.h | 349 --- SDAccel/userspace/src2/shim.cpp | 1514 ------------- SDAccel/userspace/src2/shim.h | 380 ---- SDAccel/userspace/src2/xclbin.cpp | 53 - conftest.py | 9 +- hdk/cl/examples/cl_dram_dma/README.md | 4 +- hdk/cl/examples/cl_dram_dma/design/cl_tst.sv | 87 +- .../verif/tests/test_axi_mstr_multi_rw.sv | 10 +- .../cl_dram_dma/verif/tests/test_bar1.sv | 4 +- .../verif/tests/test_clk_recipe.sv | 2 +- .../cl_dram_dma/verif/tests/test_ddr.sv | 10 +- .../tests/test_ddr_peek_bdr_walking_ones.sv | 4 +- .../verif/tests/test_ddr_peek_poke.sv | 6 +- .../verif/tests/test_dma_pcim_concurrent.sv | 19 +- .../verif/tests/test_dma_pcis_concurrent.sv | 21 +- .../verif/tests/test_dma_sda_concurrent.sv | 15 +- .../cl_dram_dma/verif/tests/test_dram_dma.sv | 33 +- .../verif/tests/test_dram_dma_4k_crossing.sv | 27 +- .../tests/test_dram_dma_allgn_addr_4k.sv | 27 +- .../verif/tests/test_dram_dma_axi_mstr.sv | 18 +- .../verif/tests/test_dram_dma_bdr_common.svh | 11 +- .../test_dram_dma_dram_bdr_row_col_combo.sv | 2 +- .../verif/tests/test_dram_dma_dram_bdr_wr.sv | 2 +- .../tests/test_dram_dma_mem_model_bdr_rd.sv | 12 +- .../tests/test_dram_dma_mem_model_bdr_wr.sv | 12 +- .../verif/tests/test_dram_dma_multi_ddr.sv | 17 +- .../verif/tests/test_dram_dma_rnd.sv | 14 +- .../tests/test_dram_dma_single_beat_4k.sv | 27 +- .../cl_dram_dma/verif/tests/test_host_pcim.sv | 27 +- .../cl_dram_dma/verif/tests/test_int.sv | 10 +- .../verif/tests/test_peek_poke_pcis_axsize.sv | 6 +- .../verif/tests/test_peek_poke_rnd_lengths.sv | 10 +- .../verif/tests/test_peek_poke_wc.sv | 6 +- .../cl_dram_dma/verif/tests/test_sda.sv | 4 +- .../software/runtime/test_hello_world.c | 30 +- hdk/cl/examples/cl_sde/README.md | 4 +- .../examples/cl_sde/build/scripts/encrypt.tcl | 2 +- hdk/cl/examples/cl_sde/design/cl_pkt_tst.sv | 14 +- hdk/cl/examples/cl_sde/design/cl_sde.sv | 26 +- .../examples/cl_sde/design/cl_sde_defines.vh | 1 + hdk/cl/examples/cl_sde/design/cl_tst.sv | 89 +- hdk/cl/examples/cl_sde/design/sde_c2h_data.sv | 26 +- hdk/cl/examples/cl_sde/design/sde_h2c_data.sv | 20 +- hdk/cl/examples/cl_sde/design/sde_ps_acc.sv | 12 +- hdk/cl/examples/cl_sde/design/sde_wb.sv | 4 +- hdk/cl/examples/cl_sde/lib/ram_fifo_ft.sv | 2 +- .../examples/cl_sde/software/runtime/Makefile | 27 +- .../software/runtime/test_uram_example.c | 12 +- hdk/common/software/include/fpga_pci_sv.h | 17 + hdk/common/software/src/fpga_pci_sv.c | 10 + hdk/docs/RTL_Simulating_CL_Designs.md | 2 +- hdk/hdk_version.txt | 2 +- hdk/tests/simulation_tests/run_sim.sh | 113 +- hdk/tests/simulation_tests/test_sims.py | 253 +-- hdk/tests/test_gen_dcp.py | 20 +- hdk/tests/test_load_afi.py | 15 +- hdk_setup.sh | 25 +- sdaccel_runtime_setup.sh | 2 +- sdk/apps/byte_swapper/app.py | 1 + sdk/apps/byte_swapper/fpga_funcs.py | 4 + .../scripts/virtual_ethernet_install.py | 0 .../virtual_ethernet_pktgen_install.py | 0 .../scripts/virtual_ethernet_pktgen_setup.py | 0 .../scripts/virtual_ethernet_setup.py | 0 sdk/linux_kernel_drivers/xocl/xocl_drv.h | 2 +- sdk/tests/test_fpga_tools.py | 16 + sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c | 74 +- .../fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c | 43 +- .../fpga_libs/fpga_mgmt/fpga_mgmt_internal.h | 9 + .../fpga_libs/fpga_pci/fpga_pci_sysfs.c | 145 +- .../fpga_mgmt_tools/src/fpga_local_cmd.c | 4 +- shared/bin/set_common_functions.sh | 11 +- .../aws_fpga_test_utils/AwsFpgaTestBase.py | 1 + shared/tests/bin/setup_test_env.sh | 5 +- shared/tests/bin/setup_test_env_al2.sh | 3 +- shared/tests/bin/setup_test_xrtpatch.sh | 52 +- 136 files changed, 4782 insertions(+), 11985 deletions(-) create mode 100644 Jenkinsfile_int_sims rename SDAccel/{docs/README_third_party.md => examples/3rd_party/README.md} (86%) delete mode 100644 SDAccel/examples/3rd_party/matrix_mult/Makefile delete mode 100644 SDAccel/examples/3rd_party/matrix_mult/README.md delete mode 100644 SDAccel/examples/3rd_party/matrix_mult/device/matrix_mult.cl delete mode 100644 SDAccel/examples/3rd_party/matrix_mult/host/inc/matrixMult.h delete mode 100644 SDAccel/examples/3rd_party/matrix_mult/host/src/main.cpp delete mode 100644 SDAccel/tools/awssak/memaccess.h delete mode 100644 SDAccel/tools/awssak2/LICENSE-2.0.txt delete mode 100644 SDAccel/tools/awssak2/Makefile delete mode 100644 SDAccel/tools/awssak2/main.cpp delete mode 100755 SDAccel/userspace/include/xcl_app_debug2.h delete mode 100644 SDAccel/userspace/include/xclbin2.h delete mode 100644 SDAccel/userspace/include/xclhal2.h delete mode 100755 SDAccel/userspace/include/xclperf2.h rename SDAccel/userspace/{src2 => src}/README.md (91%) rename SDAccel/userspace/{src2 => src}/awssak.cpp (100%) rename SDAccel/userspace/{src2 => src}/awssak.h (99%) rename SDAccel/userspace/{src2 => src}/awssak_debug.cpp (99%) rename SDAccel/userspace/{src2 => src}/awssak_utils.cpp (100%) rename SDAccel/userspace/{src2 => src}/awssak_utils.h (100%) delete mode 100644 SDAccel/userspace/src/datamover.h rename SDAccel/userspace/{src2 => src}/dd.cpp (100%) rename SDAccel/userspace/{src2 => src}/dd.h (100%) rename SDAccel/userspace/{src2 => src}/dmatest.h (99%) rename SDAccel/userspace/{src2 => src}/memaccess.h (99%) delete mode 100644 SDAccel/userspace/src/memorymanager.cpp delete mode 100644 SDAccel/userspace/src/memorymanager.h rename SDAccel/userspace/{src2 => src}/scan.cpp (100%) rename SDAccel/userspace/{src2 => src}/scan.h (100%) delete mode 100644 SDAccel/userspace/src/test delete mode 100644 SDAccel/userspace/src2/LICENSE-2.0.txt delete mode 100755 SDAccel/userspace/src2/Makefile delete mode 100644 SDAccel/userspace/src2/debug.cpp delete mode 100755 SDAccel/userspace/src2/perf.cpp delete mode 100755 SDAccel/userspace/src2/perfmon_parameters.h delete mode 100755 SDAccel/userspace/src2/shim.cpp delete mode 100755 SDAccel/userspace/src2/shim.h delete mode 100755 SDAccel/userspace/src2/xclbin.cpp mode change 100644 => 100755 sdk/apps/virtual-ethernet/scripts/virtual_ethernet_install.py mode change 100644 => 100755 sdk/apps/virtual-ethernet/scripts/virtual_ethernet_pktgen_install.py mode change 100644 => 100755 sdk/apps/virtual-ethernet/scripts/virtual_ethernet_pktgen_setup.py mode change 100644 => 100755 sdk/apps/virtual-ethernet/scripts/virtual_ethernet_setup.py diff --git a/.gitmodules b/.gitmodules index 3cccf78d..a31a1562 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,7 +5,7 @@ [submodule "SDAccel/examples/xilinx_2018.2"] path = SDAccel/examples/xilinx_2018.2 url = https://github.com/Xilinx/SDAccel_Examples.git - branch = 2018.2 + branch = 2018.2_xdf [submodule "SDAccel/examples/xilinx_2018.3"] path = SDAccel/examples/xilinx_2018.3 url = https://github.com/Xilinx/SDAccel_Examples.git diff --git a/ERRATA.md b/ERRATA.md index 2dd87370..fc379d81 100644 --- a/ERRATA.md +++ b/ERRATA.md @@ -5,23 +5,13 @@ [Shell\_04261818_Errata](./hdk/docs/AWS_Shell_ERRATA.md) ## HDK -* Multiple SDE instances per CL is not supported in this release. Support planned for future release. +* Multiple SDE instances per CL is not supported in this release. Support is planned for a future release. * DRAM Data retention is not supported for CL designs with less than 4 DDRs enabled * Combinatorial loops in CL designs are not supported. -* [Automatic Traffic Generator (ATG)](./hdk/cl/examples/cl_dram_dma/design/cl_tst.sv) in SYNC mode does not wait for write response transaction before issuing read transactions. The fix for this issue is planned in a future release. ## SDK ## SDAccel (For additional restrictions see [SDAccel ERRATA](./SDAccel/ERRATA.md)) * Virtual Ethernet is not supported when using SDAccel * DRAM Data retention is not supported for kernels that provision less than 4 DDRs -* Combinatorial loops in CL designs are not supported. -* When using [Xilinx runtime(XRT) version 2018.3.3.1](https://github.com/Xilinx/XRT/releases/tag/2018.3.3.1) or [AWS FPGA Developer AMI Version 1.6.0](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) your host application could fail with following error: - - ``` - : symbol lookup error: /opt/xilinx/xrt/lib/libxrt_aws.so: undefined symbol: uuid_parse! - - ``` - The SDAccel examples included in the developer kit use a SDAccel configuration file [sdaccel.ini]. To workaround this error please copy the SDAccel configuration file [sdaccel.ini](SDAccel/examples/aws/helloworld_ocl_runtime/sdaccel.ini) to your executable directory and try executing your application again. - AWS is working with Xilinx to release a XRT patch to fix this issue. - +* Combinatorial loops in CL designs are not supported. diff --git a/Jenkinsfile b/Jenkinsfile index 11da24a6..3df7ee08 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -46,7 +46,7 @@ boolean test_all_sdaccel_examples_fdf = params.get('test_all_sdaccel_examples_fd boolean test_helloworld_sdaccel_example_fdf = params.get('test_helloworld_sdaccel_example_fdf') boolean disable_runtime_tests = params.get('disable_runtime_tests') -def runtime_sw_cl_names = ['cl_dram_dma', 'cl_hello_world'] +def runtime_sw_cl_names = ['cl_dram_dma', 'cl_hello_world', 'cl_sde'] def dcp_recipe_cl_names = ['cl_dram_dma', 'cl_hello_world'] def dcp_recipe_scenarios = [ // Default values are tested in FDF: A0-B0-C0-DEFAULT @@ -68,6 +68,7 @@ def fdf_test_names = [ 'cl_dram_dma[A1-B0-C0-DEFAULT]', 'cl_hello_world[A0-B0-C0-DEFAULT]', 'cl_hello_world_vhdl', + 'cl_sde[A0-B0-C0-DEFAULT]', 'cl_uram_example[2]', 'cl_uram_example[3]', 'cl_uram_example[4]' @@ -75,7 +76,7 @@ def fdf_test_names = [ boolean debug_dcp_gen = params.get('debug_dcp_gen') if (debug_dcp_gen) { - fdf_test_names = ['cl_hello_world[A0-B0-C0-DEFAULT]'] + fdf_test_names = ['cl_sde[A0-B0-C0-DEFAULT]'] test_markdown_links = false test_sims = false test_runtime_software = false @@ -158,19 +159,19 @@ def sdaccel_example_default_map = [ def simulator_tool_default_map = [ '2017.4' : [ 'vivado': 'xilinx/SDx/2017.4_04112018', - 'vcs': 'vcs-mx/L-2016.06-1', + 'vcs': 'synopsys/vcs-mx/M-2017.03-SP2-11', 'questa': 'questa/10.6b', 'ies': 'incisive/15.20.063' ], '2018.2' : [ 'vivado': 'xilinx/SDx/2018.2_06142018', - 'vcs': 'vcs-mx/N-2017.12-SP1-1', + 'vcs': 'synopsys/vcs-mx/N-2017.12-SP2', 'questa': 'questa/10.6c_1', 'ies': 'incisive/15.20.063' ], '2018.3' : [ 'vivado': 'xilinx/SDx/2018.3_1207', - 'vcs': 'vcs-mx/N-2017.12-SP1-1', + 'vcs': 'synopsys/vcs-mx/N-2017.12-SP2', 'questa': 'questa/10.6c_1', 'ies': 'incisive/15.20.063' ] @@ -196,7 +197,7 @@ def get_task_label(Map args=[ : ]) { } if (params.internal_simulations) { echo "internal simulation agent requested" - task_label = 'f1' + task_label = 'f1_3rd_party_sims' } echo "Label Requested: $task_label" @@ -492,7 +493,7 @@ if (test_fpga_tools) { if (test_sims) { all_tests['Run Sims'] = { stage('Run Sims') { - def cl_names = ['cl_uram_example', 'cl_dram_dma', 'cl_hello_world', 'cl_sde'] + def cl_names = ['cl_vhdl_hello_world', 'cl_uram_example', 'cl_dram_dma', 'cl_hello_world', 'cl_sde'] def simulators = ['vivado'] def sim_nodes = [:] if(params.internal_simulations) { @@ -505,6 +506,15 @@ if (test_sims) { String xilinx_version = y String cl_name = x String simulator = z + if((cl_name == 'cl_vhdl_hello_world') && (simulator == 'ies')) { + println ("Skipping Simulator: ${simulator} CL: ${cl_name}") + continue; + } + String cl_dir_name = cl_name + if(cl_name == 'cl_vhdl_hello_world') { + cl_dir_name = "cl_hello_world_vhdl" + } + String node_name = "Sim ${cl_name} ${xilinx_version} ${simulator}" String key = "test_${cl_name}__" String report_file = "test_sims_${cl_name}_${xilinx_version}.xml" @@ -525,19 +535,21 @@ if (test_sims) { sh """ set -e module purge - module load python/2.7.9 + module load python/3.7.2 + module load python/2.7.14 + module load batch module load ${vivado_module} module load ${vcs_module} module load ${questa_module} module load ${ies_module} source $WORKSPACE/hdk_setup.sh - python2.7 -m pytest -v $WORKSPACE/hdk/tests/simulation_tests/test_sims.py -k \"${key}\" --junit-xml $WORKSPACE/${report_file} --simulator ${simulator} + python2.7 -m pytest -v $WORKSPACE/hdk/tests/simulation_tests/test_sims.py -k \"${key}\" --junit-xml $WORKSPACE/${report_file} --simulator ${simulator} --batch 'TRUE' """ } else { sh """ set -e source $WORKSPACE/shared/tests/bin/setup_test_hdk_env.sh - python2.7 -m pytest -v $WORKSPACE/hdk/tests/simulation_tests/test_sims.py -k \"${key}\" --junit-xml $WORKSPACE/${report_file} --simulator ${simulator} + python2.7 -m pytest -v $WORKSPACE/hdk/tests/simulation_tests/test_sims.py -k \"${key}\" --junit-xml $WORKSPACE/${report_file} --simulator ${simulator} --batch 'FALSE' """ } } catch (exc) { @@ -545,7 +557,7 @@ if (test_sims) { throw exc } finally { run_junit(report_file) - archiveArtifacts artifacts: "hdk/cl/examples/${cl_name}/**/*.sim.log", fingerprint: true + archiveArtifacts artifacts: "hdk/cl/examples/${cl_dir_name}/**/*.sim.log", fingerprint: true } } } @@ -923,13 +935,15 @@ if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { sh """ set -e source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh - python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_find_sdaccel_examples.py --junit-xml $WORKSPACE/${report_file} + python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_find_sdaccel_examples.py --junit-xml $WORKSPACE/${report_file} --xilinxVersion ${xilinx_version} """ } catch (exc) { echo "Could not find tests. Please check the repository." throw exc } finally { run_junit(report_file) + archiveArtifacts artifacts: "${sdaccel_examples_list}.*", fingerprint: true + } // Only run the hello world test by default diff --git a/Jenkinsfile_int_sims b/Jenkinsfile_int_sims new file mode 100644 index 00000000..093164a7 --- /dev/null +++ b/Jenkinsfile_int_sims @@ -0,0 +1,1150 @@ +#!/usr/bin/env groovy + +//============================================================================= +// Pipeline parameters +//============================================================================= +properties([parameters([ + string(name: 'branch', defaultValue: ''), + booleanParam(name: 'test_markdown_links', defaultValue: false, description: 'Test markdown files and check for broken links'), + booleanParam(name: 'test_src_headers', defaultValue: false, description: 'Check copyright heaers of source files'), + booleanParam(name: 'test_fpga_tools', defaultValue: false, description: 'Test fpga-* commands on F1'), + booleanParam(name: 'test_hdk_scripts', defaultValue: false, description: 'Test the HDK setup scripts'), + booleanParam(name: 'test_sims', defaultValue: true, description: 'Run all Simulations'), + booleanParam(name: 'test_non_root_access', defaultValue: false, description: 'Test non-root access to FPGA tools'), + booleanParam(name: 'test_xdma', defaultValue: false, description: 'Test XDMA driver'), + booleanParam(name: 'test_py_bindings', defaultValue: false, description: 'Test Python Bindings'), + booleanParam(name: 'test_runtime_software', defaultValue: false, description: 'Test precompiled AFIs'), + booleanParam(name: 'test_dcp_recipes', defaultValue: false, description: 'Run DCP generation with all clock recipes and build strategies.'), + booleanParam(name: 'test_hdk_fdf', defaultValue: false, description: 'Run Full developer flow testing on cl_hello_world and cl_dram_dma'), + booleanParam(name: 'test_sdaccel_scripts', defaultValue: false, description: 'Test SDAccel setup scripts'), + booleanParam(name: 'test_all_sdaccel_examples_fdf', defaultValue: false, description: 'Run Full Developer Flow testing of all SDAccel examples. This overrides test_helloworld_sdaccel_example'), + booleanParam(name: 'test_helloworld_sdaccel_example_fdf', defaultValue: false, description: 'Run Full Developer Flow testing of the Hello World SDAccel example'), + booleanParam(name: 'debug_dcp_gen', defaultValue: false, description: 'Only run FDF on cl_hello_world. Overrides test_*.'), + booleanParam(name: 'debug_fdf_uram', defaultValue: false, description: 'Debug the FDF for cl_uram_example.'), + booleanParam(name: 'fdf_ddr_comb', defaultValue: false, description: 'run FDF for cl_dram_dma ddr combinations.'), + booleanParam(name: 'disable_runtime_tests', defaultValue: false, description: 'Option to disable runtime tests.'), + booleanParam(name: 'use_test_ami', defaultValue: false, description: 'This option asks for the test AMI from Jenkins'), + booleanParam(name: 'internal_simulations', defaultValue: true, description: 'This option asks for default agent from Jenkins') +])]) + +//============================================================================= +// Configuration +//============================================================================= +boolean test_markdown_links = params.get('test_markdown_links') +boolean test_src_headers = params.get('test_src_headers') +boolean test_hdk_scripts = params.get('test_hdk_scripts') +boolean test_fpga_tools = params.get('test_fpga_tools') +boolean test_sims = params.get('test_sims') +boolean test_non_root_access = params.get('test_non_root_access') +boolean test_xdma = params.get('test_xdma') +boolean test_py_bindings = params.get('test_py_bindings') +boolean test_runtime_software = params.get('test_runtime_software') +boolean test_dcp_recipes = params.get('test_dcp_recipes') +boolean test_hdk_fdf = params.get('test_hdk_fdf') +boolean test_sdaccel_scripts = params.get('test_sdaccel_scripts') +boolean test_all_sdaccel_examples_fdf = params.get('test_all_sdaccel_examples_fdf') +boolean test_helloworld_sdaccel_example_fdf = params.get('test_helloworld_sdaccel_example_fdf') +boolean disable_runtime_tests = params.get('disable_runtime_tests') + +def runtime_sw_cl_names = ['cl_dram_dma', 'cl_hello_world'] +def dcp_recipe_cl_names = ['cl_dram_dma', 'cl_hello_world'] +def dcp_recipe_scenarios = [ + // Default values are tested in FDF: A0-B0-C0-DEFAULT + // Fastest clock speeds are: A1-B2-C0 + // Test each clock recipe with the BASIC strategy + // Test all strategies with highest clock speeds + 'A1-B1-C1-BASIC', + 'A1-B2-C0-BASIC', + 'A2-B3-C2-BASIC', + 'A1-B4-C3-BASIC', + 'A1-B5-C0-BASIC', + 'A1-B2-C0-DEFAULT', + 'A1-B2-C0-EXPLORE', + 'A1-B2-C0-TIMING', + 'A1-B2-C0-TIMING', + 'A1-B2-C0-CONGESTION', + ] +def fdf_test_names = [ + 'cl_dram_dma[A1-B0-C0-DEFAULT]', + 'cl_hello_world[A0-B0-C0-DEFAULT]', + 'cl_hello_world_vhdl', + 'cl_uram_example[2]', + 'cl_uram_example[3]', + 'cl_uram_example[4]' + ] + +boolean debug_dcp_gen = params.get('debug_dcp_gen') +if (debug_dcp_gen) { + fdf_test_names = ['cl_hello_world[A0-B0-C0-DEFAULT]'] + test_markdown_links = false + test_sims = false + test_runtime_software = false + test_sdaccel_scripts = false +} + +boolean debug_fdf_uram = params.get('debug_fdf_uram') +if (debug_fdf_uram) { + fdf_test_names = ['cl_uram_example[2]', 'cl_uram_example[3]', 'cl_uram_example[4]'] + test_markdown_links = false + test_sims = false + test_runtime_software = false + test_sdaccel_scripts = false +} + +boolean fdf_ddr_comb = params.get('fdf_ddr_comb') +if(fdf_ddr_comb) { + fdf_test_names = ['cl_dram_dma[A0-B0-C0-DEFAULT-111]', 'cl_dram_dma[A0-B0-C0-DEFAULT-110]', 'cl_dram_dma[A0-B0-C0-DEFAULT-101]','cl_dram_dma[A0-B0-C0-DEFAULT-100]','cl_dram_dma[A0-B0-C0-DEFAULT-011]','cl_dram_dma[A0-B0-C0-DEFAULT-010]','cl_dram_dma[A0-B0-C0-DEFAULT-001]','cl_dram_dma[A0-B0-C0-DEFAULT-000]'] + test_markdown_links = false + test_sims = false + test_runtime_software = false + test_sdaccel_scripts = false +} + +//============================================================================= +// Globals +//============================================================================= + +// Map that contains stages of tests +def all_tests = [:] + +// Task to Label map +task_label = [ + 'create_afi': 't2.l_50', + 'simulation': 'z1d.l', + 'dcp_gen': 'z1d.2xl', + 'runtime': 'f1.2xl', + 'runtime_all_slots': 'f1.16xl', + 'source_scripts': 'c4.xl', + 'md_links': 'c4.xl', + 'find_tests': 't2.l_50', + 'sdaccel_builds': 'z1d.2xl' +] + +// Put the latest version last +def xilinx_versions = [ '2017.4', '2018.2', '2018.3' ] + +// We want the default to be the latest. +def default_xilinx_version = xilinx_versions.last() + +def dsa_map = [ + '2017.4' : [ 'DYNAMIC_5_0' : 'dyn'], + '2018.2' : [ 'DYNAMIC_5_0' : 'dyn'], + '2018.3' : [ 'DYNAMIC_5_0' : 'dyn'] +] + +def sdaccel_example_default_map = [ + '2017.4' : [ + 'Hello_World_1ddr': 'SDAccel/examples/xilinx/getting_started/host/helloworld_ocl', + 'Gmem_2Banks_2ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/gmem_2banks_ocl', + 'kernel_3ddr_bandwidth_4ddr': 'SDAccel/examples/aws/kernel_3ddr_bandwidth', + 'Kernel_Global_Bw_4ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/kernel_global_bandwidth', + 'RTL_Vadd_Debug': 'SDAccel/examples/xilinx/getting_started/rtl_kernel/rtl_vadd_hw_debug' + ], + '2018.2' : [ + 'Hello_World_1ddr': 'SDAccel/examples/xilinx/getting_started/host/helloworld_ocl', + 'Gmem_2Banks_2ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/gmem_2banks_ocl', + 'kernel_3ddr_bandwidth_4ddr': 'SDAccel/examples/aws/kernel_3ddr_bandwidth', + 'Kernel_Global_Bw_4ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/kernel_global_bandwidth', + 'RTL_Vadd_Debug': 'SDAccel/examples/xilinx/getting_started/rtl_kernel/rtl_vadd_hw_debug' + ], + '2018.3' : [ + 'Hello_World_1ddr': 'SDAccel/examples/xilinx/getting_started/host/helloworld_ocl', + 'Gmem_2Banks_2ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/gmem_2banks_ocl', + 'Kernel_Global_Bw_4ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/kernel_global_bandwidth', + 'RTL_Vadd_Debug': 'SDAccel/examples/xilinx/getting_started/rtl_kernel/rtl_vadd_hw_debug' + ] +] + +def simulator_tool_default_map = [ + '2017.4' : [ + 'vivado': 'xilinx/SDx/2017.4_04112018', + 'vcs': 'synopsys/vcs-mx/M-2017.03-SP2-11', + 'questa': 'questa/10.6b', + 'ies': 'incisive/15.20.063' + ], + '2018.2' : [ + 'vivado': 'xilinx/SDx/2018.2_06142018', + 'vcs': 'synopsys/vcs-mx/N-2017.12-SP2', + 'questa': 'questa/10.6c_1', + 'ies': 'incisive/15.20.063' + ], + '2018.3' : [ + 'vivado': 'xilinx/SDx/2018.3_1207', + 'vcs': 'synopsys/vcs-mx/N-2017.12-SP2', + 'questa': 'questa/10.6c_1', + 'ies': 'incisive/15.20.063' + ] +] + + +// Get serializable entry set +@NonCPS def entrySet(m) {m.collect {k, v -> [key: k, value: v]}} + +@NonCPS +def is_public_repo() { + echo "Change URL: ${env.CHANGE_URL}" + return (env.CHANGE_URL =~ /^(\S+)?aws-fpga\/pull\/(\d+)$/) +} + +def get_task_label(Map args=[ : ]) { + String task_label = args.xilinx_version + '_' + task_label[args.task] + //boolean use_test_ami = params.get('use_test_ami') + + if (params.use_test_ami) { + echo "Test AMI Requested" + task_label = task_label + '_test' + } + if (params.internal_simulations) { + echo "internal simulation agent requested" + task_label = 'f1_3rd_party_sims' + } + + echo "Label Requested: $task_label" + return task_label +} + +def abort_previous_running_builds() { + def hi = Hudson.instance + def pname = env.JOB_NAME.split('/')[0] + + hi.getItem(pname).getItem(env.JOB_BASE_NAME).getBuilds().each{ build -> + def executor = build.getExecutor() + + if (build.number != currentBuild.number && build.number < currentBuild.number && executor != null) { + executor.interrupt( + Result.ABORTED, + new CauseOfInterruption.UserInterruption("Aborted by #${currentBuild.number}")) + println("Aborted previous running build #${build.number}") + } else { + println("Build is not running or is current build, not aborting - #${build.number}") + } + } +} + +// Wait for input if we are running on a public repo to avoid malicious PRS +if (is_public_repo()) { + input "Running on a public repository, do you want to proceed with running the tests?" +} else { + echo "Running on a private repository" +} + + +//Abort previous builds on PR when we push new commits +// env.CHANGE_ID is only available on PR's and not on branch builds +if (env.CHANGE_ID) { + abort_previous_running_builds() +} + + +def run_junit(String report_file) { + + if (fileExists(report_file)) { + junit healthScaleFactor: 10.0, testResults: report_file + } else { + echo "Pytest wasn't run for stage. Report file not generated: ${report_file}" + } +} + +def git_cleanup() { + sh """ + set -e + sudo git reset --hard + sudo git clean -fdx + """ +} + +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// +// Test Functions///////////////////////////////////// +////////////////////////////////////////////////////// +////////////////////////////////////////////////////// + +def test_run_py_bindings() { + echo "Test Python Bindings" + checkout scm + + String test = "sdk/tests/test_py_bindings.py" + String report_file = "test_py_bindings.xml" + + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_sdk_env_al2.sh "py_bindings" + python2.7 -m pytest -v $WORKSPACE/${test} --junit-xml $WORKSPACE/${report_file} + """ + } catch (exc) { + echo "${test} failed." + input message: "Python bindings test failed. Click Proceed or Abort when you are done debugging on the instance." + throw exc + } finally { + run_junit(report_file) + } +} + +def test_doc_markdown_links() { + String report_file = 'test_md_links.xml' + checkout scm + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_env.sh + python2.7 -m pytest -v $WORKSPACE/shared/tests/test_md_links.py --junit-xml $WORKSPACE/${report_file} + """ + } finally { + run_junit(report_file) + } +} + +def test_doc_src_headers() { + String report_file = 'test_check_src_headers.xml' + checkout scm + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_env.sh + python2.7 -m pytest -v $WORKSPACE/shared/tests/test_check_src_headers.py --junit-xml $WORKSPACE/${report_file} + """ + } finally { + run_junit(report_file) + } +} + +def test_run_hdk_scripts() { + checkout scm + String report_file = 'test_hdk_scripts.xml' + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_env.sh + python2.7 -m pytest -v $WORKSPACE/hdk/tests/test_hdk_scripts.py --junit-xml $WORKSPACE/${report_file} + """ + } finally { + run_junit(report_file) + } +} + +def test_fpga_1_slot() { + String report_file_tools = 'test_fpga_tools.xml' + String report_file_sdk = 'test_fpga_sdk.xml' + String report_file_combined = 'test_fpga_*.xml' + checkout scm + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh + python2.7 -m pytest -v $WORKSPACE/sdk/tests/test_fpga_tools.py --junit-xml $WORKSPACE/${report_file_tools} + sudo -E sh -c 'source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh && python2.7 -m pytest -v $WORKSPACE/sdk/tests/test_sdk.py --junit-xml $WORKSPACE/${report_file_sdk}' + sudo -E chmod 666 $WORKSPACE/${report_file_sdk} + """ + } + catch (exception) { + echo "Test FPGA Tools 1 Slot failed" + input message: "1 slot FPGA Tools test failed. Click Proceed or Abort when you are done debugging on the instance." + throw exception + } + finally { + if (fileExists(report_file_tools)) { + junit healthScaleFactor: 10.0, testResults: report_file_combined + } else { + echo "Pytest wasn't run for stage. Report file not generated: ${report_file_combined}" + } + } +} + +def test_fpga_all_slots() { + String report_file_tools = 'test_fpga_tools_all_slots.xml' + String report_file_sdk = 'test_fpga_sdk_all_slots.xml' + String report_file_combined = 'test_fpga_*_all_slots.xml' + checkout scm + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh + python2.7 -m pytest -v $WORKSPACE/sdk/tests/test_fpga_tools.py --junit-xml $WORKSPACE/${report_file_tools} + sudo -E sh -c 'source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh && python2.7 -m pytest -v $WORKSPACE/sdk/tests/test_sdk.py --junit-xml $WORKSPACE/${report_file_sdk}' + sudo -E chmod 666 $WORKSPACE/${report_file_sdk} + """ + } + catch (exception) { + echo "Test FPGA Tools All Slots failed" + input message: "1 slot FPGA Tools test failed. Click Proceed or Abort when you are done debugging on the instance." + throw exception + } + finally { + if (fileExists(report_file_tools)) { + junit healthScaleFactor: 10.0, testResults: report_file_combined + } else { + echo "Pytest wasn't run for stage. Report file not generated: ${report_file_combined}" + } + } +} + + +def test_run_non_root_access() { + echo "Test non-root access to FPGA tools" + checkout scm + + String test = "sdk/tests/test_non_root_access.py" + String report_file = "test_non_root_access.xml" + + try { + sh """ + set -e + export AWS_FPGA_ALLOW_NON_ROOT=y + export AWS_FPGA_SDK_OVERRIDE_GROUP=y + source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh + newgrp fpgauser + export SDK_DIR="${WORKSPACE}/sdk" + source $WORKSPACE/shared/tests/bin/setup_test_env.sh + python2.7 -m pytest -v $WORKSPACE/${test} --junit-xml $WORKSPACE/${report_file} + """ + } catch (exc) { + input message: "Non-root access test failed. Click Proceed or Abort when you are done debugging on the instance." + throw exc + } finally { + run_junit(report_file) + } +} + +def test_xdma_driver() { + echo "Test XDMA Driver" + checkout scm + + String test = "sdk/tests/test_xdma.py" + String report_file = "test_xdma.xml" + + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh + python2.7 -m pytest -v ${test} --junit-xml $WORKSPACE/${report_file} + """ + } catch (exc) { + echo "${test} failed." + junit healthScaleFactor: 10.0, testResults: report_file + input message: "XDMA driver test failed. Click Proceed or Abort when you are done debugging on the instance." + throw exc + } finally { + run_junit(report_file) + } +} + +//============================================================================= +// Shared Tests +//============================================================================= + + +if (test_markdown_links || test_src_headers) { + all_tests['Documentation Tests'] = { + node(get_task_label(task: 'md_links', xilinx_version: default_xilinx_version)) { + if (test_markdown_links) { + stage('Test Markdown Links') { + test_doc_markdown_links() + } + } + + if (test_src_headers) { + stage('Test Source Headers') { + test_doc_src_headers() + } + } + } + } +} + +//============================================================================= +// HDK Tests +//============================================================================= + +if (test_hdk_scripts) { + all_tests['Test HDK Scripts'] = { + stage('Test HDK Scripts') { + node(get_task_label(task: 'source_scripts', xilinx_version: default_xilinx_version)) { + test_run_hdk_scripts() + } + } + } +} + +//============================================================================= +// FPGA Tool Tests +//============================================================================= +if (test_fpga_tools) { + all_tests['Test FPGA Tools 1 Slot'] = { + stage('Test FPGA Tools 1 Slot') { + node(get_task_label(task: 'runtime', xilinx_version: default_xilinx_version)) { + test_fpga_1_slot() + } + } + } + all_tests['Test FPGA Tools All Slots'] = { + stage('Test FPGA Tools All Slots') { + node(get_task_label(task: 'runtime_all_slots', xilinx_version: default_xilinx_version)) { + test_fpga_all_slots() + } + } + } +} + +//============================================================================= +// Simulations +//============================================================================= +if (test_sims) { + all_tests['Run Sims'] = { + stage('Run Sims') { + def cl_names = ['cl_vhdl_hello_world', 'cl_uram_example', 'cl_dram_dma', 'cl_hello_world', 'cl_sde'] + def simulators = ['vivado'] + def sim_nodes = [:] + if(params.internal_simulations) { + simulators = ['vcs', 'ies', 'questa', 'vivado'] + } + + for (x in cl_names) { + for (y in xilinx_versions) { + for (z in simulators) { + String xilinx_version = y + String cl_name = x + String simulator = z + if((cl_name == 'cl_vhdl_hello_world') && (simulator == 'ies')) { + println ("Skipping Simulator: ${simulator} CL: ${cl_name}") + continue; + } + String cl_dir_name = cl_name + if(cl_name == 'cl_vhdl_hello_world') { + cl_dir_name = "cl_hello_world_vhdl" + } + String node_name = "Sim ${cl_name} ${xilinx_version} ${simulator}" + String key = "test_${cl_name}__" + String report_file = "test_sims_${cl_name}_${xilinx_version}.xml" + def tool_module_map = simulator_tool_default_map.get(xilinx_version) + String vcs_module = tool_module_map.get('vcs') + String questa_module = tool_module_map.get('questa') + String ies_module = tool_module_map.get('ies') + String vivado_module = tool_module_map.get('vivado') + + if(params.internal_simulations) { + report_file = "test_sims_${cl_name}_${xilinx_version}_${simulator}.xml" + } + sim_nodes[node_name] = { + node(get_task_label(task: 'simulation', xilinx_version: xilinx_version)) { + checkout scm + try { + if(params.internal_simulations) { + sh """ + set -e + module purge + module load python/3.7.2 + module load python/2.7.14 + module load batch + module load ${vivado_module} + module load ${vcs_module} + module load ${questa_module} + module load ${ies_module} + source $WORKSPACE/hdk_setup.sh + python2.7 -m pytest -v $WORKSPACE/hdk/tests/simulation_tests/test_sims.py -k \"${key}\" --junit-xml $WORKSPACE/${report_file} --simulator ${simulator} --batch 'TRUE' + """ + } else { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_hdk_env.sh + python2.7 -m pytest -v $WORKSPACE/hdk/tests/simulation_tests/test_sims.py -k \"${key}\" --junit-xml $WORKSPACE/${report_file} --simulator ${simulator} --batch 'FALSE' + """ + } + } catch (exc) { + echo "${node_name} failed" + throw exc + } finally { + run_junit(report_file) + archiveArtifacts artifacts: "hdk/cl/examples/${cl_dir_name}/**/*.sim.log", fingerprint: true + } + } + } + } + } + } + + parallel sim_nodes + } + } +} + +//============================================================================= +// Non root access Test +//============================================================================= +if (test_non_root_access) { + all_tests['Test non-root access to FPGA tools'] = { + stage('Test non-root access to FPGA tools') { + node(get_task_label(task: 'runtime', xilinx_version: default_xilinx_version)) { + test_run_non_root_access() + } + } + } +} + +//============================================================================= +// Driver Tests +//============================================================================= +if (test_xdma) { + all_tests['Test XDMA Driver'] = { + stage('Test XDMA Driver') { + node(get_task_label(task: 'runtime', xilinx_version: default_xilinx_version)) { + test_xdma_driver() + } + } + } +} + +//============================================================================= +// Python Binding Test +//============================================================================= +if (test_py_bindings) { + all_tests['Test Python Bindings'] = { + stage('Test Python Bindings') { + node('f1.2xl_runtime_test_al2') { + test_run_py_bindings() + } + } + } +} + +//============================================================================= +// Precompiled Runtime Tests +//============================================================================= +if(disable_runtime_tests) { + echo "Runtime tests disabled. Not running Test Runtime Software stages" +} else { + if (test_runtime_software) { + all_tests['Test Runtime Software'] = { + stage('Test Runtime Software') { + def nodes = [:] + def node_types = ['runtime', 'runtime_all_slots'] + for (n in node_types) { + node_type = n + for (x in runtime_sw_cl_names) { + String cl_name = x + String node_name = "Undefined" + switch (node_type) { + case "runtime": + node_name = "Test Runtime Software ${default_xilinx_version} f1.2xl ${cl_name}" + break; + case "runtime_all_slots": + node_name = "Test Runtime Software ${default_xilinx_version} f1.16xl ${cl_name}" + break; + } + String node_label = get_task_label(task: node_type, xilinx_version: default_xilinx_version) + nodes[node_name] = { + node(node_label) { + String test = "hdk/tests/test_load_afi.py::TestLoadAfi::test_precompiled_${cl_name}" + String report_file = "test_runtime_software_${cl_name}.xml" + checkout scm + + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh + python2.7 -m pytest -v ${test} --junit-xml $WORKSPACE/${report_file} + """ + } finally { + run_junit(report_file) + } + } + } + } + } + parallel nodes + } + } + } +} + +//============================================================================= +// DCP Recipe Tests +//============================================================================= +if (test_dcp_recipes) { + all_tests['Test DCP Recipes'] = { + stage('Test DCP Recipes') { + def nodes = [:] + for (version in xilinx_versions) { + String xilinx_version = version + + for (cl in dcp_recipe_cl_names) { + String cl_name = cl + for (s in dcp_recipe_scenarios) { + String recipe_scenario = s + String node_name = "Test DCP Recipe ${cl_name}[${xilinx_version}-${recipe_scenario}]" + nodes[node_name] = { + node(get_task_label(task: 'dcp_gen', xilinx_version: xilinx_version)) { + String test_name = "test_${cl_name}[${xilinx_version}-${recipe_scenario}]" + String report_file = "test_dcp_recipe_${cl_name}[${xilinx_version}-${recipe_scenario}].xml" + String build_dir = "hdk/cl/examples/${cl_name}/build" + checkout scm + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_hdk_env.sh + python2.7 -m pytest -s -v hdk/tests/test_gen_dcp.py::TestGenDcp::${test_name} --junit-xml $WORKSPACE/${report_file} --xilinxVersion ${xilinx_version} + """ + } catch(exc) { + echo "${test_name} DCP generation failed: archiving results" + archiveArtifacts artifacts: "${build_dir}/**", fingerprint: true + throw exc + } finally { + run_junit(report_file) + } + } + } + } + } + } + + parallel nodes + } + } +} + +//============================================================================= +// HDK Full Developer Flow Tests +//============================================================================= +if (test_hdk_fdf) { + // Top level stage for FDF + // Each CL will have its own parallel FDF stage under this one. + all_tests['HDK_FDF'] = { + stage('HDK FDF') { + def fdf_stages = [:] + for (version in xilinx_versions) { + String xilinx_version = version + + for (x in fdf_test_names) { + String fdf_test_name = x + String cl_name = "" + + if (fdf_test_name.contains('[')) { + def split_test = fdf_test_name.split(/\[/) + def test_base_name = split_test[0] + def test_args = split_test[1] + + fdf_test_name = "$test_base_name[$xilinx_version-$test_args" + cl_name = test_base_name + } + + String fdf_stage_name = "FDF ${xilinx_version} ${fdf_test_name}" + fdf_stages[fdf_stage_name] = { + stage(fdf_stage_name) { + echo "Generate DCP for ${xilinx_version} ${fdf_test_name}" + String build_dir = "hdk/cl/examples/${cl_name}/build" + String dcp_stash_name = "dcp_tarball_${fdf_test_name}_${xilinx_version}".replaceAll(/[\[\]]/, "_") + String dcp_stash_dir = "${build_dir}/checkpoints/to_aws" + String afi_stash_name = "afi_${fdf_test_name}_${xilinx_version}".replaceAll(/[\[\]]/, "_") + String afi_stash_dir = "${build_dir}/create_afi" + echo "dcp_stash_name=${dcp_stash_name}" + echo "afi_stash_name=$afi_stash_name}" + node(get_task_label(task: 'dcp_gen', xilinx_version: xilinx_version)) { + String test = "hdk/tests/test_gen_dcp.py::TestGenDcp::test_${fdf_test_name}" + String report_file = "test_dcp_${fdf_test_name}_${xilinx_version}.xml" + checkout scm + // Clean out the to_aws directory to make sure there are no artifacts left over from a previous build + try { + sh """ + rm -rf ${dcp_stash_dir} + """ + } catch(exc) { + // Ignore any errors + echo "Failed to clean ${dcp_stash_dir}" + } + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_hdk_env.sh + python2.7 -m pytest -v ${test} --junit-xml $WORKSPACE/${report_file} --xilinxVersion ${xilinx_version} + """ + } catch (exc) { + echo "${fdf_test_name} DCP generation failed: archiving results" + archiveArtifacts artifacts: "${build_dir}/**", fingerprint: true + throw exc + } finally { + run_junit(report_file) + } + try { + stash name: dcp_stash_name, includes: "${dcp_stash_dir}/**" + } catch (exc) { + echo "stash ${dcp_stash_name} failed:\n${exc}" + } + } + node(get_task_label(task: 'create_afi', xilinx_version: xilinx_version)) { + echo "Generate AFI for ${xilinx_version} ${fdf_test_name}" + checkout scm + String test = "hdk/tests/test_create_afi.py::TestCreateAfi::test_${fdf_test_name}" + String report_file = "test_create_afi_${fdf_test_name}_${xilinx_version}.xml" + // Clean out the stash directories to make sure there are no artifacts left over from a previous build + try { + sh """ + rm -rf ${dcp_stash_dir} + """ + } catch(exc) { + // Ignore any errors + echo "Failed to clean ${dcp_stash_dir}" + } + try { + sh """ + rm -rf ${afi_stash_dir} + """ + } catch(exc) { + // Ignore any errors + echo "Failed to clean ${afi_stash_dir}" + } + try { + unstash name: dcp_stash_name + } catch (exc) { + echo "unstash ${dcp_stash_name} failed:\n${exc}" + //throw exc + } + try { + // There is a Xilinx bug that causes the following error during hdk_setup.sh if multiple + // processes are doing it at the same time: + // WARNING: [Common 17-1221] Tcl app 'xsim' is out of date for this release. Please run tclapp::reset_tclstore and reinstall the app. + // ERROR: [Common 17-685] Unable to load Tcl app xilinx::xsim + // ERROR: [Common 17-69] Command failed: ERROR: [Common 17-685] Unable to load Tcl app xilinx::xsim + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_env.sh + python2.7 -m pytest -v ${test} --junit-xml $WORKSPACE/${report_file} --xilinxVersion ${xilinx_version} + """ + } catch (exc) { + echo "${fdf_test_name} AFI generation failed: archiving results" + archiveArtifacts artifacts: "${build_dir}/to_aws/**", fingerprint: true + throw exc + } finally { + run_junit(report_file) + } + try { + stash name: afi_stash_name, includes: "${afi_stash_dir}/**" + } catch (exc) { + echo "stash ${afi_stash_name} failed:\n${exc}" + } + } + + if(disable_runtime_tests) { + echo "Runtime tests disabled. Not running runtime ${fdf_test_name}" + } else { + node(get_task_label(task: 'runtime', xilinx_version: xilinx_version)) { + String test = "hdk/tests/test_load_afi.py::TestLoadAfi::test_${fdf_test_name}" + String report_file = "test_load_afi_${fdf_test_name}_${xilinx_version}.xml" + checkout scm + echo "Test AFI for ${xilinx_version} ${fdf_test_name} on F1 instance" + // Clean out the stash directories to make sure there are no artifacts left over from a previous build + try { + sh """ + rm -rf ${afi_stash_dir} + """ + } catch(exc) { + // Ignore any errors + echo "Failed to clean ${afi_stash_dir}" + } + try { + unstash name: afi_stash_name + } catch (exc) { + echo "unstash ${afi_stash_name} failed:\n${exc}" + } + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh + python2.7 -m pytest -v ${test} --junit-xml $WORKSPACE/${report_file} --xilinxVersion ${xilinx_version} + """ + } finally { + run_junit(report_file) + } + } + } //else + } // stage( + } + } // for (x in fdf_test_names) + + } // for (xilinx_version in xilinx_versions) { + + parallel fdf_stages + } + } +} + +//============================================================================= +// SDAccel Tests +//============================================================================= + +if (test_sdaccel_scripts) { + all_tests['Test SDAccel Scripts'] = { + stage('Test SDAccel Scripts') { + def nodes = [:] + for (def xilinx_version in xilinx_versions) { + + String node_label = get_task_label(task: 'source_scripts', xilinx_version: xilinx_version) + String node_name = "Test SDAccel Scripts ${xilinx_version}" + nodes[node_name] = { + node(node_label) { + String report_file = "test_sdaccel_scripts_${xilinx_version}.xml" + checkout scm + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_env.sh + python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_sdaccel_scripts.py --junit-xml $WORKSPACE/${report_file} + """ + } finally { + run_junit(report_file) + } + } + } + } + parallel nodes + } + } +} + +if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { + all_tests['Run SDAccel Tests'] = { + String sdaccel_examples_list = 'sdaccel_examples_list.json' + + def sdaccel_all_version_stages = [:] + + for (def version in xilinx_versions) { + + String xilinx_version = version + String sdaccel_base_stage_name = "SDx FDF $xilinx_version" + String sdaccel_find_stage_name = "SDx Find tests $xilinx_version" + + sdaccel_all_version_stages[sdaccel_base_stage_name] = { + stage (sdaccel_find_stage_name) { + + node(get_task_label(task: 'find_tests', xilinx_version: xilinx_version)) { + + checkout scm + String report_file = "test_find_sdaccel_examples_${xilinx_version}.xml" + + try { + sh """ + rm -rf ${sdaccel_examples_list} + """ + } catch(error) { + // Ignore any errors + echo "Failed to clean ${sdaccel_examples_list}" + } + + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh + python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_find_sdaccel_examples.py --junit-xml $WORKSPACE/${report_file} + """ + } catch (exc) { + echo "Could not find tests. Please check the repository." + throw exc + } finally { + run_junit(report_file) + } + + // Only run the hello world test by default + //def example_map = [ 'Hello_World': 'SDAccel/examples/xilinx/getting_started/host/helloworld_ocl' ] + def example_map = sdaccel_example_default_map.get(xilinx_version) + + // Run all examples when parameter set + if (test_all_sdaccel_examples_fdf) { + example_map = readJSON file: sdaccel_examples_list + } + + def sdaccel_build_stages = [:] + + for ( def e in entrySet(example_map) ) { + + String test_key = e.key + def dsa_map_for_version = dsa_map.get(xilinx_version) + + // dsa = [ 4DDR: 4ddr ] + for ( def dsa in entrySet(dsa_map_for_version) ) { + + String build_name = "SDx ${e.key}_${dsa.value}_${xilinx_version}" + String example_path = e.value + + String dsa_name = dsa.key + String dsa_rte_name = dsa.value + + String sw_emu_stage_name = "SDx SW_EMU ${build_name}" + String hw_emu_stage_name = "SDx HW_EMU ${build_name}" + String hw_stage_name = "SDx HW ${build_name}" + String create_afi_stage_name = "SDx AFI ${build_name}" + String run_example_stage_name = "SDx RUN ${build_name}" + + String sw_emu_report_file = "sdaccel_sw_emu_${e.key}_${dsa.value}_${xilinx_version}.xml" + String hw_emu_report_file = "sdaccel_hw_emu_${e.key}_${dsa.value}_${xilinx_version}.xml" + String hw_report_file = "sdaccel_hw_${e.key}_${dsa.value}_${xilinx_version}.xml" + String create_afi_report_file = "sdaccel_create_afi_${e.key}_${dsa.value}_${xilinx_version}.xml" + String run_example_report_file = "sdaccel_run_${e.key}_${dsa.value}_${xilinx_version}.xml" + + String description_file = "${example_path}/description.json" + def description_json = ["targets":["hw","hw_emu","sw_emu"]] + + try { + description_json = readJSON file: description_file + } + catch (exc) { + echo "Could not read the file: ${description_file}" + throw exc + } + + boolean test_sw_emu_supported = true + + if(description_json["targets"]) { + if(description_json["targets"].contains("sw_emu")) { + test_sw_emu_supported = true + echo "Description file ${description_file} has target sw_emu" + } else { + test_sw_emu_supported = false + echo "Description file ${description_file} does not have target sw_emu" + } + } else { + echo "Description json did not have a 'target' key" + } + + sdaccel_build_stages[build_name] = { + if(test_sw_emu_supported) { + stage(sw_emu_stage_name) { + node(get_task_label(task: 'sdaccel_builds', xilinx_version: xilinx_version)) { + checkout scm + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh + export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} + python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_sw_emu --examplePath ${example_path} --junit-xml $WORKSPACE/${sw_emu_report_file} --timeout=14400 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} + """ + } catch (error) { + echo "${sw_emu_stage_name} SW EMU Build generation failed" + archiveArtifacts artifacts: "${example_path}/**", fingerprint: true + throw error + } finally { + run_junit(sw_emu_report_file) + git_cleanup() + } + } + } + } + + stage(hw_emu_stage_name) { + node(get_task_label(task: 'sdaccel_builds', xilinx_version: xilinx_version)) { + checkout scm + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh + export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} + python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_hw_emu --examplePath ${example_path} --junit-xml $WORKSPACE/${hw_emu_report_file} --timeout=21600 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} + """ + } catch (error) { + echo "${hw_emu_stage_name} HW EMU Build generation failed" + archiveArtifacts artifacts: "${example_path}/**", fingerprint: true + throw error + } finally { + run_junit(hw_emu_report_file) + git_cleanup() + } + } + } + + stage(hw_stage_name) { + node(get_task_label(task: 'sdaccel_builds', xilinx_version: xilinx_version)) { + checkout scm + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh + export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} + python2.7 -m pytest -s -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_hw_build --examplePath ${example_path} --junit-xml $WORKSPACE/${hw_report_file} --timeout=36000 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} + """ + } catch (error) { + echo "${hw_stage_name} HW Build generation failed" + archiveArtifacts artifacts: "${example_path}/**", fingerprint: true + throw error + } finally { + run_junit(hw_report_file) + git_cleanup() + } + } + } + + stage(create_afi_stage_name) { + node(get_task_label(task: 'create_afi', xilinx_version: xilinx_version)) { + + checkout scm + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh + export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} + python2.7 -m pytest -s -v $WORKSPACE/SDAccel/tests/test_create_sdaccel_afi.py::TestCreateSDAccelAfi::test_create_sdaccel_afi --examplePath ${example_path} --junit-xml $WORKSPACE/${create_afi_report_file} --timeout=18000 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} + """ + } catch (error) { + echo "${create_afi_stage_name} Create AFI failed" + archiveArtifacts artifacts: "${example_path}/**", fingerprint: true + throw error + } finally { + + String to_aws_dir = "${example_path}/to_aws" + + if (fileExists(to_aws_dir)) { + sh "rm -rf ${to_aws_dir}" + } + run_junit(create_afi_report_file) + git_cleanup() + } + } + } + + stage(run_example_stage_name) { + + if(disable_runtime_tests) { + echo "Runtime tests disabled. Not running ${run_example_stage_name}" + } else { + node(get_task_label(task: 'runtime', xilinx_version: xilinx_version)) { + + checkout scm + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_runtime_sdaccel_env.sh + export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} + python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_run_sdaccel_example.py::TestRunSDAccelExample::test_run_sdaccel_example --examplePath ${example_path} --junit-xml $WORKSPACE/${run_example_report_file} --timeout=14400 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} + """ + } catch (error) { + echo "${run_example_stage_name} Runtime example failed" + archiveArtifacts artifacts: "${example_path}/**", fingerprint: true + input message: "SDAccel Runtime test failed. Click Proceed or Abort when you are done debugging on the instance." + throw error + } finally { + run_junit(run_example_report_file) + git_cleanup() + } + } + } //else + + } + + } // sdaccel_build_stages[ e.key ] + + } //for ( def dsa in entrySet(dsa_map_for_version) ) { + } // for ( e in list_map ) + + parallel sdaccel_build_stages + } + } + } + } //for (def xilinx_version in xilinx_versions) { + parallel sdaccel_all_version_stages + } +} + +//============================================================================= +// SDK Tests +//============================================================================= + + +// Run the tests here +parallel all_tests diff --git a/README.md b/README.md index e6e95ea9..f1cc5c25 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ The AWS EC2 FPGA Development Kit is provided by AWS to support development and r | Runtime Environment | Hardware Interface | Host Code Language | FPGA Tools | | --------|---------|---------|-------| -| [C/C++ Software Defined Accelerator Development](SDAccel/README.md) | OpenCL APIs, [XOCL Driver](./sdk/linux_kernel_drivers/xocl), [HAL](SDAccel/userspace/src2) | C/C++ | [SDK](./sdk), SDx | +| [C/C++ Software Defined Accelerator Development](SDAccel/README.md) | OpenCL APIs, [XOCL Driver](./sdk/linux_kernel_drivers/xocl), [HAL](SDAccel/userspace/src) | C/C++ | [SDK](./sdk), SDx | | [Hardware Accelerator Development](hdk/README.md) | [XDMA Driver](sdk/linux_kernel_drivers/xdma/README.md), [peek/poke](sdk/userspace/README.md) | C/C++ | [SDK](./sdk), Vivado | | [IP Integrator or High Level Synthesis (HLx)](hdk/docs/IPI_GUI_Vivado_Setup.md) | [XDMA Driver](sdk/linux_kernel_drivers/xdma/README.md), [peek/poke](sdk/userspace/README.md) | C/C++ | [SDK](./sdk), Vivado | diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 2f82e873..0fdff1a3 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -26,8 +26,30 @@ * 1 DDR controller implemented in the SH (always available) * 3 DDR controllers implemented in the CL (configurable number of implemented controllers allowed) + +## Release 1.4.10 (See [ERRATA](./ERRATA.md) for unsupported features) +* New functionality: + * SDK now sorts the slots in DBDF order. Any scripts or integration maintainers should note that the slot order will be different from previous versions and should make any updates accordingly. + +* Bug Fixes: + * Fixes a bug in the [Automatic Traffic Generator (ATG)](./hdk/cl/examples/cl_dram_dma/design/cl_tst.sv). In SYNC mode, the ATG did not wait for write response transaction before issuing read transactions. + * Released [Xilinx runtime(XRT) version 2018.3.3.2](https://github.com/Xilinx/XRT/releases/tag/2018.3.3.2) to fix the following error: + `symbol lookup error: /opt/xilinx/xrt/lib/libxrt_aws.so: undefined symbol: uuid_parse!` + * This release fixes a bug wherein concurrent AFI load requests on two or more slots resulted in a race condition which sometimes resulted in Error: `(20) pci-device-missing` + * This release fixes a issue with coding style of logic which could infer a latch during synthesis in [sde_ps_acc module](./hdk/cl/examples/cl_sde/design/sde_ps_acc.sv) within cl_sde example + +* Package versions used for validation + + | Package | AMI 1.6.0 [2018.3] |AMI 1.5.0 [2018.2] | AMI 1.4.0 [2017.4] | + |---------|------------------------|------------------------|-----------------------| + | OS | Centos 7.6 | Centos 7.5, 7.6 | Centos 7.4 | + | kernel | 3.10.0-957.5.1.el7.x86_64 | 3.10.0-862.11.6.el7.x86_64, 3.10.0-957.1.3.el7.x86_64 | 3.10.0-693.21.1.el7.x86_64 | + | kernel-devel | 3.10.0-957.5.1.el7.x86_64 | 3.10.0-862.11.6.el7.x86_64, 3.10.0-957.1.3.el7.x86_64 | 3.10.0-693.21.1.el7.x86_64 | + | LIBSTDC++ | libstdc++-4.8.5-36.el7.x86_64 | libstdc++-4.8.5-36.el7.x86_64 | libstdc++-4.8.5-16.el7_4.2.x86_64 | + + ## Release 1.4.9 (See [ERRATA](./ERRATA.md) for unsupported features) - * New functionality: + * New functionality: * Improved AFI load times for pipelined accelerator designs. For more details please see [Amazon FPGA image (AFI) pre-fetch and caching features](./hdk/docs/load_times.md). * Ease of Use features: diff --git a/SDAccel/FAQ.md b/SDAccel/FAQ.md index adc3d021..9786c55d 100644 --- a/SDAccel/FAQ.md +++ b/SDAccel/FAQ.md @@ -63,6 +63,9 @@ A: Please make sure you executed the following commands before launching the SDx ## Q: How do I debug error: `No current synthesis run set`? A: You may have run the previous [HDK IPI examples](../hdk/docs/IPI_GUI_Vivado_Setup.md) and created a `Vivado_init.tcl` file in `~/.Xilinx/Vivado`. It is recommended to remove it before switching from hardware development flow to SDAccel. +## Q: I am getting an error: `symbol lookup error: /opt/xilinx/xrt/lib/libxrt_aws.so: undefined symbol: uuid_parse` What should I do? +A: This error occured because the XRT RPM was built without linking in a library needed for the uuid symbols. + To fix it, use the latest XRT RPM's documented in the [XRT installation document](docs/XRT_installation_instructions.md) # Additional Resources The [AWS SDAccel README]. diff --git a/SDAccel/Makefile b/SDAccel/Makefile index 436c6882..284cbe04 100644 --- a/SDAccel/Makefile +++ b/SDAccel/Makefile @@ -40,9 +40,9 @@ $(info OS is $(OS)) MODULE := ifeq ($(RELEASE_VER),2017.4) DSA := $(DSA) - SRC_DIR = src2 + SRC_DIR = src XRT_HAL_LIB = libxrt-aws.so - EXE = awssak2 + EXE = awssak MODULE = xocl ifeq ($(OS),Ubuntu) GLIBCPP_PATH = lib/lnx64.o/Ubuntu diff --git a/SDAccel/docs/Create_Runtime_AMI.md b/SDAccel/docs/Create_Runtime_AMI.md index 0adf3f95..1bd05c22 100644 --- a/SDAccel/docs/Create_Runtime_AMI.md +++ b/SDAccel/docs/Create_Runtime_AMI.md @@ -67,8 +67,8 @@ $ mkdir -p $XLNXRTE/lib/lnx64.o $ mkdir -p $XLNXRTE/runtime/bin $ mkdir -p $XLNXRTE/runtime/lib/x86_64 - $ cp $SDACCEL_DIR/userspace/src2/libxrt-aws.so $XLNXRTE/runtime/platforms/xilinx_aws-vu9p-f1-04261818_dynamic_5_0/driver/ - $ cp $SDACCEL_DIR/tools/awssak2/xbsak $XLNXRTE/runtime/bin/ + $ cp $SDACCEL_DIR/userspace/src/libxrt-aws.so $XLNXRTE/runtime/platforms/xilinx_aws-vu9p-f1-04261818_dynamic_5_0/driver/ + $ cp $SDACCEL_DIR/tools/awssak/xbsak $XLNXRTE/runtime/bin/ $ cp $XIILNX_SDX/lib/lnx64.o/$GLIBPATH/libstdc++.so* xlnxrte/lib/x86_64/ $ cp $XIILNX_SDX/runtime/bin/xclbinsplit xlnxrte/runtime/bin/ $ cp $XIILNX_SDX/runtime/bin/xclbincat xlnxrte/runtime/bin/ diff --git a/SDAccel/docs/XRT_installation_instructions.md b/SDAccel/docs/XRT_installation_instructions.md index 0ed1bd17..00f1a5ab 100644 --- a/SDAccel/docs/XRT_installation_instructions.md +++ b/SDAccel/docs/XRT_installation_instructions.md @@ -1,12 +1,12 @@ # XRT Installation Instructions -# Installing Xilinx Runtime (XRT) 2018.3 RC3 Patch 1 +# Installing Xilinx Runtime (XRT) 2018.3 RC3 Patch 2 * Applicable SDx Tool Version: 2018.3 - * XRT Release Tag: 2018.3.3.1 (SHA: 48cafdc100b29843fd013d371ffba0141db06b7a) + * XRT Release Tag: 2018.3.3.2 (SHA: f96913247f94f4bc3b5134c92a0decc138351038) - * [Xilinx Runtime (XRT) 2018.3 RC3 Patch 1 release](https://github.com/Xilinx/XRT/releases/tag/2018.3.3.1) + * [Xilinx Runtime (XRT) 2018.3 RC3 Patch 2 release](https://github.com/Xilinx/XRT/releases/tag/2018.3.3.2) ### Instructions to build & install XRT @@ -18,21 +18,22 @@ source sdaccel_setup.sh mkdir $SDACCEL_DIR/Runtime cd $SDACCEL_DIR/Runtime - export XRT_PATH="${SDACCEL_DIR}/Runtime/XRT_20183rc3p1 " - git clone http://www.github.com/Xilinx/XRT.git -b 2018.3.3.1 ${XRT_PATH} + export XRT_PATH="${SDACCEL_DIR}/Runtime/XRT_2018.3.3.2" + git clone http://www.github.com/Xilinx/XRT.git -b 2018.3.3.2 ${XRT_PATH} cd ${XRT_PATH} sudo ./src/runtime_src/tools/scripts/xrtdeps.sh cd build ``` - Follow [Xilinx's instructions to build & install XRT on Centos/Redhat & Ubuntu/Debian](https://xilinx.github.io/XRT/master/html/build.html#xrt-for-pcie-platforms) to build XRT for supported OS. + Follow [Xilinx's instructions to build & install XRT on Centos/Redhat & Ubuntu/Debian](https://xilinx.github.io/XRT/master/html/build.html#xrt-for-pcie-platforms) to build XRT for a supported OS. - ### Install on Centos/RedHat Linux using prebuilt RPM + ### Install on Centos/RHEL using prebuilt RPM ``` - curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.6.0/Patches/XRT_2018_3_RC3_Patch1/xrt_201830.2.1.0_7.6.1810-xrt.rpm -o xrt_201830.2.1.0_7.6.1810-xrt.rpm - curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.6.0/Patches/XRT_2018_3_RC3_Patch1/xrt_201830.2.1.0_7.6.1810-aws.rpm -o xrt_201830.2.1.0_7.6.1810-aws.rpm + + curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.6.0/Patches/XRT_2018_3_RC3_Patch2/xrt_201830.2.1.0_7.6.1810-xrt.rpm -o xrt_201830.2.1.0_7.6.1810-xrt.rpm + curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.6.0/Patches/XRT_2018_3_RC3_Patch2/xrt_201830.2.1.0_7.6.1810-aws.rpm -o xrt_201830.2.1.0_7.6.1810-aws.rpm sudo yum remove -y xrt-aws sudo yum remove -y xrt sudo yum install -y xrt_201830.2.1.0_7.6.1810-xrt.rpm diff --git a/SDAccel/docs/README_third_party.md b/SDAccel/examples/3rd_party/README.md similarity index 86% rename from SDAccel/docs/README_third_party.md rename to SDAccel/examples/3rd_party/README.md index 1e8fc873..5e82242d 100644 --- a/SDAccel/docs/README_third_party.md +++ b/SDAccel/examples/3rd_party/README.md @@ -2,7 +2,6 @@ * In the interest of providing more examples for the user, we present this guide that tells how to port third party OpenCL examples to the SDAccel flow. * In this guide, we show the changes necessary to port third party host code and kernel code for 2 different examples. * We also show some [differences between the third party OpenCL and Xilinx SDAccel implementations](#xilinx-and-third-party-implementation-differences) that the user should be aware of. -* There is a third example (matrix_mult, not discussed here) available at SDAccel/examples/3rd_party. ## The file structure of the third party examples used in this guide. * The following shows the common file structure of the third party examples used in this guide. @@ -27,16 +26,16 @@ common/src/AOCLUtils/options.cpp ## Changes to the host code. - * The changes needed for the **vector_addition** host code can be found [here](../examples/3rd_party/vector_addition) in the file named vector_addition_main.cpp.diff. - * The changes needed for the **fft1d** host code can be found [here](../examples/3rd_party/fft1d) in the file named fft1d_main.cpp.diff. - * All the modified dependency files can be found in the [SDAccel/examples/3rd_party/common](../examples/3rd_party/common) directory. + * The changes needed for the **vector_addition** host code can be found [here](vector_addition) in the file named vector_addition_main.cpp.diff. + * The changes needed for the **fft1d** host code can be found [here](fft1d) in the file named fft1d_main.cpp.diff. + * All the modified dependency files can be found in the [SDAccel/examples/3rd_party/common](common) directory. ## Changes to the kernel code. * The kernel code, found in the <example_name>/device directory, will most likely need modifications. * The **vector addition** kernel does not need changes. * The **fft1d** example needs several changes due to the differences between the third party and Xilinx implementations. -* The changes needed for the fft1d.cl file are found [here](../examples/3rd_party/fft1d) in the file named fft1d_fft1d.cl.diff. +* The changes needed for the fft1d.cl file are found [here](fft1d) in the file named fft1d_fft1d.cl.diff. * See table below regarding [implementation differences between third party and Xilinx](#xilinx-and-third-party-implementation-differences). * The <example_name>/device/twid_radix4_8.cl file will get many warnings about casting from double to float. @@ -46,18 +45,18 @@ common/src/AOCLUtils/options.cpp sed 's/\([0-9]\)\( \{0,\}[,}]\)/\1f\2/g' twid_radix4_8.cl > tmp mv tmp twid_radix4_8.cl ``` -* The script above can be found [here](../examples/3rd_party/fft1d) named cast_float_const.sh. +* The script above can be found [here](fft1d) named cast_float_const.sh. ## Changes to the Makefile. * The third party Makefile can be replaced by a version that is similar to the SDAccel example Makefiles. -* For example, for the third party **vector_addition** code, the Makefile can be found [here](../examples/3rd_party/vector_addition). -* The **fft1d** example Makefile can be found [here](../examples/3rd_party/fft1d). +* For example, for the third party **vector_addition** code, the Makefile can be found [here](vector_addition). +* The **fft1d** example Makefile can be found [here](fft1d). ## Compiling and running. * The steps to compile and run would be the same as those used for the SDAccel examples with the exception that the host program would need the -hw=<mode> switch when running in emulation mode. -* For the complete guide on compiling and running the SDAccel examples, see [this](../README.md). +* For the complete guide on compiling and running the SDAccel examples, see [this](../../README.md). * To run in software emulation mode, use the following commands. ``` @@ -80,7 +79,7 @@ make TARGETS=hw DEVICES=$AWS_PLATFORM all ./main ``` -* For more information on running this example on an F1 instance, see [this](../README.md#runonf1). +* For more information on running this example on an F1 instance, see [this](../../README.md#runonf1). ## Xilinx and third party Implementation Differences diff --git a/SDAccel/examples/3rd_party/matrix_mult/Makefile b/SDAccel/examples/3rd_party/matrix_mult/Makefile deleted file mode 100644 index d459aff2..00000000 --- a/SDAccel/examples/3rd_party/matrix_mult/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -## Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. -## -## Licensed under the Amazon Software License (the "License"). You may not use -## this file except in compliance with the License. A copy of the License is -## located at -## -## http://aws.amazon.com/asl/ -## -## or in the "license" file accompanying this file. This file is distributed on -## an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or -## implied. See the License for the specific language governing permissions and -## limitations under the License. - - -COMMON_REPO := $(SDACCEL_DIR)/examples/xilinx - -include $(COMMON_REPO)/utility/boards.mk -include $(COMMON_REPO)/libs/xcl/xcl.mk -include $(COMMON_REPO)/libs/opencl/opencl.mk - -main_SRCS=$(wildcard host/src/*.cpp ../common/src/AOCLUtils/*.cpp) $(xcl_SRCS) -main_HDRS=$(xcl_HDRS) - -main_CXXFLAGS=$(xcl_CXXFLAGS) $(opencl_CXXFLAGS) -Ihost/inc/ -I../common/inc/ -main_LDFLAGS=$(opencl_LDFLAGS) -lrt - -EXES=main - -# Kernel -matrix_mult_SRCS=./device/matrix_mult.cl -matrix_mult_CLFLAGS= -k matrix_mult -Ihost/inc/ -#Specifyinng Fifo depth for Dataflow -matrix_mult_CLFLAGS+=--xp "param:compiler.xclDataflowFifoDepth=32" - -XOS=matrix_mult - -# xclbin -matrix_mult_XOS=matrix_mult - -XCLBINS=matrix_mult - -# check -check_EXE=main -check_XCLBINS=matrix_mult - -CHECKS=check - -# Compilation flags -ifeq ($(DEBUG),1) -CXXFLAGS += -g -else -CXXFLAGS += -O2 -endif - -# Compiler -#CXX := g++ - -include $(COMMON_REPO)/utility/rules.mk diff --git a/SDAccel/examples/3rd_party/matrix_mult/README.md b/SDAccel/examples/3rd_party/matrix_mult/README.md deleted file mode 100644 index 228c3161..00000000 --- a/SDAccel/examples/3rd_party/matrix_mult/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Third party matrix multiply OpcnCL example. -## Compiling and running. -* The steps to compile and run are the same as those used for the SDAccel examples with the exception that the host program would need the -hw=<mode> switch when running in emulation mode. - - -* For the complete guide on compiling and running the SDAccel examples, see [this](../../../README.md). - -* To run in software emulation mode, use the following commands. - ``` -make clean -source $XILINX_SDX/settings64.sh -make TARGETS=sw_emu DEVICES=$AWS_PLATFORM all -./main -hw=sw_emu -``` - -* To run in hardware emulation mode, use the following commands. - ``` -make clean -source $XILINX_SDX/settings64.sh -make TARGETS=hw_emu DEVICES=$AWS_PLATFORM all -./main -hw=hw_emu -``` - -* To run on an F1 instance, use the following commands. - ``` -make clean -source $XILINX_SDX/settings64.sh -make TARGETS=hw DEVICES=$AWS_PLATFORM all -./main -``` - -* For more information on running this example on an F1 instance, see [this](../../../README.md#runonf1). \ No newline at end of file diff --git a/SDAccel/examples/3rd_party/matrix_mult/device/matrix_mult.cl b/SDAccel/examples/3rd_party/matrix_mult/device/matrix_mult.cl deleted file mode 100644 index 42dc429f..00000000 --- a/SDAccel/examples/3rd_party/matrix_mult/device/matrix_mult.cl +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (C) 2013-2016 Altera Corporation, San Jose, California, USA. All rights reserved. -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to -// whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -// This agreement shall be governed in all respects by the laws of the State of California and -// by the laws of the United States of America. - -// This kernel computes C = A * B, where -// A is a N x K matrix -// B is a K x M matrix -// C is a N x M matrix -// All dimensions must be a multiple of BLOCK_SIZE (defined below). -// -// The ND-range is two-dimensional and corresponds to the dimensions of matrix -// C. Each work-item computes one element of the output matrix. -// -// The implemented algorithm uses blocking to take advantage of data reuse -// across multiple elements in matrix C. This is just like the standard loop -// tiling optimization often used in matrix multiplication implementations. -// -// This kernel is intended to be compiled with the following compiler flags: -// --no-interleaving default -// This flag indicates that the global memory is divided into two logical -// banks and allows the host program to assign buffers to specific buffers. -// This allows the host to manage the load on each memory bank, usually -// to maximize the memory bandwidth usage. -// -// This flag is used for matrix multiplication because there are -// two primary memory accesses: reads from matrix A and reads from -// matrix B. To maximize memory bandwidth, the two input matrices -// are placed in different memory banks, which ensures that there is no -// contention when trying to read elements from both matrices -// simultaneously. -// -// -fp-relaxed=true -// This flag enables the order of additions in the dot product -// computation within a block to be rearranged. This enables the additions -// to be computed more efficiently in hardware, using a tree structure -// instead of a vine. -// -// As a simple example, take the addition of four values: a0 + a1 + a2 + a3. -// The default implementation (without -fp-relaxed=true) is: -// (((a0 + a1) + a2) + a3) -// which matches the standard ordering of operations. In hardware, this -// looks like: -// a0 a1 -// |-+-| -// | a2 -// |-+-| -// | a3 -// |-+-| -// | -// -// With -fp-relaxed=true, the implementation is a balanced tree: -// ((a0 + a1) + (a2 + a3)) -// In hardware, this looks like: -// a0 a1 a2 a3 -// |-+-| |-+-| -// | | -// |----+----| -// | -// -// There are two values that need to be defined in the preprocessor. -// BLOCK_SIZE -// The dimension of the block used in the core computation -// is BLOCK_SIZE x BLOCK_SIZE. This is defined in the host -// include file because the host needs to know too (just to -// ensure that the matrix sizes are a multiple of the block -// size. -// SIMD_WORK_ITEMS -// This value tells the compiler how many work-items in the work-group -// in a SIMD fashion. In the context of matrix multiplication, this -// value indicates how many output elements will be computed -// in a SIMD manner. BLOCK_SIZE must be a multiple of SIMD_WORK_ITEMS. -// See the Optimization Guide for details about this attribute. -// -// The combination of these values determines the number of floating-point -// operations per cycle. - -#include "matrixMult.h" - -#ifndef SIMD_WORK_ITEMS -#define SIMD_WORK_ITEMS 4 // default value -#endif - -__kernel -__attribute((reqd_work_group_size(BLOCK_SIZE,BLOCK_SIZE,1))) -__attribute((num_simd_work_items(SIMD_WORK_ITEMS))) -void matrix_mult( // Input and output matrices - __global float *restrict C, - __global float *A, - __global float *B, - // Widths of matrices. - int A_width, int B_width) -{ - // Local storage for a block of input matrices A and B - __local float A_local[BLOCK_SIZE][BLOCK_SIZE]; - __local float B_local[BLOCK_SIZE][BLOCK_SIZE]; - - // Block index - int block_x = get_group_id(0); - int block_y = get_group_id(1); - - // Local ID index (offset within a block) - int local_x = get_local_id(0); - int local_y = get_local_id(1); - - // Compute loop bounds - int a_start = A_width * BLOCK_SIZE * block_y; - int a_end = a_start + A_width - 1; - int b_start = BLOCK_SIZE * block_x; - - float running_sum = 0.0f; - - // Compute the matrix multiplication result for this output element. Each - // loop iteration processes one block of the matrix. - for (int a = a_start, b = b_start; a <= a_end; a += BLOCK_SIZE, b += (BLOCK_SIZE * B_width)) - { - // Load the matrices to local memory. Note that the (x, y) indices - // are swapped for A_local and B_local. This affects the reads from - // A_local and B_local below and result in more efficient hardware. - // - // This is actually an optimization that the compiler can perform, - // but is shown here for illustration purposes. - A_local[local_y][local_x] = A[a + A_width * local_y + local_x]; - B_local[local_x][local_y] = B[b + B_width * local_y + local_x]; - - // Wait for the entire block to be loaded. - barrier(CLK_LOCAL_MEM_FENCE); - - // Do the dot product accumulation within this block. Fully unroll the loop. - // As a result of the swap of indices above, memory accesses to - // A_local and B_local are very efficient because each loop iteration - // accesses consecutive elements. This can be seen by unrolling the - // loop and analyzing the regions that are loaded: - // A_local[local_y][0..BLOCK_SIZE-1] and - // B_local[local_x][0..BLOCK_SIZE-1] - __attribute__((opencl_unroll_hint())) - for (int k = 0; k < BLOCK_SIZE; ++k) - { - running_sum += A_local[local_y][k] * B_local[local_x][k]; - } - - // Wait for the block to be fully consumed before loading the next - // block. - barrier(CLK_LOCAL_MEM_FENCE); - } - - // Store result in matrix C - C[get_global_id(1) * get_global_size(0) + get_global_id(0)] = running_sum; -} diff --git a/SDAccel/examples/3rd_party/matrix_mult/host/inc/matrixMult.h b/SDAccel/examples/3rd_party/matrix_mult/host/inc/matrixMult.h deleted file mode 100644 index 76f8f0ad..00000000 --- a/SDAccel/examples/3rd_party/matrix_mult/host/inc/matrixMult.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2013-2016 Altera Corporation, San Jose, California, USA. All rights reserved. -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to -// whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -// This agreement shall be governed in all respects by the laws of the State of California and -// by the laws of the United States of America. - -#ifndef MATRIXMULT_H -#define MATRIXMULT_H - -// Block size. Affects the kernel, so if this value changes, the kernel -// needs to be recompiled. -#ifndef BLOCK_SIZE -#define BLOCK_SIZE 64 // default value -#endif - -#endif - diff --git a/SDAccel/examples/3rd_party/matrix_mult/host/src/main.cpp b/SDAccel/examples/3rd_party/matrix_mult/host/src/main.cpp deleted file mode 100644 index 4481372d..00000000 --- a/SDAccel/examples/3rd_party/matrix_mult/host/src/main.cpp +++ /dev/null @@ -1,549 +0,0 @@ -// Copyright (C) 2013-2016 Altera Corporation, San Jose, California, USA. All rights reserved. -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to -// whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -// This agreement shall be governed in all respects by the laws of the State of California and -// by the laws of the United States of America. - -/////////////////////////////////////////////////////////////////////////////////// -// This host program executes a matrix multiplication kernel to perform: -// C = A * B -// where A is a N x K matrix, B is a K x M matrix and C is a N x M matrix. -// All dimensions must be a multiple of BLOCK_SIZE, which affects the -// underlying kernel. -// -// This host program supports partitioning the problem across multiple OpenCL -// devices if available. If there are M available devices, the problem is -// divided so that each device operates on N/M rows (with -// processed by each device is . The host program -// assumes that all devices are of the same type (that is, the same binary can -// be used), but the code can be generalized to support different device types -// easily. -// -// Verification is performed against the same computation on the host CPU. -/////////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include "CL/opencl.h" -#include "AOCLUtils/aocl_utils.h" -#include "matrixMult.h" - -using namespace aocl_utils; - -// OpenCL runtime configuration -cl_platform_id platform = NULL; -unsigned num_devices = 0; -scoped_array device; // num_devices elements -cl_context context = NULL; -scoped_array queue; // num_devices elements -cl_program program = NULL; -scoped_array kernel; // num_devices elements -#if USE_SVM_API == 0 -scoped_array input_a_buf; // num_devices elements -scoped_array input_b_buf; // num_devices elements -scoped_array output_buf; // num_devices elements -#endif /* USE_SVM_API == 0 */ - -// Problem data. -unsigned A_height = 32 * BLOCK_SIZE; -unsigned A_width = 16 * BLOCK_SIZE; -const unsigned &B_height = A_width; -unsigned B_width = 16 * BLOCK_SIZE; -const unsigned &C_height = A_height; -const unsigned &C_width = B_width; -std::string hwtype = "hw"; - -#if USE_SVM_API == 0 -scoped_array > input_a; // num_devices elements -scoped_aligned_ptr input_b; -scoped_array > output; // num_devices elements -#else -scoped_array > input_a; // num_devices elements -scoped_SVM_aligned_ptr input_b; -scoped_array > output; // num_devices elements -#endif /* USE_SVM_API == 0 */ -scoped_array ref_output; -scoped_array rows_per_device; // num_devices elements - -// Function prototypes -float rand_float(); -bool init_opencl(); -void init_problem(); -void run(); -void compute_reference(); -void verify(); -void cleanup(); - -// Entry point. -int main(int argc, char **argv) { - Options options(argc, argv); - - if(options.has("ah")) { - A_height = options.get("ah"); - } - if(options.has("aw")) { - A_width = options.get("aw"); - } - if(options.has("bw")) { - B_width = options.get("bw"); - } - if(options.has("hw")) { - hwtype = options.get("hw"); - } - - printf("Matrix sizes:\n A: %d x %d\n B: %d x %d\n C: %d x %d\n", - A_height, A_width, B_height, B_width, C_height, C_width); - - // Spot check matrix sizes. They all must be a multiple of BLOCK_SIZE, - // although it is relatively straightforward to handle non-multiples - // by adding padding. For simplicity, this example does not pad. - if((A_height % BLOCK_SIZE) != 0 || (A_width % BLOCK_SIZE) != 0 || - (B_height % BLOCK_SIZE) != 0 || (B_width % BLOCK_SIZE) != 0 || - (C_height % BLOCK_SIZE) != 0 || (C_width % BLOCK_SIZE) != 0) { - printf("Matrix sizes must be a multiple of %d.\n", BLOCK_SIZE); - return -1; - } - - // Initialize OpenCL. - if(!init_opencl()) { - return -1; - } - - // Initialize the problem data. - // Requires the number of devices to be known. - init_problem(); - - // Run the kernel. - run(); - - // Free the resources allocated - cleanup(); - - return 0; -} - -/////// HELPER FUNCTIONS /////// - -// Randomly generate a floating-point number between -10 and 10. -float rand_float() { - return float(rand()) / float(RAND_MAX) * 20.0f - 10.0f; -} - -// Initializes the OpenCL objects. -bool init_opencl() { - cl_int status; - - printf("Initializing OpenCL\n"); - - if(!setCwdToExeDir()) { - return false; - } - - // Get the OpenCL platform. - platform = findPlatform("Xilinx"); - if(platform == NULL) { - printf("ERROR: Unable to find Xilinx OpenCL platform.\n"); - return false; - } - - // Query the available OpenCL device. - device.reset(getDevices(platform, CL_DEVICE_TYPE_ALL, &num_devices)); - printf("Platform: %s\n", getPlatformName(platform).c_str()); - printf("Using %d device(s)\n", num_devices); - for(unsigned i = 0; i < num_devices; ++i) { - printf(" %s\n", getDeviceName(device[i]).c_str()); - } - - // Create the context. - context = clCreateContext(NULL, num_devices, device, &oclContextCallback, NULL, &status); - checkError(status, "Failed to create context"); - - // Create the program for all device. Use the first device as the - // representative device (assuming all device are of the same type). - std::string fname = "xclbin/matrix_mult."+ hwtype + "." + VERSION_STR; - std::string binary_file = getBoardBinaryFile(fname.c_str(), device[0]); - printf("Using XCLBIN: %s\n", binary_file.c_str()); - program = createProgramFromBinary(context, binary_file.c_str(), device, num_devices); - - // Build the program that was just created. - status = clBuildProgram(program, 0, NULL, "", NULL, NULL); - checkError(status, "Failed to build program"); - - // Create per-device objects. - queue.reset(num_devices); - kernel.reset(num_devices); - rows_per_device.reset(num_devices); -#if USE_SVM_API == 0 - input_a_buf.reset(num_devices); - input_b_buf.reset(num_devices); - output_buf.reset(num_devices); -#endif /* USE_SVM_API == 0 */ - - const unsigned num_block_rows = C_height / BLOCK_SIZE; - - for(unsigned i = 0; i < num_devices; ++i) { - // Command queue. - queue[i] = clCreateCommandQueue(context, device[i], CL_QUEUE_PROFILING_ENABLE, &status); - checkError(status, "Failed to create command queue"); - - // Kernel. - const char *kernel_name = "matrix_mult"; - kernel[i] = clCreateKernel(program, kernel_name, &status); - checkError(status, "Failed to create kernel"); - - // Determine the number of rows processed by this device. - // First do this computation in block-rows. - rows_per_device[i] = num_block_rows / num_devices; // this is the number of block-rows - - // Spread out the remainder of the block-rows over the first - // N % num_devices. - if(i < (num_block_rows % num_devices)) { - rows_per_device[i]++; - } - - // Multiply by BLOCK_SIZE to get the actual number of rows. - rows_per_device[i] *= BLOCK_SIZE; - -#if USE_SVM_API == 0 - // Input buffers. - // For matrix A, each device only needs the rows corresponding - // to the rows of the output matrix. We specifically - // assign this buffer to the first bank of global memory. - input_a_buf[i] = clCreateBuffer(context, CL_MEM_READ_ONLY , // remove for now // | CL_MEM_BANK_1_ALTERA, - rows_per_device[i] * A_width * sizeof(float), NULL, &status); - checkError(status, "Failed to create buffer for input A"); - - // For matrix B, each device needs the whole matrix. We specifically - // assign this buffer to the second bank of global memory. - input_b_buf[i] = clCreateBuffer(context, CL_MEM_READ_ONLY, // remove for now // | CL_MEM_BANK_2_ALTERA, - B_height * B_width * sizeof(float), NULL, &status); - checkError(status, "Failed to create buffer for input B"); - - // Output buffer. This is matrix C, for the rows that are computed by this - // device. We assign this buffer to the first bank of global memory, - // although it is not material to performance to do so because - // the reads from the input matrices are far more frequent than the - // write to the output matrix. - output_buf[i] = clCreateBuffer(context, CL_MEM_WRITE_ONLY, // remove for now // | CL_MEM_BANK_1_ALTERA, - rows_per_device[i] * C_width * sizeof(float), NULL, &status); - checkError(status, "Failed to create buffer for output"); -#else - cl_device_svm_capabilities caps = 0; - - status = clGetDeviceInfo( - device[i], - CL_DEVICE_SVM_CAPABILITIES, - sizeof(cl_device_svm_capabilities), - &caps, - 0 - ); - checkError(status, "Failed to get device info"); - - if (!(caps & CL_DEVICE_SVM_COARSE_GRAIN_BUFFER)) { - printf("The host was compiled with USE_SVM_API, however the device currently being targeted does not support SVM.\n"); - // Free the resources allocated - cleanup(); - return false; - } -#endif /* USE_SVM_API == 0 */ - } - - return true; -} - -// Initialize the data for the problem. Requires num_devices to be known. -void init_problem() { - if(num_devices == 0) { - checkError(-1, "No devices"); - } - - // Generate input matrices A and B. For matrix A, we divide up the host - // buffers so that the buffers are aligned for each device. The whole of - // matrix B is used by each device, so it does not need to be divided. - printf("Generating input matrices\n"); - input_a.reset(num_devices); - output.reset(num_devices); -#if USE_SVM_API == 0 - for(unsigned i = 0; i < num_devices; ++i) { - input_a[i].reset(rows_per_device[i] * A_width); - output[i].reset(rows_per_device[i] * C_width); - - for(unsigned j = 0; j < rows_per_device[i] * A_width; ++j) { - input_a[i][j] = rand_float(); - } - } - - input_b.reset(B_height * B_width); - for(unsigned i = 0; i < B_height * B_width; ++i) { - input_b[i] = rand_float(); - } -#else - for(unsigned i = 0; i < num_devices; ++i) { - input_a[i].reset(context, rows_per_device[i] * A_width); - output[i].reset(context, rows_per_device[i] * C_width); - - cl_int status; - - status = clEnqueueSVMMap(queue[i], CL_TRUE, CL_MAP_WRITE, - (void *)input_a[i], rows_per_device[i] * A_width * sizeof(float), 0, NULL, NULL); - checkError(status, "Failed to map input A"); - - for(unsigned j = 0; j < rows_per_device[i] * A_width; ++j) { - input_a[i][j] = rand_float(); - } - - status = clEnqueueSVMUnmap(queue[i], (void *)input_a[i], 0, NULL, NULL); - checkError(status, "Failed to unmap input A"); - } - - input_b.reset(context, B_height * B_width); - - cl_int status; - - for (unsigned i = 0; i < num_devices; ++i) { - status = clEnqueueSVMMap(queue[i], CL_TRUE, CL_MAP_WRITE, - (void *)input_b, B_height * B_width * sizeof(float), 0, NULL, NULL); - checkError(status, "Failed to map input B"); - } - - for(unsigned i = 0; i < B_height * B_width; ++i) { - input_b[i] = rand_float(); - } - - for (unsigned i = 0; i < num_devices; ++i) { - status = clEnqueueSVMUnmap(queue[i], (void *)input_b, 0, NULL, NULL); - checkError(status, "Failed to unmap input B"); - } -#endif /* USE_SVM_API == 0 */ -} - -void run() { - cl_int status; - -#if USE_SVM_API == 0 - // Transfer inputs to each device. Each of the host buffers supplied to - // clEnqueueWriteBuffer here is already aligned to ensure that DMA is used - // for the host-to-device transfer. - for(unsigned i = 0; i < num_devices; ++i) { - status = clEnqueueWriteBuffer(queue[i], input_a_buf[i], CL_FALSE, - 0, rows_per_device[i] * A_width * sizeof(float), input_a[i], 0, NULL, NULL); - checkError(status, "Failed to transfer input A"); - - status = clEnqueueWriteBuffer(queue[i], input_b_buf[i], CL_FALSE, - 0, B_width * B_height * sizeof(float), input_b, 0, NULL, NULL); - checkError(status, "Failed to transfer input B"); - } - - // Wait for all queues to finish. - for(unsigned i = 0; i < num_devices; ++i) { - clFinish(queue[i]); - } -#endif /* USE_SVM_API == 0 */ - - // Launch kernels. - // This is the portion of time that we'll be measuring for throughput - // benchmarking. - scoped_array kernel_event(num_devices); - - const double start_time = getCurrentTimestamp(); - for(unsigned i = 0; i < num_devices; ++i) { - // Set kernel arguments. - unsigned argi = 0; - -#if USE_SVM_API == 0 - status = clSetKernelArg(kernel[i], argi++, sizeof(cl_mem), &output_buf[i]); - checkError(status, "Failed to set argument %d", argi - 1); - - status = clSetKernelArg(kernel[i], argi++, sizeof(cl_mem), &input_a_buf[i]); - checkError(status, "Failed to set argument %d", argi - 1); - - status = clSetKernelArg(kernel[i], argi++, sizeof(cl_mem), &input_b_buf[i]); - checkError(status, "Failed to set argument %d", argi - 1); -#else - status = clSetKernelArgSVMPointer(kernel[i], argi++, (void*)output[i]); - checkError(status, "Failed to set argument %d", argi - 1); - - status = clSetKernelArgSVMPointer(kernel[i], argi++, (void*)input_a[i]); - checkError(status, "Failed to set argument %d", argi - 1); - - status = clSetKernelArgSVMPointer(kernel[i], argi++, (void*)input_b); - checkError(status, "Failed to set argument %d", argi - 1); -#endif /* USE_SVM_API == 0 */ - - status = clSetKernelArg(kernel[i], argi++, sizeof(A_width), &A_width); - checkError(status, "Failed to set argument %d", argi - 1); - - status = clSetKernelArg(kernel[i], argi++, sizeof(B_width), &B_width); - checkError(status, "Failed to set argument %d", argi - 1); - - // Enqueue kernel. - // Use a global work size corresponding to the size of the output matrix. - // Each work-item computes the result for one value of the output matrix, - // so the global work size has the same dimensions as the output matrix. - // - // The local work size is one block, so BLOCK_SIZE x BLOCK_SIZE. - // - // Events are used to ensure that the kernel is not launched until - // the writes to the input buffers have completed. - const size_t global_work_size[2] = {C_width, rows_per_device[i]}; - const size_t local_work_size[2] = {BLOCK_SIZE, BLOCK_SIZE}; - printf("Launching for device %d (global size: %zd, %zd)\n", i, global_work_size[0], global_work_size[1]); - - status = clEnqueueNDRangeKernel(queue[i], kernel[i], 2, NULL, - global_work_size, local_work_size, 0, NULL, &kernel_event[i]); - checkError(status, "Failed to launch kernel"); - } - - // Wait for all kernels to finish. - clWaitForEvents(num_devices, kernel_event); - - const double end_time = getCurrentTimestamp(); - const double total_time = end_time - start_time; - - // Wall-clock time taken. - printf("\nTime: %0.3f ms\n", total_time * 1e3); - - // Get kernel times using the OpenCL event profiling API. - for(unsigned i = 0; i < num_devices; ++i) { - cl_ulong time_ns = getStartEndTime(kernel_event[i]); - printf("Kernel time (device %d): %0.3f ms\n", i, double(time_ns) * 1e-6); - } - - // Compute the throughput (GFLOPS). - // There are C_width * C_height output values, with each value - // computed using A_width multiplies and adds. - const float flops = (float)(2.0f * C_width * C_height * A_width / total_time); - printf("\nThroughput: %0.2f GFLOPS\n\n", flops * 1e-9); - - // Release kernel events. - for(unsigned i = 0; i < num_devices; ++i) { - clReleaseEvent(kernel_event[i]); - } - - // Read the result. - for(unsigned i = 0; i < num_devices; ++i) { -#if USE_SVM_API == 0 - status = clEnqueueReadBuffer(queue[i], output_buf[i], CL_TRUE, - 0, rows_per_device[i] * C_width * sizeof(float), output[i], 0, NULL, NULL); - checkError(status, "Failed to read output matrix"); -#else - status = clEnqueueSVMMap(queue[i], CL_TRUE, CL_MAP_READ, - (void *)output[i], rows_per_device[i] * C_width * sizeof(float), 0, NULL, NULL); - checkError(status, "Failed to map output"); -#endif /* USE_SVM_API == 0 */ - } - - // Verify results. - compute_reference(); - verify(); -#if USE_SVM_API == 1 - for (unsigned i = 0; i < num_devices; ++i) { - status = clEnqueueSVMUnmap(queue[i], (void *)output[i], 0, NULL, NULL); - checkError(status, "Failed to unmap output"); - } -#endif /* USE_SVM_API == 1 */ -} - -void compute_reference() { - // Compute the reference output. - printf("Computing reference output\n"); - ref_output.reset(C_height * C_width); - - for(unsigned y = 0, dev_index = 0; y < C_height; ++dev_index) { - for(unsigned yy = 0; yy < rows_per_device[dev_index]; ++yy, ++y) { - for(unsigned x = 0; x < C_width; ++x) { - // Compute result for C(y, x) - float sum = 0.0f; - for(unsigned k = 0; k < A_width; ++k) { - sum += input_a[dev_index][yy * A_width + k] * input_b[k * B_width + x]; - } - ref_output[y * C_width + x] = sum; - } - } - } -} - -void verify() { - printf("Verifying\n"); - - // Compute the L^2-Norm of the difference between the output and reference - // output matrices and compare it against the L^2-Norm of the reference. - float diff = 0.0f; - float ref = 0.0f; - for(unsigned y = 0, dev_index = 0; y < C_height; ++dev_index) { - for(unsigned yy = 0; yy < rows_per_device[dev_index]; ++yy, ++y) { - for(unsigned x = 0; x < C_width; ++x) { - const float o = output[dev_index][yy * C_width + x]; - const float r = ref_output[y * C_width + x]; - const float d = o - r; - diff += d * d; - ref += r * r; - } - } - } - - const float diff_l2norm = sqrtf(diff); - const float ref_l2norm = sqrtf(ref); - const float error = diff_l2norm / ref_l2norm; - const bool pass = error < 1e-6; - printf("Verification: %s\n", pass ? "PASS" : "FAIL"); - if(!pass) { - printf("Error (L^2-Norm): %0.3g\n", error); - } -} - -// Free the resources allocated during initialization -void cleanup() { - for(unsigned i = 0; i < num_devices; ++i) { - if(kernel && kernel[i]) { - clReleaseKernel(kernel[i]); - } - if(queue && queue[i]) { - clReleaseCommandQueue(queue[i]); - } -#if USE_SVM_API == 0 - if(input_a_buf && input_a_buf[i]) { - clReleaseMemObject(input_a_buf[i]); - } - if(input_b_buf && input_b_buf[i]) { - clReleaseMemObject(input_b_buf[i]); - } - if(output_buf && output_buf[i]) { - clReleaseMemObject(output_buf[i]); - } -#else - if(input_a[i].get()) - input_a[i].reset(); - if(output[i].get()) - output[i].reset(); -#endif /* USE_SVM_API == 0 */ - } -#if USE_SVM_API == 1 - if(input_b.get()) - input_b.reset(); -#endif /* USE_SVM_API == 1 */ - - if(program) { - clReleaseProgram(program); - } - if(context) { - clReleaseContext(context); - } -} - diff --git a/SDAccel/examples/xilinx_2018.2 b/SDAccel/examples/xilinx_2018.2 index 70a0f3ed..a41b5892 160000 --- a/SDAccel/examples/xilinx_2018.2 +++ b/SDAccel/examples/xilinx_2018.2 @@ -1 +1 @@ -Subproject commit 70a0f3edc6d78f3de13806ec7a7a01d1fbe0d2bd +Subproject commit a41b58921188ad90ace2d34a22a2513d8f74b549 diff --git a/SDAccel/sdaccel_xrt_version.txt b/SDAccel/sdaccel_xrt_version.txt index 4518becc..cff9b8f5 100644 --- a/SDAccel/sdaccel_xrt_version.txt +++ b/SDAccel/sdaccel_xrt_version.txt @@ -1,4 +1,5 @@ 2018.2:343186f76f59edd01bc48d84cf67fe22a0a3f338 2018.2:65ffad62f427c0bd1bc65b6ea555a810295468b7 +2018.3:f96913247f94f4bc3b5134c92a0decc138351038 2018.3:3636217b633930ed4815abd598324691ca25c2f3 -2018.3:48cafdc100b29843fd013d371ffba0141db06b7a +2018.3:48cafdc100b29843fd013d371ffba0141db06b7a \ No newline at end of file diff --git a/SDAccel/tests/test_find_sdaccel_examples.py b/SDAccel/tests/test_find_sdaccel_examples.py index f0c5c758..ce443cc9 100644 --- a/SDAccel/tests/test_find_sdaccel_examples.py +++ b/SDAccel/tests/test_find_sdaccel_examples.py @@ -44,6 +44,8 @@ class TestFindSDAccelExamples(AwsFpgaTestBase): NOTE: Cannot have an __init__ method. ''' + ADD_XILINX_VERSION = True + @classmethod def setup_class(cls): ''' @@ -52,7 +54,7 @@ def setup_class(cls): AwsFpgaTestBase.setup_class(cls, __file__) return - def test_find_example_makefiles(self): + def test_find_example_makefiles(self, xilinxVersion): assert os.path.exists(self.xilinx_sdaccel_examples_dir), "The Xilinx SDAccel example dir does not exist: {}".format(self.xilinx_sdaccel_examples_dir) assert os.listdir(self.xilinx_sdaccel_examples_dir) != [], "Xilinx SDAccel example submodule not cloned or does not exist" @@ -61,13 +63,11 @@ def test_find_example_makefiles(self): xilinx_sdaccel_example_map = {} for root, dirs, files in os.walk(self.xilinx_sdaccel_examples_dir): - for file in files: - if file.endswith('Makefile'): - makefile_path = root + "/Makefile" - - # If the Makefile has a docs target, it's not the makefile we want to read - if 'docs:' not in open(makefile_path).read(): - xilinx_examples_makefiles.append(root) + if os.path.exists(root + "/description.json") and os.path.exists(root + "/Makefile"): + xilinx_examples_makefiles.append(root) + logger.info("Adding: " + root) + else: + logger.info("Ignoring: " + root) assert len(xilinx_examples_makefiles) != 0, "Could not find any Xilinx SDAccel example in %s" % self.xilinx_sdaccel_examples_dir @@ -84,4 +84,8 @@ def test_find_example_makefiles(self): with open(self.xilinx_sdaccel_examples_list_file, 'w') as outfile: json.dump(xilinx_sdaccel_example_map, outfile) + # Also write the archive file + with open(self.xilinx_sdaccel_examples_list_file + "." + xilinxVersion, 'w') as archive_file: + json.dump(xilinx_sdaccel_example_map, archive_file) + assert os.path.getsize(self.xilinx_sdaccel_examples_list_file) > 0, "%s is a non zero file. We need to have some data in the file" % self.xilinx_sdaccel_examples_list_file diff --git a/SDAccel/tools/awssak/Makefile b/SDAccel/tools/awssak/Makefile index 8b1fff39..019ae6fa 100644 --- a/SDAccel/tools/awssak/Makefile +++ b/SDAccel/tools/awssak/Makefile @@ -24,14 +24,15 @@ CXX := g++ CXXFLAGS := -Wall -Werror -std=c++11 ROOT = $(SDACCEL_DIR) -HAL_INC := -I../../include -I$(ROOT)/userspace/include +HAL_INC := -I$(SDACCEL_DIR)/userspace/src -I$(SDACCEL_DIR)/userspace/include -I$(SDK_DIR)/userspace/include -I$(SDK_DIR)/linux_kernel_drivers CXXFLAGS += $(HAL_INC) ifeq ($(ec2),1) -AWSBM_HAL_LIBNAME := $(ROOT)/userspace/src/libawsxcldrv.a +AWS_HAL_LIBNAME := $(ROOT)/userspace/src/libxrt-aws.a else -AWSBM_HAL_LIBNAME := $(ROOT)/userspace/src/libawsbmdrv.a +AWS_HAL_LIBNAME := $(ROOT)/userspace/src/libxrtbm-aws.a +CXXFLAGS += -DINTERNAL_RELEASE endif ifeq ($(debug),1) @@ -59,8 +60,8 @@ all : $(EXENAME) $(CXX) $(CXXFLAGS) $(MYCFLAGS) $(MYCXXFLAGS) -c $< -o $@ $(CXX) $(CXXFLAGS) $(MYCFLAGS) $(MYCXXFLAGS) -c -MM $< -o $(patsubst %.o, %.d, $@) -$(EXENAME): $(OBJS) $(AWSBM_HAL_LIBNAME) - $(CXX) -o $@ $(OBJS) $(AWSBM_HAL_LIBNAME) $(LDFLAGS) $(LDLIBS) -lrt +$(EXENAME): $(OBJS) $(AWS_HAL_LIBNAME) + $(CXX) -o $@ $(OBJS) $(AWS_HAL_LIBNAME) $(LDFLAGS) $(LDLIBS) -lrt -pthread clean: rm -rf *.o *.d $(EXENAME) diff --git a/SDAccel/tools/awssak/main.cpp b/SDAccel/tools/awssak/main.cpp index 91f95bd6..09b96f57 100644 --- a/SDAccel/tools/awssak/main.cpp +++ b/SDAccel/tools/awssak/main.cpp @@ -1,9 +1,7 @@ /** * Copyright (C) 2017-2018 Xilinx, Inc - * Author: Sonal Santan - * Simple command line utility to interact with SDX PCIe devices - * - * Code copied verbatim from SDAccel xbsak implementation + * Author: Sonal Santan, Ryan Radjabi + * Simple command line utility to inetract with SDX PCIe devices * * Licensed under the Apache License, Version 2.0 (the "License"). You may * not use this file except in compliance with the License. A copy of the @@ -18,921 +16,9 @@ * under the License. */ -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xclhal.h" -#include "xcl_axi_checker_codes.h" -#include "memaccess.h" - - -#define TO_STRING(x) #x -#define OCL_NUM_CLOCKS 2 - -class Timer { - std::chrono::high_resolution_clock::time_point mTimeStart; -public: - Timer() { - reset(); - } - long long stop() { - std::chrono::high_resolution_clock::time_point timeEnd = std::chrono::high_resolution_clock::now(); - return std::chrono::duration_cast(timeEnd - mTimeStart).count(); - } - void reset() { - mTimeStart = std::chrono::high_resolution_clock::now(); - } -}; - -/* - * Simple command line tool to query and interact with SDx PCIe devices - * The tool statically links with xcldma HAL driver inorder to avoid - * dependencies on environment variables like XILINX_OPENCL, LD_LIBRARY_PATH, etc. - * TODO: - * Rewrite the command line parsing to provide interface like Android adb: - * xcldev [options] - */ - -namespace xcldev { - enum command { - FLASH, - PROGRAM, - CLOCK, - BOOT, - HELP, - QUERY, - RESET, - RUN, - FAN, - DMATEST, - LIST, - MEM, - STATUS, - CMD_MAX - }; - - enum subcommand { - MEM_READ = 0, - MEM_WRITE, - STATUS_APM, - STATUS_LAPC - }; - enum statusmask { - STATUS_NONE_MASK = 0x0, - STATUS_APM_MASK = 0x1, - STATUS_LAPC_MASK = 0x2 - }; - - static const std::pair map_pairs[] = { - std::make_pair("flash", FLASH), - std::make_pair("program", PROGRAM), - std::make_pair("clock", CLOCK), - std::make_pair("boot", BOOT), - std::make_pair("help", HELP), - std::make_pair("query", QUERY), - std::make_pair("reset", RESET), - std::make_pair("run", RUN), - std::make_pair("fan", FAN), - std::make_pair("dmatest", DMATEST), - std::make_pair("list", LIST), - std::make_pair("mem", MEM), - std::make_pair("status", STATUS) - }; - - static const std::pair subcmd_pairs[] = { - std::make_pair("read", MEM_READ), - std::make_pair("write", MEM_WRITE), - std::make_pair("apm", STATUS_APM), - std::make_pair("lapc", STATUS_LAPC) - }; - - - static const std::map commandTable(map_pairs, map_pairs + sizeof(map_pairs) / sizeof(map_pairs[0])); - - class device { - unsigned int m_idx; - xclDeviceHandle m_handle; - xclDeviceInfo2 m_devinfo; - bool m_multiclock; - - public: - device(unsigned int idx, const char* log) : m_idx(idx), m_handle(nullptr), m_devinfo{}, - m_multiclock(false) { - m_handle = xclOpen(m_idx, log, XCL_QUIET); - if (!m_handle) - throw std::runtime_error("Failed to open device index, " + std::to_string(m_idx)); - if (xclGetDeviceInfo2(m_handle, &m_devinfo)) - throw std::runtime_error("Unable to query device index, " + std::to_string(m_idx)); -// const unsigned id = (m_devinfo.mDeviceId << 16) | m_devinfo.mSubsystemId; - m_multiclock = true; - } - - bool isMultipleOCLClockSupported() { return m_multiclock; } - - device(device&& rhs) : m_idx(rhs.m_idx), m_handle(rhs.m_handle), m_devinfo(std::move(rhs.m_devinfo)) { - } - - device(const device &dev) = delete; - device& operator=(const device &dev) = delete; - - ~device() { - xclClose(m_handle); - } - - const char *name() const { - return m_devinfo.mName; - } - - int flash(const std::string& mcs1, const std::string& mcs2) { - return xclUpgradeFirmware2(m_handle, mcs1.c_str(), mcs2.c_str()); - } - - int reclock2(unsigned regionIndex, const unsigned short *freq) { - return xclReClock2(m_handle, 2, freq); - } - - std::string parseCUStatus(unsigned val) const { - char delim = '('; - std::string status; - if (val & 0x1) { - status += delim; - status += "START"; - delim = '|'; - } - if (val & 0x2) { - status += delim; - status += "DONE"; - delim = '|'; - } - if (val & 0x4) { - status += delim; - status += "IDLE"; - delim = '|'; - } - if (val & 0x8) { - status += delim; - status += "READY"; - delim = '|'; - } - if (val & 0x10) { - status += delim; - status += "RESTART"; - delim = '|'; - } - if (status.size()) - status += ')'; - else if (val == 0x0) - status = "(--)"; - else - status = "(?\?)"; - return status; - } - - std::ostream& dump(std::ostream& ostr) const { - ostr << "DSA name: " << m_devinfo.mName << "\n"; - ostr << "HAL ver: " << m_devinfo.mHALMajorVersion << "." << m_devinfo.mHALMinorVersion << "\n"; - ostr << "Vendor: " << std::hex << m_devinfo.mVendorId << std::dec << "\n"; - ostr << "Device: " << std::hex << m_devinfo.mDeviceId << std::dec << "\n"; - ostr << "Device ver: " << m_devinfo.mDeviceVersion << "\n"; - ostr << "SDevice: " << std::hex << m_devinfo.mSubsystemId << std::dec << "\n"; - ostr << "SVendor: " << std::hex << m_devinfo.mSubsystemVendorId << std::dec << "\n"; - ostr << "DDR size: " << "0x" << std::hex << m_devinfo.mDDRSize/1024 << std::dec << " KB\n"; - ostr << "DDR count: " << m_devinfo.mDDRBankCount << "\n"; - ostr << "Data alignment: " << m_devinfo.mDataAlignment << "\n"; - ostr << "DDR free size: " << "0x" << std::hex << m_devinfo.mDDRFreeSize/1024 << std::dec << " KB\n"; - ostr << "Min xfer size: " << m_devinfo.mMinTransferSize << "\n"; - ostr << "OnChip Temp: " << m_devinfo.mOnChipTemp << " C\n"; - //ostr << "Fan Temp: " << m_devinfo.mFanTemp<< " C\n"; - ostr << "VCC INT: " << m_devinfo.mVInt << " mV\n"; - ostr << "VCC AUX: " << m_devinfo.mVAux << " mV\n"; - ostr << "VCC BRAM: " << m_devinfo.mVBram << " mV\n"; - if (m_multiclock) { - ostr << "OCL freq1: " << m_devinfo.mOCLFrequency[0] << " MHz\n"; - ostr << "OCL freq2: " << m_devinfo.mOCLFrequency[1] << " MHz\n"; - } - else { - ostr << "OCL freq: " << m_devinfo.mOCLFrequency[0] << " MHz\n"; - } - ostr << "PCIe: " << "GEN" << m_devinfo.mPCIeLinkSpeed << " x " << m_devinfo.mPCIeLinkWidth << "\n"; - ostr << "DMA threads: " << m_devinfo.mDMAThreads << "\n"; - //ostr << "Fan Speed: " << m_devinfo.mFanSpeed << "\n"; - ostr << "MIG Calibrated: " << std::boolalpha << m_devinfo.mMigCalib << std::noboolalpha << "\n"; - - ostr << "CU Status:\n"; - unsigned buf[16]; - for (unsigned i = 0; i < 4; i++) { - xclRead(m_handle, XCL_ADDR_KERNEL_CTRL, i * 4096, static_cast(buf), 16); - ostr << " " << std::setw(7) << i << ": 0x" << std::hex << buf[0] << std::dec << " " << parseCUStatus(buf[0]) << "\n"; - } - return ostr; - } - - int program(const std::string& xclbin, unsigned region) { - std::ifstream stream(xclbin.c_str()); - - if(!stream.is_open()) { - std::cout << "ERROR: Cannot open " << xclbin << ". Check that it exists and is readable." << std::endl; - return -ENOENT; - } - - char temp[8]; - stream.read(temp, 8); - if (std::strncmp(temp, "xclbin0", 8) && std::strncmp(temp, "xclbin2", 8)) - return -EINVAL; - - stream.seekg(0, stream.end); - int length = stream.tellg(); - stream.seekg(0, stream.beg); - - char *buffer = new char[length]; - stream.read(buffer, length); - const xclBin *header = (const xclBin *)buffer; - int result = xclLockDevice(m_handle); - if (result) - return result; - result = xclLoadXclBin(m_handle, header); - delete [] buffer; - return result; - } - - int boot() { - return xclBootFPGA(m_handle); - } - - int reset(unsigned region) { - return xclResetDevice(m_handle, XCL_RESET_KERNEL); - } - - int run(unsigned region, unsigned cu) { - std::cout << "ERROR: Not implemented\n"; - return -1; - } - - int fan(unsigned speed) { - std::cout << "ERROR: Not implemented\n"; - return -1; - } - - int dmatest(unsigned long long blockSize) { - void *buf = 0; - if (posix_memalign(&buf, 4096, blockSize)) - return -1; - std::memset(buf, 0, blockSize); - - double bw = m_devinfo.mDDRSize; - bw /= 0x100000; // Convert to MB - - // Use plain POSIX open/pwrite/close. - // std::ofstream causes libstdc++ to use AIO with xcldma on CentOS 6.x (but not on Ubuntu 15.10) - std::string baseName("/dev/xdma"); - baseName += std::to_string(m_idx); - baseName += "_h2c_0"; - int fd = open(baseName.c_str(), O_WRONLY); - if (fd < 0) { - std::cout << "Unable to open device node " << baseName << "\n"; - return -1; - } - std::cout << "INFO: Zeroing DDR with " << blockSize/1024 << " KB blocks using DMA channel 0 ...\n"; - ssize_t count = 0; - Timer tim; - for (uint64_t phy = 0; phy < m_devinfo.mDDRSize; phy += blockSize) { - count += pwrite(fd, (const char *)buf, blockSize, phy); - } - double elapsed = tim.stop(); - close(fd); - bw /= elapsed; - bw *= 1000000; // Convert from microseconds to seconds - if (count != (ssize_t)m_devinfo.mDDRSize) { - std::cout << "DMA error\n"; - return -1; - } - std::cout << "INFO: Host -> PCIe -> MIG write bandwidth " << bw << " MB/s\n"; - - baseName.pop_back(); - baseName += "1"; - bw = m_devinfo.mDDRSize; - bw /= 0x100000; // Convert to MB - - // Use plain POSIX open/pwrite/close. - // std::ofstream causes libstdc++ to use AIO with xcldma on CentOS 6.x (but not on Ubuntu 15.10) - fd = open(baseName.c_str(), O_WRONLY); - if (fd < 0) { - std::cout << "Unable to open device node " << baseName << "\n"; - return -1; - } - - std::cout << "INFO: Zeroing DDR with " << blockSize/1024 << " KB blocks using DMA channel 1 ...\n"; - count = 0; - tim.reset(); - for (uint64_t phy = 0; phy < m_devinfo.mDDRSize; phy += blockSize) { - count += pwrite(fd, (const char *)buf, blockSize, phy); - } - elapsed = tim.stop(); - close(fd); - bw /= elapsed; - bw *= 1000000; // Convert from microseconds to seconds - if (count != (ssize_t)m_devinfo.mDDRSize) { - std::cout << "DMA error\n"; - return -1; - } - std::cout << "INFO: Host -> PCIe -> MIG write bandwidth " << bw << " MB/s\n"; - - // Now read bandwidth - bw = m_devinfo.mDDRSize; - bw /= 0x100000; // Convert to MB - baseName.erase(baseName.size() - 6); - baseName += "_c2h_0"; - fd = open(baseName.c_str(), O_RDONLY); - if (fd < 0) { - std::cout << "Unable to open device node " << baseName << "\n"; - return -1; - } - std::cout << "INFO: Reading back " << blockSize/1024 << " KB blocks from DDR using DMA channel 0 ...\n"; - count = 0; - tim.reset(); - for (uint64_t phy = 0; phy < m_devinfo.mDDRSize; phy += blockSize) { - count += pread(fd, (char *)buf, blockSize, phy); - } - elapsed = tim.stop(); - close(fd); - bw /= elapsed; - bw *= 1000000; // Convert from microseconds to seconds - if (count != (ssize_t)m_devinfo.mDDRSize) { - std::cout << "DMA error\n"; - return -1; - } - std::cout << "INFO: Host <- PCIe <- MIG read bandwidth " << bw << " MB/s\n"; - - baseName.pop_back(); - baseName += "1"; - bw = m_devinfo.mDDRSize; - bw /= 0x100000; // Convert to MB - - // Use plain POSIX open/pwrite/close. - // std::ofstream causes libstdc++ to use AIO with xcldma on CentOS 6.x (but not on Ubuntu 15.10) - fd = open(baseName.c_str(), O_RDONLY); - if (fd < 0) { - std::cout << "Unable to open device node " << baseName << "\n"; - return -1; - } - - std::cout << "INFO: Reading back " << blockSize/1024 << " KB blocks from DDR using DMA channel 1 ...\n"; - count = 0; - tim.reset(); - for (uint64_t phy = 0; phy < m_devinfo.mDDRSize; phy += blockSize) { - count += pread(fd, (char *)buf, blockSize, phy); - } - elapsed = tim.stop(); - close(fd); - bw /= elapsed; - bw *= 1000000; // Convert from microseconds to seconds - if (count != (ssize_t)m_devinfo.mDDRSize) { - std::cout << "DMA error\n"; - return -1; - } - std::cout << "INFO: Host <- PCIe <- MIG read bandwidth " << bw << " MB/s\n"; - - free(buf); - return 0; - } - int memread(std::string aFilename, unsigned long long aStartAddr = 0, unsigned long long aSize = 0) { - std::string baseName("/dev/xdma"); - baseName += std::to_string(m_idx); - return memaccess(baseName, m_devinfo.mDDRSize, m_devinfo.mDataAlignment).read(aFilename, aStartAddr, aSize); - } - - int memwrite(unsigned long long aStartAddr, unsigned long long aSize, unsigned int aPattern) { - std::string baseName("/dev/xdma"); - baseName += std::to_string(m_idx); - return memaccess(baseName, m_devinfo.mDDRSize, m_devinfo.mDataAlignment).write(aStartAddr, aSize, aPattern); - } - - int readAPMCounters() { - static const char* apmSlotNames [XAPM_MAX_NUMBER_SLOTS] = { - "OCL Master-0", - "XDMA ", - "OCL Master-1", - "OCL Master-2", - "OCL Master-3", - "Reserved ", - "Reserved ", - "Reserved " - }; - xclDebugCountersResults debugResults = {0}; - xclDebugReadIPStatus(m_handle, XCL_DEBUG_READ_TYPE_APM, &debugResults); - std::cout << "APM Counters\n"; - std::cout << "Slot " << std::setw(20) << " Write Bytes" << std::setw(16) << " Write Trans." << std::setw(16) << " Read Bytes" << std::setw(16) << " Read Tranx." << std::endl; - for (int i = 0; i()); - std::cout << " Other violations: \n"; - std::cout << " " << xclAXICheckerCodes::decodeAXICheckerCodes(tCummStatus); - violations_found = true; - } - } - if (!violations_found && !invalid_codes) { - std::cout << "No AXI violations found \n"; - } - if (violations_found && aVerbose && !invalid_codes) { - std::cout << "\n"; - std::cout << "Slot " << std::setw(20) << "Overall Status" << std::setw(16) << "Snapshot0" << std::setw(16) << " Snapshot1" << std::setw(16) << " Snapshot2" << std::setw(16) << " Snapshot3"; - std::cout << std::setw(16) << " Cumulative0" << std::setw(16) << " Cumulative1 " << std::setw(16) << " Cumulative2" << std::setw(16) << " Cumulative3" << std::endl; - for (int i = 0; i [options]\n\n"; - std::cout << "Command and option summary:\n"; - std::cout << " boot [-d device]\n"; - std::cout << " clock [-d device] [-r region] [-f clock1_freq_MHz] [-g clock2_freq_MHz]\n"; - std::cout << " dmatest [-d device] [-b [0x]block_size_KB]\n"; - std::cout << " mem --read [-d device] [-a [0x]start_addr] [-i size_bytes] [-o output filename]\n"; - std::cout << " mem --write [-d device] [-a [0x]start_addr] [-i size_bytes] [-e pattern_byte]\n"; -// std::cout << " fan [-d device] -s speed\n"; - std::cout << " flash [-d device] -m primary_mcs [-n secondary_mcs]\n"; - std::cout << " help\n"; - std::cout << " list\n"; - std::cout << " program [-d device] [-r region] -p xclbin\n"; - std::cout << " query [-d device [-r region]]\n"; - std::cout << " reset [-d device] [-r region]\n"; - std::cout << " status --apm\n"; - std::cout << " status --lapc\n"; -// std::cout << " run -d device [-r region] -c compunit\n"; TODO - std::cout << "\nExamples:\n"; - std::cout << "List all devices\n"; - std::cout << " " << exe << " list\n"; - std::cout << "Boot device 1 from PROM and retrain the PCIe link without rebooting the host\n"; - std::cout << " " << exe << " boot -d 1\n"; - std::cout << "Change the clock frequency of region 0 in device 0 to 100 MHz\n"; - std::cout << " " << exe << " clock -f 100\n"; - std::cout << "For device 0 which supports multiple clocks, change the clock 1 to 200MHz and clock 2 to 250MHz\n"; - std::cout << " " << exe << " clock -f 200 -g 250\n"; - std::cout << "Download the accelerator program for device 2\n"; - std::cout << " " << exe << " program -d 2 -p a.xclbin\n"; - std::cout << "Run DMA test on device 1 with 32 KB blocks of buffer\n"; - std::cout << " " << exe << " dmatest -d 1 -b 0x20\n"; - std::cout << "Read 256 bytes from DDR starting at 0x1000 into file read.out\n"; - std::cout << " " << exe << " mem --read -a 0x1000 -i 256 -o read.out\n"; - std::cout << " " << "Default values for address is 0x0, size is DDR size and file is memread.out\n"; - std::cout << "Write 256 bytes to DDR starting at 0x1000 with byte 0xaa \n"; - std::cout << " " << exe << " mem --write -a 0x1000 -i 256 -e 0xaa\n"; - std::cout << " " << "Default values for address is 0x0, size is DDR size and pattern is 0x0\n"; - std::cout << "Read AXI Performance Monitor counters on the base platform (applicable only if APMs are available on base platform)\n"; - std::cout << " " << exe << " status --apm\n"; - std::cout << "Read AXI violation codes detected by Light weight AXI Protocol Checker (applicable only if LAPC IP available on base platform)\n"; - std::cout << " " << exe << " status --lapc\n"; - } -} - +#include "awssak.h" int main(int argc, char *argv[]) { - unsigned index = 0xffffffff; - unsigned regionIndex = 0xffffffff; - unsigned computeIndex = 0xffffffff; - unsigned short targetFreq[2] = {0, 0}; - unsigned fanSpeed = 0; - unsigned long long startAddr = 0; - unsigned int pattern_byte = 0; - size_t sizeInBytes = 0; - std::string outMemReadFile = "memread.out"; - std::string mcsFile1, mcsFile2; - std::string xclbin; - unsigned long long blockSize = 0x4000000; - - int c; - - const std::string exe(argv[0]); - if (argc == 1) { - xcldev::printHelp(exe); - return 1; - } - - argv++; - const auto v = xcldev::commandTable.find(*argv); - if (v == xcldev::commandTable.end()) { - std::cout << "ERROR: Unknown comand \'" << *argv << "\'\n"; - xcldev::printHelp(exe); - return 1; - } - - const xcldev::command cmd = v->second; - std::string cmdname = v->first; - xcldev::subcommand subcmd = xcldev::MEM_READ; - unsigned int ipmask = static_cast(xcldev::STATUS_NONE_MASK); - argc--; - - if (cmd == xcldev::HELP) { - xcldev::printHelp(exe); - return 1; - } - - argv[0] = const_cast(exe.c_str()); - static struct option long_options[] = { - {"read", no_argument, 0, xcldev::MEM_READ}, - {"write", no_argument, 0, xcldev::MEM_WRITE}, - {"apm", no_argument, 0, xcldev::STATUS_APM}, - {"lapc", no_argument, 0, xcldev::STATUS_LAPC} - }; - int long_index; - const char* short_options = "a:d:e:i:r:p:f:g:m:n:c:s:b:o:"; //don't add numbers - while ((c = getopt_long(argc, argv, short_options, long_options, &long_index)) != -1) - { - if (cmd == xcldev::LIST) { - std::cout << "ERROR: 'list' command does not accept any options\n"; - return -1; - } - switch (c) - { - //Deal with long options. Long options return the value set in option::val - case xcldev::MEM_READ : { - //--read - if (cmd != xcldev::MEM) { - std::cout << "ERROR: Option '" << long_options[long_index].name << "' cannot be used with command " << cmdname << "\n"; - return -1; - } - subcmd = xcldev::MEM_READ; - break; - } - case xcldev::MEM_WRITE : { - //--write - if (cmd != xcldev::MEM) { - std::cout << "ERROR: Option '" << long_options[long_index].name << "' cannot be used with command " << cmdname << "\n"; - return -1; - } - subcmd = xcldev::MEM_WRITE; - break; - } - case xcldev::STATUS_APM : { - //--apm - if (cmd != xcldev::STATUS) { - std::cout << "ERROR: Option '" << long_options[long_index].name << "' cannot be used with command " << cmdname << "\n"; - return -1; - } - ipmask |= static_cast(xcldev::STATUS_APM_MASK); - break; - } - case xcldev::STATUS_LAPC : { - //--lapc - if (cmd != xcldev::STATUS) { - std::cout << "ERROR: Option '" << long_options[long_index].name << "' cannot be used with command " << cmdname << "\n"; - return -1; - } - ipmask |= static_cast(xcldev::STATUS_LAPC_MASK); - break; - } - //short options are dealt here - case 'a':{ - if (cmd != xcldev::MEM) { - std::cout << "ERROR: '-a' not applicable for this command\n"; - return -1; - } - size_t idx = 0; - try { - startAddr = std::stoll(optarg, &idx, 0); - } - catch (const std::exception& ex) { - //out of range, invalid argument ex - std::cout << "ERROR: Value supplied to -" << (char)c << " option is invalid\n"; - return -1; - } - if (idx < strlen(optarg)) { - std::cout << "ERROR: Value supplied to -" << (char)c << " option is invalid\n"; - return -1; - } - break; - } - case 'o': - if (cmd != xcldev::MEM || subcmd != xcldev::MEM_READ) { - std::cout << "ERROR: '-o' not applicable for this command\n"; - return -1; - } - outMemReadFile = optarg; - break; - case 'e': { - if (cmd != xcldev::MEM || subcmd != xcldev::MEM_WRITE) { - std::cout << "ERROR: '-e' not applicable for this command\n"; - return -1; - } - size_t idx = 0; - try { - pattern_byte = std::stoi(optarg, &idx, 0); - } - catch (const std::exception& ex) { - //out of range, invalid argument ex - std::cout << "ERROR: Value supplied to -" << (char)c << " option must be a value between 0 and 255\n"; - return -1; - } - if (pattern_byte > 0xff || idx < strlen(optarg)) { - std::cout << "ERROR: Value supplied to -" << (char)c << " option must be a value between 0 and 255\n"; - return -1; - } - break; - } - case 'i': { - if (cmd != xcldev::MEM) { - std::cout << "ERROR: '-i' not applicable for this command\n"; - return -1; - } - size_t idx = 0; - try { - sizeInBytes = std::stoll(optarg, &idx, 0); - } - catch (const std::exception& ex) { - //out of range, invalid argument ex - std::cout << "ERROR: Value supplied to -" << (char)c << " option is invalid\n"; - return -1; - } - if (idx < strlen(optarg)) { - std::cout << "ERROR: Value supplied to -" << (char)c << " option is invalid\n"; - return -1; - } - break; - } - case 'd': - index = std::atoi(optarg); - break; - case 'r': - if ((cmd == xcldev::FLASH) || (cmd == xcldev::BOOT) || (cmd == xcldev::DMATEST)) { - std::cout << "ERROR: '-r' not applicable for this command\n"; - return -1; - } - regionIndex = std::atoi(optarg); - break; - case 'p': - if (cmd != xcldev::PROGRAM) { - std::cout << "ERROR: '-p' only allowed with 'program' command\n"; - return -1; - } - xclbin = optarg; - break; - case 'f': - if (cmd != xcldev::CLOCK) { - std::cout << "ERROR: '-f' only allowed with 'clock' command\n"; - return -1; - } - targetFreq[0] = std::atoi(optarg); - break; - case 'g': - if (cmd != xcldev::CLOCK) { - std::cout << "ERROR: '-g' only allowed with 'clock' command\n"; - return -1; - } - targetFreq[1] = std::atoi(optarg); - break; - case 'm': - if (cmd != xcldev::FLASH) { - std::cout << "ERROR: '-m' only allowed with 'flash' command\n"; - return -1; - } - mcsFile1 = optarg; - break; - case 'n': - if (cmd != xcldev::FLASH) { - std::cout << "ERROR: '-n' only allowed with 'flash' command\n"; - return -1; - } - mcsFile2 = optarg; - break; - case 'c': - if (cmd != xcldev::RUN) { - std::cout << "ERROR: '-c' only allowed with 'run' command\n"; - return -1; - } - computeIndex = std::atoi(optarg); - break; - case 's': - if (cmd != xcldev::FAN) { - std::cout << "ERROR: '-s' only allowed with 'fan' command\n"; - return -1; - } - fanSpeed = std::atoi(optarg); - break; - case 'b': - { - if (cmd != xcldev::DMATEST) { - std::cout << "ERROR: '-b' only allowed with 'dmatest' command\n"; - return -1; - } - std::string tmp(optarg); - if ((tmp[0] == '0') && (std::tolower(tmp[1]) == 'x')) { - blockSize = std::stoll(tmp, 0, 16); - } - else { - blockSize = std::stoll(tmp, 0, 10); - } - - if (blockSize & (blockSize - 1)) { - std::cout << "ERROR: block size should be power of 2\n"; - return -1; - } - blockSize *= 1024; // convert kilo bytes to bytes - break; - } - default: - xcldev::printHelp(exe); - return 1; - } - } - - if (optind != argc) { - std::cout << "ERROR: Illegal command \'" << argv[optind++] << "\'\n"; - } - - if (index == 0xffffffff) index = 0; - - if (regionIndex == 0xffffffff) regionIndex = 0; - - switch (cmd) { - case xcldev::FLASH: - { - if (mcsFile1.size() == 0) { - std::cout << "ERROR: Please specify mcs file with '-m' switch\n"; - return -1; - } - break; - } - case xcldev::BOOT: - case xcldev::RUN: - case xcldev::FAN: - case xcldev::DMATEST: - case xcldev::QUERY: - case xcldev::STATUS: - break; - case xcldev::PROGRAM: - { - if (xclbin.size() == 0) { - std::cout << "ERROR: Please specify xclbin file with '-p' switch\n"; - return -1; - } - break; - } - case xcldev::CLOCK: - { - if (!targetFreq[0] && !targetFreq[1]) { - std::cout << "ERROR: Please specify frequency(ies) with '-f' and or '-g' switch(es)\n"; - return -1; - } - break; - } - default: - break; - } - - std::vector> deviceVec; - - try { - unsigned int count = xclProbe(); - if (count == 0) { - std::cout << "ERROR: No devices found\n"; - return 1; - } - - for (unsigned i = 0; i < count; i++) { - deviceVec.emplace_back(new xcldev::device(i, nullptr)); - } - } - catch (const std::exception& ex) { - std::cout << ex.what() << std::endl; - return 1; - } - - std::cout << "INFO: Found " << deviceVec.size() << " device(s)\n"; - - if (cmd == xcldev::LIST) { - for (unsigned i = 0; i < deviceVec.size(); i++) { - std::cout << '[' << i << "] " << deviceVec[i]->name() << std::endl; - } - return 0; - } - - if (index >= deviceVec.size()) { - std::cout << "ERROR: Device index " << index << " out of range\n"; - return 1; - } - - int result = 0; - - switch (cmd) - { - case xcldev::BOOT: - result = deviceVec[index]->boot(); - break; - case xcldev::CLOCK: - result = deviceVec[index]->reclock2(regionIndex, targetFreq); - break; - case xcldev::FAN: - result = deviceVec[index]->fan(fanSpeed); - break; - case xcldev::FLASH: - result = deviceVec[index]->flash(mcsFile1, mcsFile2); - break; - case xcldev::PROGRAM: - result = deviceVec[index]->program(xclbin, regionIndex); - break; - case xcldev::QUERY: - deviceVec[index]->dump(std::cout); - break; - case xcldev::RESET: - result = deviceVec[index]->reset(regionIndex); - break; - case xcldev::RUN: - result = deviceVec[index]->run(regionIndex, computeIndex); - break; - case xcldev::DMATEST: - result = deviceVec[index]->dmatest(blockSize); - break; - case xcldev::MEM: - if (subcmd == xcldev::MEM_READ) { - result = deviceVec[index]->memread(outMemReadFile, startAddr, sizeInBytes); - } - else if (subcmd == xcldev::MEM_WRITE) { - result = deviceVec[index]->memwrite(startAddr, sizeInBytes, pattern_byte); - } - break; - case xcldev::STATUS: - if (ipmask == xcldev::STATUS_NONE_MASK) { - //if no ip specified then read all - ipmask = static_cast(xcldev::STATUS_APM_MASK); - if (!(getuid() && geteuid())) { - ipmask |= static_cast(xcldev::STATUS_LAPC_MASK); - } - } - if (ipmask & static_cast(xcldev::STATUS_APM_MASK)) { - result = deviceVec[index]->readAPMCounters(); - } - if (ipmask & static_cast(xcldev::STATUS_LAPC_MASK)) { - result = deviceVec[index]->readLAPCheckers(1); - } - break; - default: - std::cout << "ERROR: Not implemented\n"; - result = -1; - } - - if(result == 0) { - std::cout << "INFO: xbsak " << v->first << " successful." << std::endl; - } else { - std::cout << "ERROR: xbsak " << v->first << " failed." << std::endl; - } - - return result; + return xcldev::xclXbsak(argc, argv); } diff --git a/SDAccel/tools/awssak/memaccess.h b/SDAccel/tools/awssak/memaccess.h deleted file mode 100644 index b85ed53f..00000000 --- a/SDAccel/tools/awssak/memaccess.h +++ /dev/null @@ -1,159 +0,0 @@ -/** - * Copyright (C) 2017-2018 Xilinx, Inc - * Author: Sonal Santan - * Simple command line utility to inetract with SDX PCIe devices - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -#include -#include -#include -#include -#include -#include - -#include "xclhal.h" -namespace xcldev { - class memaccess { - std::string mDevName; - size_t mDDRSize, mDataAlignment; - public: - memaccess(std::string aDevName, size_t aDDRSize, size_t aDataAlignment) : - mDevName(aDevName), mDDRSize(aDDRSize), mDataAlignment (aDataAlignment) {} - - int read(std::string aFilename, unsigned long long aStartAddr = 0, unsigned long long aSize = 0) { - void *buf = 0; - unsigned long long size; - unsigned long long blockSize = 0x20000; - if (posix_memalign(&buf, 4096, blockSize)) - return -1; - std::memset(buf, 0, blockSize); - - //sanity check - if (aStartAddr > mDDRSize) { - std::cout << "Start address " << std::hex << aStartAddr << - " is greater than device memory " << std::hex << mDDRSize << std::endl; - return -1; - } - //sanity check - if (aSize > mDDRSize || aStartAddr+aSize > mDDRSize) { - std::cout << "Read size " << std::dec << aSize << " from address 0x" << std::hex << aStartAddr << - " goes beyond the device memory" << std::endl; - return -1; - } - - unsigned long long endAddr = aSize == 0 ? mDDRSize : aStartAddr+aSize; - - size = endAddr-aStartAddr; - std::ofstream outFile(aFilename, std::ofstream::out | std::ofstream::binary); - - // Use plain POSIX open/pwrite/close. - std::string baseName = mDevName; - baseName += "_c2h_0"; - int fd = open(baseName.c_str(), O_RDONLY); - if (fd < 0) { - std::cout << "Unable to open device node " << baseName << "\n"; - return -1; - } - size_t count = size; - uint64_t incr; - size_t nRead = 0; - for (uint64_t phy = aStartAddr; phy < aStartAddr+size; phy += incr) { - incr = (count >= blockSize) ? blockSize : count; - nRead = pread(fd, (char *)buf, incr, phy); - if (nRead == (size_t)-1) { - //error - std::cout << "Error (" << strerror (errno) << ") reading " << incr << " bytes from DDR at offset " << std::hex << phy << std::dec << "\n"; - return -1; - } - count -= nRead; - if (nRead) { - outFile.write((const char*)(char*)buf, nRead); - if ((outFile.rdstate() & std::ifstream::failbit) != 0) { - std::cout << "Error writing to file \n"; - } - } - std::cout << "INFO: Read block 0x" << std::hex << nRead << " total 0x" < mDDRSize) { - std::cout << "Start address " << std::hex << aStartAddr << - " is greater than device memory " << std::hex << mDDRSize << std::endl; - return -1; - } - //sanity check - if (aSize > mDDRSize || aStartAddr+aSize > mDDRSize) { - std::cout << "Read size " << std::dec << aSize << " from address 0x" << std::hex << aStartAddr << - " goes beyond the device memory" << std::endl; - return -1; - } - - endAddr = aSize == 0 ? mDDRSize : aStartAddr + aSize; - size = endAddr-aStartAddr; - - // Use plain POSIX open/pwrite/close. - std::string baseName = mDevName; - baseName += "_h2c_0"; - - std::cout << "INFO: Writing DDR with " << std::dec << size << " bytes of pattern: 0x" - << std::hex << aPattern << " from address 0x" <= blockSize) ? blockSize : count; - size_t nWrite = pwrite(wfd, (const char *)buf, incr, phy); - if (nWrite == (size_t)-1) { - //error - std::cout << "Error (" << strerror (errno) << ") writing " << incr << " bytes to DDR at offset " << std::hex << phy << std::dec << "\n"; - return -1; - } - count -= nWrite; - } - - close(wfd); - if (count != 0) { - std::cout << "Error! Written " << std::dec << size-count << " bytes, requested " << size << std::endl; - return -1; - } - return count; - } - }; -} diff --git a/SDAccel/tools/awssak2/LICENSE-2.0.txt b/SDAccel/tools/awssak2/LICENSE-2.0.txt deleted file mode 100644 index d6456956..00000000 --- a/SDAccel/tools/awssak2/LICENSE-2.0.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/SDAccel/tools/awssak2/Makefile b/SDAccel/tools/awssak2/Makefile deleted file mode 100644 index 391ad587..00000000 --- a/SDAccel/tools/awssak2/Makefile +++ /dev/null @@ -1,71 +0,0 @@ -# Amazon FPGA Hardware Development Kit -# -# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Amazon Software License (the "License"). You may not use -# this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/asl/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or -# implied. See the License for the specific language governing permissions and -# limitations under the License. - -EXENAME := xbsak - -CXX_EXT := cpp -CL_EXT := cl - -AR := ar -CXX := g++ - -CXXFLAGS := -Wall -Werror -std=c++11 - -ROOT = $(SDACCEL_DIR) -HAL_INC := -I$(SDACCEL_DIR)/userspace/src2 -I$(SDACCEL_DIR)/userspace/include -I$(SDK_DIR)/userspace/include -I$(SDK_DIR)/linux_kernel_drivers - -CXXFLAGS += $(HAL_INC) - -ifeq ($(ec2),1) -AWS_HAL_LIBNAME := $(ROOT)/userspace/src2/libxrt-aws.a -else -AWS_HAL_LIBNAME := $(ROOT)/userspace/src2/libxrtbm-aws.a -CXXFLAGS += -DINTERNAL_RELEASE -endif - -ifeq ($(debug),1) - CXXFLAGS += -g -D_DEBUG -else - CXXFLAGS += -O2 -DNDEBUG -endif - -SRCS := $(wildcard *.$(CXX_EXT)) -OBJS := $(patsubst %.$(CXX_EXT), %.o, $(SRCS)) - --include $(OBJS:.o=.d) - -AWS_FPGA_MGMTLIB := fpga_mgmt -AWS_FPGA_MGMTLIB_DIR := $(SDK_DIR)/userspace/lib - -ifeq ($(ec2),1) -LDFLAGS += -L$(AWS_FPGA_MGMTLIB_DIR) -LDLIBS += -l$(AWS_FPGA_MGMTLIB) -endif - -all : $(EXENAME) - -%.o: %.$(CXX_EXT) - $(CXX) $(CXXFLAGS) $(MYCFLAGS) $(MYCXXFLAGS) -c $< -o $@ - $(CXX) $(CXXFLAGS) $(MYCFLAGS) $(MYCXXFLAGS) -c -MM $< -o $(patsubst %.o, %.d, $@) - -$(EXENAME): $(OBJS) $(AWS_HAL_LIBNAME) - $(CXX) -o $@ $(OBJS) $(AWS_HAL_LIBNAME) $(LDFLAGS) $(LDLIBS) -lrt -pthread - -clean: - rm -rf *.o *.d $(EXENAME) - -.PHONY: all - -.DEFAULT_GOAL := all diff --git a/SDAccel/tools/awssak2/main.cpp b/SDAccel/tools/awssak2/main.cpp deleted file mode 100644 index 09b96f57..00000000 --- a/SDAccel/tools/awssak2/main.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (C) 2017-2018 Xilinx, Inc - * Author: Sonal Santan, Ryan Radjabi - * Simple command line utility to inetract with SDX PCIe devices - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -#include "awssak.h" - -int main(int argc, char *argv[]) -{ - return xcldev::xclXbsak(argc, argv); -} diff --git a/SDAccel/userspace/include/xcl_app_debug.h b/SDAccel/userspace/include/xcl_app_debug.h index 71d5c20b..0c3fb604 100644 --- a/SDAccel/userspace/include/xcl_app_debug.h +++ b/SDAccel/userspace/include/xcl_app_debug.h @@ -1,8 +1,23 @@ /** - * Copyright (C) 2015-2018 Xilinx, Inc + * Copyright (C) 2016-2018 Xilinx, Inc * + * Licensed under the Apache License, Version 2.0 (the "License"). You may + * not use this file except in compliance with the License. A copy of the + * License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +/** * Xilinx SDAccel HAL userspace driver extension APIs * Performance Monitoring Exposed Parameters + * Copyright (C) 2015-2018, Xilinx Inc - All rights reserved * * Licensed under the Apache License, Version 2.0 (the "License"). You may * not use this file except in compliance with the License. A copy of the @@ -24,13 +39,14 @@ extern "C" { #endif -/************************ APM Debug Counters ********************************/ -#define XAPM_DEBUG_METRIC_COUNTERS_PER_SLOT 4 //debug is only interested in 4 metric counters +/************************ SPM Debug Counters ********************************/ +//debug is only interested in 4 metric counters: wb,wt,rb,rt,outstanding,lwa,lwd,lra,lrd +#define XSPM_DEBUG_SAMPLE_COUNTERS_PER_SLOT 9 /* * LAPC related defs here */ -#define XLAPC_MAX_NUMBER_SLOTS 4 +#define XLAPC_MAX_NUMBER_SLOTS 31 #define XLAPC_STATUS_PER_SLOT 9 /* Metric counters per slot */ @@ -47,15 +63,24 @@ extern "C" { /********************** Definitions: Enums, Structs ***************************/ enum xclDebugReadType { XCL_DEBUG_READ_TYPE_APM = 0, - XCL_DEBUG_READ_TYPE_LAPC = 1 + XCL_DEBUG_READ_TYPE_LAPC = 1, + XCL_DEBUG_READ_TYPE_SPM = 2 }; /* Debug counter results */ typedef struct { - unsigned int WriteBytes[XAPM_MAX_NUMBER_SLOTS]; - unsigned int WriteTranx[XAPM_MAX_NUMBER_SLOTS]; - unsigned int ReadBytes[XAPM_MAX_NUMBER_SLOTS]; - unsigned int ReadTranx[XAPM_MAX_NUMBER_SLOTS]; + unsigned int WriteBytes[XSPM_MAX_NUMBER_SLOTS]; + unsigned int WriteTranx[XSPM_MAX_NUMBER_SLOTS]; + unsigned int ReadBytes[XSPM_MAX_NUMBER_SLOTS]; + unsigned int ReadTranx[XSPM_MAX_NUMBER_SLOTS]; + + unsigned int OutStandCnts[XSPM_MAX_NUMBER_SLOTS]; + unsigned int LastWriteAddr[XSPM_MAX_NUMBER_SLOTS]; + unsigned int LastWriteData[XSPM_MAX_NUMBER_SLOTS]; + unsigned int LastReadAddr[XSPM_MAX_NUMBER_SLOTS]; + unsigned int LastReadData[XSPM_MAX_NUMBER_SLOTS]; + unsigned int NumSlots; + char DevUserName[256]; } xclDebugCountersResults; enum xclCheckerType { @@ -67,6 +92,8 @@ typedef struct { unsigned int OverallStatus[XLAPC_MAX_NUMBER_SLOTS]; unsigned int CumulativeStatus[XLAPC_MAX_NUMBER_SLOTS][4]; unsigned int SnapshotStatus[XLAPC_MAX_NUMBER_SLOTS][4]; + unsigned int NumSlots; + char DevUserName[256]; } xclDebugCheckersResults; #ifdef __cplusplus diff --git a/SDAccel/userspace/include/xcl_app_debug2.h b/SDAccel/userspace/include/xcl_app_debug2.h deleted file mode 100755 index 0c3fb604..00000000 --- a/SDAccel/userspace/include/xcl_app_debug2.h +++ /dev/null @@ -1,102 +0,0 @@ -/** - * Copyright (C) 2016-2018 Xilinx, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -/** - * Xilinx SDAccel HAL userspace driver extension APIs - * Performance Monitoring Exposed Parameters - * Copyright (C) 2015-2018, Xilinx Inc - All rights reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -#ifndef _XCL_DEBUG_H_ -#define _XCL_DEBUG_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/************************ SPM Debug Counters ********************************/ -//debug is only interested in 4 metric counters: wb,wt,rb,rt,outstanding,lwa,lwd,lra,lrd -#define XSPM_DEBUG_SAMPLE_COUNTERS_PER_SLOT 9 - -/* - * LAPC related defs here - */ -#define XLAPC_MAX_NUMBER_SLOTS 31 -#define XLAPC_STATUS_PER_SLOT 9 - -/* Metric counters per slot */ -#define XLAPC_OVERALL_STATUS 0 -#define XLAPC_CUMULATIVE_STATUS_0 1 -#define XLAPC_CUMULATIVE_STATUS_1 2 -#define XLAPC_CUMULATIVE_STATUS_2 3 -#define XLAPC_CUMULATIVE_STATUS_3 4 -#define XLAPC_SNAPSHOT_STATUS_0 5 -#define XLAPC_SNAPSHOT_STATUS_1 6 -#define XLAPC_SNAPSHOT_STATUS_2 7 -#define XLAPC_SNAPSHOT_STATUS_3 8 - -/********************** Definitions: Enums, Structs ***************************/ -enum xclDebugReadType { - XCL_DEBUG_READ_TYPE_APM = 0, - XCL_DEBUG_READ_TYPE_LAPC = 1, - XCL_DEBUG_READ_TYPE_SPM = 2 -}; - -/* Debug counter results */ -typedef struct { - unsigned int WriteBytes[XSPM_MAX_NUMBER_SLOTS]; - unsigned int WriteTranx[XSPM_MAX_NUMBER_SLOTS]; - unsigned int ReadBytes[XSPM_MAX_NUMBER_SLOTS]; - unsigned int ReadTranx[XSPM_MAX_NUMBER_SLOTS]; - - unsigned int OutStandCnts[XSPM_MAX_NUMBER_SLOTS]; - unsigned int LastWriteAddr[XSPM_MAX_NUMBER_SLOTS]; - unsigned int LastWriteData[XSPM_MAX_NUMBER_SLOTS]; - unsigned int LastReadAddr[XSPM_MAX_NUMBER_SLOTS]; - unsigned int LastReadData[XSPM_MAX_NUMBER_SLOTS]; - unsigned int NumSlots; - char DevUserName[256]; -} xclDebugCountersResults; - -enum xclCheckerType { -XCL_CHECKER_MEMORY = 0, -}; - -/* Debug checker results */ -typedef struct { - unsigned int OverallStatus[XLAPC_MAX_NUMBER_SLOTS]; - unsigned int CumulativeStatus[XLAPC_MAX_NUMBER_SLOTS][4]; - unsigned int SnapshotStatus[XLAPC_MAX_NUMBER_SLOTS][4]; - unsigned int NumSlots; - char DevUserName[256]; -} xclDebugCheckersResults; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/SDAccel/userspace/include/xclbin.h b/SDAccel/userspace/include/xclbin.h index f9af178f..c94ee9d1 100644 --- a/SDAccel/userspace/include/xclbin.h +++ b/SDAccel/userspace/include/xclbin.h @@ -1,20 +1,32 @@ /** - * Copyright (C) 2015-2018 Xilinx, Inc + * Copyright (C) 2015-2018 Xilinx, Inc + * Xilinx SDAccel xclbin container definition * - * Xilinx SDAccel xclbin container definition + * This file is dual licensed. It may be redistributed and/or modified + * under the terms of the Apache 2.0 License OR version 2 of the GNU + * General Public License. * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at + * Apache License Verbiage * - * http://www.apache.org/licenses/LICENSE-2.0 + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. -*/ + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * GPL license Verbiage: + * + * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ #ifndef _XCLBIN_H_ #define _XCLBIN_H_ @@ -30,31 +42,32 @@ #include #endif +#define ENABLE_MTAG + #ifdef __cplusplus extern "C" { #endif + /** + * Container format for Xilinx bitstreams, metadata and other + * binary blobs. + * Every segment must be aligned at 8 byte boundary with null byte padding + * between adjacent segments if required. + * For segements which are not present both offset and length must be 0 in + * the header. + * Currently only xclbin0\0 is recognized as file magic. In future if/when file + * format is updated the magic string will be changed to xclbin1\0 and so on. + */ enum XCLBIN_MODE { - // Use with flat flow where the full FPGA is re-programmed XCLBIN_FLAT, - // Used with Partial Reconfig flow XCLBIN_PR, - // Unused at the moment XCLBIN_TANDEM_STAGE2, - // Unused at the moment XCLBIN_TANDEM_STAGE2_WITH_PR, - // Used in HW emulation XCLBIN_HW_EMU, - // Used in SW emulation XCLBIN_SW_EMU, XCLBIN_MODE_MAX }; - /** - * Note that xclBin format has been deprecated from 2017.1 release onwards. - * SDAccel has switched to AXLF also known as xclbin2 -- look for struct axlf - * below. - */ struct xclBin { char m_magic[8]; /* should be xclbin0\0 */ @@ -98,15 +111,35 @@ extern "C" { enum axlf_section_kind { BITSTREAM = 0, - CLEARING_BITSTREAM = 1, - EMBEDDED_METADATA = 2, - FIRMWARE = 3, - DEBUG_DATA = 4 + CLEARING_BITSTREAM, + EMBEDDED_METADATA, + FIRMWARE, + DEBUG_DATA, + SCHED_FIRMWARE, + MEM_TOPOLOGY, + CONNECTIVITY, + IP_LAYOUT, + DEBUG_IP_LAYOUT, + DESIGN_CHECK_POINT + }; + + enum MEM_TYPE { + MEM_DDR3, + MEM_DDR4, + MEM_DRAM, + MEM_STREAMING, + MEM_PREALLOCATED_GLOB, + MEM_ARE //Aurora + }; + + enum IP_TYPE { + IP_MB = 0, + IP_KERNEL //kernel instance }; struct axlf_section_header { uint32_t m_sectionKind; /* Section type */ - char m_sectionName[16]; /* Examples: "stage2", "clear1", "clear2", "ocl1", "ocl2, "ublaze" */ + char m_sectionName[16]; /* Examples: "stage2", "clear1", "clear2", "ocl1", "ocl2, "ublaze", "sched" */ uint64_t m_sectionOffset; /* File offset of section data */ uint64_t m_sectionSize; /* Size of section data */ }; @@ -114,7 +147,7 @@ extern "C" { struct axlf_header { uint64_t m_length; /* Total size of the xclbin file */ uint64_t m_timeStamp; /* Number of seconds since epoch when xclbin was created */ - uint64_t m_featureRomTimeStamp; /* TimeSinceEpoch of the Feature ROM in the DSA */ + uint64_t m_featureRomTimeStamp; /* TimeSinceEpoch of the featureRom */ uint32_t m_version; /* Tool version used to create xclbin */ uint32_t m_mode; /* XCLBIN_MODE */ uint64_t m_platformId; /* 64 bit platform ID: vendor-device-subvendor-subdev */ @@ -127,19 +160,99 @@ extern "C" { struct axlf { char m_magic[8]; /* Should be "xclbin2\0" */ - unsigned char m_cipher[32]; /* HMAC output digest */ + unsigned char m_cipher[32]; /* Hmac output digest */ unsigned char m_keyBlock[256]; /* Signature for validation of binary */ - uint64_t m_uniqueId; /* axlf's uniqueId, use it to skip re-download etc */ + uint64_t m_uniqueId; /* axlf's uniqueId, use it to skip redownload etc */ struct axlf_header m_header; /* Inline header */ struct axlf_section_header m_sections[1]; /* One or more section headers follow */ }; - //xilinx internal + /**** BEGIN : Xilinx internal section *****/ + + /* bitstream information */ struct xlnx_bitstream { uint8_t m_freq[8]; char bits[1]; }; + /**** MEMORY TOPOLOGY SECTION ****/ + struct mem_data { + uint8_t m_type; //enum corresponding to mem_type. + uint8_t m_used; //if 0 this bank is not present + uint64_t m_size; //in KB + uint64_t m_base_address; +#ifdef ENABLE_MTAG + unsigned char m_tag[16]; //Initially: BANK0,1,2,3, has to be null terminated. +#endif + }; + + struct mem_topology { + int32_t m_count; //Number of mem_data + struct mem_data m_mem_data[1]; //Should be sorted on mem_type + }; + + /**** CONNECTIVITY SECTION ****/ + /* Connectivity of each argument of Kernel. It will be in terms of argument + * index associated. For associating kernel instances with arguments and + * banks, start at the connectivity section. Using the m_ip_layout_index + * access the ip_data.m_name. Now we can associate this kernel instance + * with its original kernel name and get the connectivity as well. This + * enables us to form related groups of kernel instances. + */ + + struct connection { + int32_t arg_index; //From 0 to n, may not be contiguous as scalars skipped + int32_t m_ip_layout_index; //index into the ip_layout section. ip_layout.m_ip_data[index].m_type == IP_KERNEL + int32_t mem_data_index; //index of the m_mem_data . Flag error is m_used false. + }; + + struct connectivity { + int32_t m_count; + struct connection m_connection[1]; + }; + + + /**** IP_LAYOUT SECTION ****/ + /* IPs on AXI lite - their types, names, and base addresses.*/ + struct ip_data { + uint32_t m_type; //map to IP_TYPE enum + uint32_t properties; //32 bits to indicate ip specific property. eg if m_type == IP_KERNEL then bit 0 is for interrupt. + uint64_t m_base_address; + uint8_t m_name[64]; //eg Kernel name corresponding to KERNEL instance, can embed CU name in future. + }; + + struct ip_layout { + int32_t m_count; + struct ip_data m_ip_data[1]; //All the ip_data needs to be sorted by m_base_address. + }; + + /*** Debug IP section layout ****/ + enum DEBUG_IP_TYPE { + UNDEFINED = 0, + LAPC, + ILA, + AXI_MM_MONITOR, + AXI_TRACE_FUNNEL, + AXI_MONITOR_FIFO_LITE, + AXI_MONITOR_FIFO_FULL + }; + + struct debug_ip_data { + uint8_t m_type; // type of enum DEBUG_IP_TYPE + uint8_t m_index; + uint8_t m_properties; + uint8_t m_reserved[5]; + uint64_t m_base_address; + uint8_t m_name[128]; + }; + + struct debug_ip_layout { + uint16_t m_count; + struct debug_ip_data m_debug_ip_data[1]; + }; + + /**** END : Xilinx internal section *****/ + # ifdef __cplusplus namespace xclbin { inline const axlf_section_header* diff --git a/SDAccel/userspace/include/xclbin2.h b/SDAccel/userspace/include/xclbin2.h deleted file mode 100644 index c94ee9d1..00000000 --- a/SDAccel/userspace/include/xclbin2.h +++ /dev/null @@ -1,273 +0,0 @@ -/** - * Copyright (C) 2015-2018 Xilinx, Inc - * Xilinx SDAccel xclbin container definition - * - * This file is dual licensed. It may be redistributed and/or modified - * under the terms of the Apache 2.0 License OR version 2 of the GNU - * General Public License. - * - * Apache License Verbiage - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * GPL license Verbiage: - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef _XCLBIN_H_ -#define _XCLBIN_H_ - -#if defined(__KERNEL__) -#include -#elif defined(__cplusplus) -#include -#include -#include -#else -#include -#include -#endif - -#define ENABLE_MTAG - -#ifdef __cplusplus -extern "C" { -#endif - - /** - * Container format for Xilinx bitstreams, metadata and other - * binary blobs. - * Every segment must be aligned at 8 byte boundary with null byte padding - * between adjacent segments if required. - * For segements which are not present both offset and length must be 0 in - * the header. - * Currently only xclbin0\0 is recognized as file magic. In future if/when file - * format is updated the magic string will be changed to xclbin1\0 and so on. - */ - enum XCLBIN_MODE { - XCLBIN_FLAT, - XCLBIN_PR, - XCLBIN_TANDEM_STAGE2, - XCLBIN_TANDEM_STAGE2_WITH_PR, - XCLBIN_HW_EMU, - XCLBIN_SW_EMU, - XCLBIN_MODE_MAX - }; - - - struct xclBin { - char m_magic[8]; /* should be xclbin0\0 */ - uint64_t m_length; /* total size of the xclbin file */ - uint64_t m_timeStamp; /* number of seconds since epoch when xclbin was created */ - uint64_t m_version; /* tool version used to create xclbin */ - unsigned m_mode; /* XCLBIN_MODE */ - char m_nextXclBin[24]; /* Name of next xclbin file in the daisy chain */ - uint64_t m_metadataOffset; /* file offset of embedded metadata */ - uint64_t m_metadataLength; /* size of the embedded metdata */ - uint64_t m_primaryFirmwareOffset; /* file offset of bitstream or emulation archive */ - uint64_t m_primaryFirmwareLength; /* size of the bistream or emulation archive */ - uint64_t m_secondaryFirmwareOffset; /* file offset of clear bitstream if any */ - uint64_t m_secondaryFirmwareLength; /* size of the clear bitstream */ - uint64_t m_driverOffset; /* file offset of embedded device driver if any (currently unused) */ - uint64_t m_driverLength; /* size of the embedded device driver (currently unused) */ - - // Extra debug information for hardware and hardware emulation debug - - uint64_t m_dwarfOffset ; - uint64_t m_dwarfLength ; - uint64_t m_ipiMappingOffset ; - uint64_t m_ipiMappingLength ; - }; - - /* - * AXLF LAYOUT - * ----------- - * - * ----------------------------------------- - * | Magic | - * ----------------------------------------- - * | Header | - * ----------------------------------------- - * | One or more section headers | - * ----------------------------------------- - * | Matching number of sections with data | - * ----------------------------------------- - * - */ - - enum axlf_section_kind { - BITSTREAM = 0, - CLEARING_BITSTREAM, - EMBEDDED_METADATA, - FIRMWARE, - DEBUG_DATA, - SCHED_FIRMWARE, - MEM_TOPOLOGY, - CONNECTIVITY, - IP_LAYOUT, - DEBUG_IP_LAYOUT, - DESIGN_CHECK_POINT - }; - - enum MEM_TYPE { - MEM_DDR3, - MEM_DDR4, - MEM_DRAM, - MEM_STREAMING, - MEM_PREALLOCATED_GLOB, - MEM_ARE //Aurora - }; - - enum IP_TYPE { - IP_MB = 0, - IP_KERNEL //kernel instance - }; - - struct axlf_section_header { - uint32_t m_sectionKind; /* Section type */ - char m_sectionName[16]; /* Examples: "stage2", "clear1", "clear2", "ocl1", "ocl2, "ublaze", "sched" */ - uint64_t m_sectionOffset; /* File offset of section data */ - uint64_t m_sectionSize; /* Size of section data */ - }; - - struct axlf_header { - uint64_t m_length; /* Total size of the xclbin file */ - uint64_t m_timeStamp; /* Number of seconds since epoch when xclbin was created */ - uint64_t m_featureRomTimeStamp; /* TimeSinceEpoch of the featureRom */ - uint32_t m_version; /* Tool version used to create xclbin */ - uint32_t m_mode; /* XCLBIN_MODE */ - uint64_t m_platformId; /* 64 bit platform ID: vendor-device-subvendor-subdev */ - uint64_t m_featureId; /* 64 bit feature id */ - unsigned char m_platformVBNV[64]; /* e.g. xilinx:xil-accel-rd-ku115:4ddr-xpr:3.4: null terminated */ - char m_next_axlf[16]; /* Name of next xclbin file in the daisy chain */ - char m_debug_bin[16]; /* Name of binary with debug information */ - uint32_t m_numSections; /* Number of section headers */ - }; - - struct axlf { - char m_magic[8]; /* Should be "xclbin2\0" */ - unsigned char m_cipher[32]; /* Hmac output digest */ - unsigned char m_keyBlock[256]; /* Signature for validation of binary */ - uint64_t m_uniqueId; /* axlf's uniqueId, use it to skip redownload etc */ - struct axlf_header m_header; /* Inline header */ - struct axlf_section_header m_sections[1]; /* One or more section headers follow */ - }; - - /**** BEGIN : Xilinx internal section *****/ - - /* bitstream information */ - struct xlnx_bitstream { - uint8_t m_freq[8]; - char bits[1]; - }; - - /**** MEMORY TOPOLOGY SECTION ****/ - struct mem_data { - uint8_t m_type; //enum corresponding to mem_type. - uint8_t m_used; //if 0 this bank is not present - uint64_t m_size; //in KB - uint64_t m_base_address; -#ifdef ENABLE_MTAG - unsigned char m_tag[16]; //Initially: BANK0,1,2,3, has to be null terminated. -#endif - }; - - struct mem_topology { - int32_t m_count; //Number of mem_data - struct mem_data m_mem_data[1]; //Should be sorted on mem_type - }; - - /**** CONNECTIVITY SECTION ****/ - /* Connectivity of each argument of Kernel. It will be in terms of argument - * index associated. For associating kernel instances with arguments and - * banks, start at the connectivity section. Using the m_ip_layout_index - * access the ip_data.m_name. Now we can associate this kernel instance - * with its original kernel name and get the connectivity as well. This - * enables us to form related groups of kernel instances. - */ - - struct connection { - int32_t arg_index; //From 0 to n, may not be contiguous as scalars skipped - int32_t m_ip_layout_index; //index into the ip_layout section. ip_layout.m_ip_data[index].m_type == IP_KERNEL - int32_t mem_data_index; //index of the m_mem_data . Flag error is m_used false. - }; - - struct connectivity { - int32_t m_count; - struct connection m_connection[1]; - }; - - - /**** IP_LAYOUT SECTION ****/ - /* IPs on AXI lite - their types, names, and base addresses.*/ - struct ip_data { - uint32_t m_type; //map to IP_TYPE enum - uint32_t properties; //32 bits to indicate ip specific property. eg if m_type == IP_KERNEL then bit 0 is for interrupt. - uint64_t m_base_address; - uint8_t m_name[64]; //eg Kernel name corresponding to KERNEL instance, can embed CU name in future. - }; - - struct ip_layout { - int32_t m_count; - struct ip_data m_ip_data[1]; //All the ip_data needs to be sorted by m_base_address. - }; - - /*** Debug IP section layout ****/ - enum DEBUG_IP_TYPE { - UNDEFINED = 0, - LAPC, - ILA, - AXI_MM_MONITOR, - AXI_TRACE_FUNNEL, - AXI_MONITOR_FIFO_LITE, - AXI_MONITOR_FIFO_FULL - }; - - struct debug_ip_data { - uint8_t m_type; // type of enum DEBUG_IP_TYPE - uint8_t m_index; - uint8_t m_properties; - uint8_t m_reserved[5]; - uint64_t m_base_address; - uint8_t m_name[128]; - }; - - struct debug_ip_layout { - uint16_t m_count; - struct debug_ip_data m_debug_ip_data[1]; - }; - - /**** END : Xilinx internal section *****/ - -# ifdef __cplusplus - namespace xclbin { - inline const axlf_section_header* - get_axlf_section(const axlf* top, axlf_section_kind kind) - { - auto begin = top->m_sections; - auto end = begin + top->m_header.m_numSections; - auto itr = std::find_if(begin,end,[kind](const axlf_section_header& sec) { return sec.m_sectionKind==kind; }); - return (itr!=end) ? &(*itr) : nullptr; - } - } -# endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/SDAccel/userspace/include/xclhal.h b/SDAccel/userspace/include/xclhal.h index f5c8cb3f..1758350a 100644 --- a/SDAccel/userspace/include/xclhal.h +++ b/SDAccel/userspace/include/xclhal.h @@ -1,6 +1,5 @@ -/** +/* * Copyright (C) 2015-2018 Xilinx, Inc - * * Xilinx SDAccel HAL userspace driver APIs * * Licensed under the Apache License, Version 2.0 (the "License"). You may @@ -16,8 +15,8 @@ * under the License. */ -#ifndef _XCL_HAL_H_ -#define _XCL_HAL_H_ +#ifndef _XCL_HAL2_H_ +#define _XCL_HAL2_H_ #ifdef __cplusplus #include @@ -40,320 +39,795 @@ #include "xclperf.h" #include "xcl_app_debug.h" +#include "xclerr.h" #ifdef __cplusplus extern "C" { #endif - typedef void * xclDeviceHandle; - - struct xclBin; - struct axlf; - /** - * Structure used to obtain various bits of information from the device. - */ - - struct xclDeviceInfo2 { - unsigned mMagic; // = 0X586C0C6C; XL OpenCL X->58(ASCII), L->6C(ASCII), O->0 C->C L->6C(ASCII); - char mName[256]; - unsigned short mHALMajorVersion; - unsigned short mHALMinorVersion; - unsigned short mVendorId; - unsigned short mDeviceId; - unsigned short mSubsystemId; - unsigned short mSubsystemVendorId; - unsigned short mDeviceVersion; - size_t mDDRSize; // Size of DDR memory - size_t mDataAlignment; // Minimum data alignment requirement for host buffers - size_t mDDRFreeSize; // Total unused/available DDR memory - size_t mMinTransferSize; // Minimum DMA buffer size - unsigned short mDDRBankCount; - unsigned short mOCLFrequency[4]; - unsigned short mPCIeLinkWidth; - unsigned short mPCIeLinkSpeed; - unsigned short mDMAThreads; - short mOnChipTemp; - short mFanTemp; - unsigned short mVInt; - unsigned short mVAux; - unsigned short mVBram; - float mCurrent; -// unsigned short mCurrent; // Change float to short after driver unification since it changes the ABI - unsigned short mNumClocks; - unsigned short mFanSpeed; - bool mMigCalib; - // More properties here - }; - - enum xclMemoryDomains { - XCL_MEM_HOST_RAM = 0x00000000, - XCL_MEM_DEVICE_RAM = 0x00000001, - XCL_MEM_DEVICE_BRAM = 0x00000002, - XCL_MEM_SVM = 0x00000003, - XCL_MEM_CMA = 0x00000004, - XCL_MEM_DEVICE_REG = 0x00000005 - }; - - enum xclDDRFlags { - XCL_DEVICE_RAM_BANK0 = 0, - XCL_DEVICE_RAM_BANK1 = 1, - XCL_DEVICE_RAM_BANK2 = 2, - XCL_DEVICE_RAM_BANK3 = 3 - }; - - enum xclBRAMFlags { - XCL_DEVICE_BRAM0 = 0, - XCL_DEVICE_BRAM1 = 1, - XCL_DEVICE_BRAM2 = 2, - XCL_DEVICE_BRAM3 = 3, - }; - - /** - * Define address spaces on the device AXI bus. The enums are used in xclRead() and xclWrite() - * to pass relative offsets. - */ - - enum xclAddressSpace { - XCL_ADDR_SPACE_DEVICE_FLAT = 0, // Absolute address space - XCL_ADDR_SPACE_DEVICE_RAM = 1, // Address space for the DDR memory - XCL_ADDR_KERNEL_CTRL = 2, // Address space for the OCL Region control port - XCL_ADDR_SPACE_DEVICE_PERFMON = 3, // Address space for the Performance monitors - XCL_ADDR_SPACE_DEVICE_REG = 4, // Address space for device registers. - XCL_ADDR_SPACE_DEVICE_CHECKER = 5, // Address space for protocol checker - - XCL_ADDR_SPACE_MAX = 8 - }; - - /** - * Defines verbosity levels which are passed to xclOpen during device creation time - */ - - enum xclVerbosityLevel { - XCL_QUIET = 0, - XCL_INFO = 1, - XCL_WARN = 2, - XCL_ERROR = 3 - }; - - enum xclResetKind { - XCL_RESET_KERNEL, - XCL_RESET_FULL - }; - - // VERSION 1.0 APIs - // ---------------- - - /** - * @defgroup devman DEVICE MANAGMENT APIs - * -------------------------------------- - * APIs to open, close, query and program the device - * @{ - */ - - /** - * Open a device and obtain its handle. - * "deviceIndex" is 0 for first device, 1 for the second device and so on - * "logFileName" is optional and if not NULL should be used to log messages - * "level" specifies the verbosity level for the messages being logged to logFileName - */ - - XCL_DRIVER_DLLESPEC xclDeviceHandle xclOpen(unsigned deviceIndex, const char *logFileName, xclVerbosityLevel level); - - /** - * Close an opened device - */ - - XCL_DRIVER_DLLESPEC void xclClose(xclDeviceHandle handle); - - /** - * Obtain various bits of information from the device - */ - - XCL_DRIVER_DLLESPEC int xclGetDeviceInfo2(xclDeviceHandle handle, xclDeviceInfo2 *info); - - /** - * Download bitstream to the device. The bitstream is passed in memory in xclBin format. The bitstream - * may be PR bistream for devices which support PR and full bitstream for devices which require full - * configuration. - */ - - XCL_DRIVER_DLLESPEC int xclLoadXclBin(xclDeviceHandle handle, const xclBin *buffer); - - /** @} */ - - /** - * @defgroup bufman BUFFER MANAGMENT APIs - * -------------------------------------- - * - * Buffer management APIs are used for managing device memory. The board vendors are expected to - * provide a memory manager with the following 4 APIs. The xclCopyXXX functions will be used by - * runtime to migrate buffers between host and device memory. - * @{ - */ - - /** - * Allocate a buffer on the device DDR and return its address - */ - - XCL_DRIVER_DLLESPEC uint64_t xclAllocDeviceBuffer(xclDeviceHandle handle, size_t size); - - /** - * Allocate a buffer on the device DDR bank and return its address - */ - - XCL_DRIVER_DLLESPEC uint64_t xclAllocDeviceBuffer2(xclDeviceHandle handle, size_t size, - xclMemoryDomains domain, - unsigned flags); - - /** - * Free a previously allocated buffer on the device DDR - */ - - XCL_DRIVER_DLLESPEC void xclFreeDeviceBuffer(xclDeviceHandle handle, uint64_t buf); - - /** - * Copy host buffer contents to previously allocated device memory. "seek" specifies how many bytes to skip - * at the beginning of the destination before copying "size" bytes of host buffer. - */ - - XCL_DRIVER_DLLESPEC size_t xclCopyBufferHost2Device(xclDeviceHandle handle, uint64_t dest, - const void *src, size_t size, size_t seek); - - /** - * Copy contents of previously allocated device memory to host buffer. "skip" specifies how many bytes to skip - * from the beginning of the source before copying "size" bytes of device buffer. - */ - - XCL_DRIVER_DLLESPEC size_t xclCopyBufferDevice2Host(xclDeviceHandle handle, void *dest, - uint64_t src, size_t size, size_t skip); - - /** @} */ - - /** - * @defgroup readwrite DEVICE READ AND WRITE APIs - * ---------------------------------------------- - * - * These functions are used to read and write peripherals sitting on the address map. An implementation - * may use these to implement xclCopyXXX functions. OpenCL runtime will be using the BUFFER MANAGEMNT - * APIs described above to manage OpenCL buffers. It would use xclRead/xclWrite to program and manage - * peripherals on the card. For programming the Kernel, OpenCL runtime uses the kernel control register - * map generated by the OpenCL compiler. - * Note that the offset is wrt the address space - * @{ - */ +/** + * DOC: Xilinx Accelerator Hardware Abstraction Library Interface Definitions + * + * Header file *xclhal.h* defines data structures and function signatures exported by + * Hardware Abstraction Library (HAL). HAL is part of software stack which is integrated + * into Xilinx reference platform. + */ + +/** + * typedef xclDeviceHandle - opaque device handle + * + * A device handle of xclDeviceHandle kind is obtained by opening a device. Clients pass this + * device handle to refer to the opened device in all future interaction with HAL. + */ +typedef void * xclDeviceHandle; + +struct xclBin; +struct axlf; + +/** + * Structure used to obtain various bits of information from the device. + */ + +struct xclDeviceInfo2 { + unsigned mMagic; // = 0X586C0C6C; XL OpenCL X->58(ASCII), L->6C(ASCII), O->0 C->C L->6C(ASCII); + char mName[256]; + unsigned short mHALMajorVersion; + unsigned short mHALMinorVersion; + unsigned short mVendorId; + unsigned short mDeviceId; + unsigned short mSubsystemId; + unsigned short mSubsystemVendorId; + unsigned short mDeviceVersion; + size_t mDDRSize; // Size of DDR memory + size_t mDataAlignment; // Minimum data alignment requirement for host buffers + size_t mDDRFreeSize; // Total unused/available DDR memory + size_t mMinTransferSize; // Minimum DMA buffer size + unsigned short mDDRBankCount; + unsigned short mOCLFrequency[4]; + unsigned short mPCIeLinkWidth; + unsigned short mPCIeLinkSpeed; + unsigned short mDMAThreads; + short mOnChipTemp; + short mFanTemp; + unsigned short mVInt; + unsigned short mVAux; + unsigned short mVBram; + float mCurrent; + unsigned short mNumClocks; + unsigned short mFanSpeed; + bool mMigCalib; + // More properties here +}; + +/** + * xclMemoryDomains is for support of legacy APIs + * It is not used in BO APIs where we instead use xclBOKind + */ +enum xclMemoryDomains { + XCL_MEM_HOST_RAM = 0x00000000, + XCL_MEM_DEVICE_RAM = 0x00000001, + XCL_MEM_DEVICE_BRAM = 0x00000002, + XCL_MEM_SVM = 0x00000003, + XCL_MEM_CMA = 0x00000004, + XCL_MEM_DEVICE_REG = 0x00000005 +}; + +/* byte-0 lower 4 bits for DDR Flags are one-hot encoded */ +enum xclDDRFlags { + XCL_DEVICE_RAM_BANK0 = 0x00000000, + XCL_DEVICE_RAM_BANK1 = 0x00000002, + XCL_DEVICE_RAM_BANK2 = 0x00000004, + XCL_DEVICE_RAM_BANK3 = 0x00000008 +}; + +/** + * xclBOKind defines Buffer Object Kind which represents a fragment of device accesible + * memory and the corresponding backing host memory. + * + * 1. Shared virtual memory (SVM) class of systems like CAPI or MPSoc with SMMU. BOs + * have a common host RAM backing store. + * XCL_BO_SHARED_VIRTUAL + * + * 2. Shared physical memory class of systems like Zynq (or MPSoc with pass though SMMU) + * with Linux CMA buffer allocation. BOs have common host CMA allocated backing store. + * XCL_BO_SHARED_PHYSICAL + * + * 3. Shared virtual memory (SVM) class of systems with dedicated RAM and device MMU. BOs + * have a device RAM dedicated backing store and another host RAM allocated backing store. + * The buffers are sync'd via DMA. Both physical buffers use the same virtual address, + * hence giving the effect of SVM. + * XCL_BO_MIRRORED_VIRTUAL + * + * 4. Dedicated memory class of devices like PCIe card with DDR. BOs have a device RAM + * dedicated backing store and another host RAM allocated backing store. The buffers + * are sync'd via DMA + * XCL_BO_DEVICE_RAM + * + * 5. Dedicated onchip memory class of devices like PCIe card with BRAM. BOs have a device + * BRAM dedicated backing store and another host RAM allocated backing store. The buffers + * are sync'd via DMA + * XCL_BO_DEVICE_BRAM + */ + +enum xclBOKind { + XCL_BO_SHARED_VIRTUAL = 0, + XCL_BO_SHARED_PHYSICAL, + XCL_BO_MIRRORED_VIRTUAL, + XCL_BO_DEVICE_RAM, + XCL_BO_DEVICE_BRAM, + XCL_BO_DEVICE_PREALLOCATED_BRAM, +}; + +enum xclBOSyncDirection { + XCL_BO_SYNC_BO_TO_DEVICE = 0, + XCL_BO_SYNC_BO_FROM_DEVICE, +}; + +/** + * Define address spaces on the device AXI bus. The enums are used in xclRead() and xclWrite() + * to pass relative offsets. + */ + +enum xclAddressSpace { + XCL_ADDR_SPACE_DEVICE_FLAT = 0, // Absolute address space + XCL_ADDR_SPACE_DEVICE_RAM = 1, // Address space for the DDR memory + XCL_ADDR_KERNEL_CTRL = 2, // Address space for the OCL Region control port + XCL_ADDR_SPACE_DEVICE_PERFMON = 3, // Address space for the Performance monitors + XCL_ADDR_SPACE_DEVICE_CHECKER = 5, // Address space for protocol checker + XCL_ADDR_SPACE_MAX = 8 +}; + +/** + * Defines verbosity levels which are passed to xclOpen during device creation time + */ + +enum xclVerbosityLevel { + XCL_QUIET = 0, + XCL_INFO = 1, + XCL_WARN = 2, + XCL_ERROR = 3 +}; + +enum xclResetKind { + XCL_RESET_KERNEL, + XCL_RESET_FULL +}; + +struct xclDeviceUsage { + size_t h2c[8]; + size_t c2h[8]; + size_t ddrMemUsed[8]; + unsigned ddrBOAllocated[8]; + unsigned totalContexts; + uint64_t xclbinId[4]; +}; + +struct xclBOProperties { + uint32_t handle; + uint32_t flags; + uint64_t size; + uint64_t paddr; + xclBOKind domain; // not implemented +}; + +/** + * DOC: HAL Device Management APIs + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +/** + * xclProbe() - Enumerate devices found in the system + * + * Return: count of devices found + */ +XCL_DRIVER_DLLESPEC unsigned xclProbe(); + +/** + * xclOpen() - Open a device and obtain its handle. + * + * @deviceIndex: Slot number of device 0 for first device, 1 for the second device... + * @logFileName: Log file to use for optional logging + * @level: Severity level of messages to log + * + * Return: Device handle + */ +XCL_DRIVER_DLLESPEC xclDeviceHandle xclOpen(unsigned deviceIndex, const char *logFileName, + xclVerbosityLevel level); + +/** + * xclClose() - Close an opened device + * + * @handle: Device handle + */ +XCL_DRIVER_DLLESPEC void xclClose(xclDeviceHandle handle); + +/** + * xclResetDevice() - Reset a device or its CL + * + * @handle: Device handle + * @kind: Reset kind +* Return: 0 on success or appropriate error number + * + * Reset the device. All running kernels will be killed and buffers in DDR will be + * purged. A device may be reset if a user's application dies without waiting for + * running kernel(s) to finish. + */ +XCL_DRIVER_DLLESPEC int xclResetDevice(xclDeviceHandle handle, xclResetKind kind); + +/** + * xclGetDeviceInfo2() - Obtain various bits of information from the device + * + * @handle: Device handle + * @info: Information record + * Return: 0 on success or appropriate error number + */ +XCL_DRIVER_DLLESPEC int xclGetDeviceInfo2(xclDeviceHandle handle, xclDeviceInfo2 *info); + +/** + * xclGetUsageInfo() - Obtain usage information from the device + * + * @handle: Device handle + * @info: Information record + * Return: 0 on success or appropriate error number + */ +XCL_DRIVER_DLLESPEC int xclGetUsageInfo(xclDeviceHandle handle, xclDeviceUsage *info); + +/** + * xclGetErrorStatus() - Obtain error information from the device + * + * @handle: Device handle + * @info: Information record + * Return: 0 on success or appropriate error number + */ +XCL_DRIVER_DLLESPEC int xclGetErrorStatus(xclDeviceHandle handle, xclErrorStatus *info); + +/** + * xclLoadXclBin() - Download FPGA image (xclbin) to the device + * + * @handle: Device handle + * @buffer: Pointer to device image (xclbin) in memory + * Return: 0 on success or appropriate error number + * + * Download FPGA image (AXLF) to the device. The PR bitstream is encapsulated inside + * xclbin as a section. xclbin may also contains other sections which are suitably + * handled by the driver. + */ +XCL_DRIVER_DLLESPEC int xclLoadXclBin(xclDeviceHandle handle, const xclBin *buffer); + +/** + * xclReClock2() - Configure PR region frequncies + * + * @handle: Device handle + * @region: PR region (always 0) + * @targetFreqMHz: Array of target frequencies in order for the Clock Wizards driving + * the PR region + * Return: 0 on success or appropriate error number + */ +XCL_DRIVER_DLLESPEC int xclReClock2(xclDeviceHandle handle, unsigned short region, + const unsigned short *targetFreqMHz); + +/** + * xclLockDevice() - Get exclusive ownership of the device + * + * @handle: Device handle + * Return: 0 on success or appropriate error number + * + * The lock is necessary before performing buffer migration, register access or + * bitstream downloads. + */ +XCL_DRIVER_DLLESPEC int xclLockDevice(xclDeviceHandle handle); - XCL_DRIVER_DLLESPEC size_t xclWrite(xclDeviceHandle handle, xclAddressSpace space, uint64_t offset, - const void *hostBuf, size_t size); +/** + * xclUnlockDevice() - Release exclusive ownership of the device + * + * @handle: Device handle + * Return: 0 on success or appropriate error number + */ +XCL_DRIVER_DLLESPEC int xclUnlockDevice(xclDeviceHandle handle); - XCL_DRIVER_DLLESPEC size_t xclRead(xclDeviceHandle handle, xclAddressSpace space, uint64_t offset, - void *hostbuf, size_t size); +/* + * Update the device BPI PROM with new image + */ +XCL_DRIVER_DLLESPEC int xclUpgradeFirmware(xclDeviceHandle handle, const char *fileName); - /** @} */ +/* + * Update the device PROM with new image with clearing bitstream + */ +XCL_DRIVER_DLLESPEC int xclUpgradeFirmware2(xclDeviceHandle handle, const char *file1, const char* file2); - // EXTENSIONS FOR PARTIAL RECONFIG FLOW - // ------------------------------------ - // TODO: Deprecate this. Update the device PROM with new base bitsream - XCL_DRIVER_DLLESPEC int xclUpgradeFirmware(xclDeviceHandle handle, const char *fileName); +/* + * Update the device SPI PROM with new image + */ +XCL_DRIVER_DLLESPEC int xclUpgradeFirmwareXSpi(xclDeviceHandle handle, const char *fileName, int index); - // Update the device PROM with new base bitsream(s). - XCL_DRIVER_DLLESPEC int xclUpgradeFirmware2(xclDeviceHandle handle, const char *file1, const char* file2); +/** + * xclBootFPGA() - Boot the FPGA from PROM + * + * @handle: Device handle + * Return: 0 on success or appropriate error number + * + * This should only be called when there are no other clients. It will cause PCIe bus re-enumeration + */ +XCL_DRIVER_DLLESPEC int xclBootFPGA(xclDeviceHandle handle); - //TODO: Deprecate this. Update the device PROM for XSpi - XCL_DRIVER_DLLESPEC int xclUpgradeFirmwareXSpi(xclDeviceHandle handle, const char *fileName, int index); +/* + * Write to /sys/bus/pci/devices//remove and initiate a pci rescan by + * writing to /sys/bus/pci/rescan. + */ +XCL_DRIVER_DLLESPEC int xclRemoveAndScanFPGA(); - //Test the flash - XCL_DRIVER_DLLESPEC int xclTestXSpi(xclDeviceHandle handle, int slave_index); +/* + * Get the version number. 1 => Hal1 ; 2 => Hal2 + */ +XCL_DRIVER_DLLESPEC unsigned int xclVersion(); - // Boot the FPGA with new bitsream in PROM. This will break the PCIe link and render the device - // unusable till a reboot of the host - XCL_DRIVER_DLLESPEC int xclBootFPGA(xclDeviceHandle handle); +/* End HAL Device Management APIs */ - // NEW APIs in VERSION 1.1 - // ----------------------- +/** + * DOC: HAL Buffer Management APIs + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Buffer management APIs are used for managing device memory and migrating buffers + * between host and device memory + */ - /** - * @addtogroup devman - * @{ - */ +/** + * xclAllocBO() - Allocate a BO of requested size with appropriate flags + * + * @handle: Device handle + * @size: Size of buffer + * @domain: Memory domain + * @flags: Specify bank information, etc + * Return: BO handle + */ +XCL_DRIVER_DLLESPEC unsigned int xclAllocBO(xclDeviceHandle handle, size_t size, xclBOKind domain, + unsigned flags); - /** - * Reset the device. All running kernels will be killed and buffers in DDR will be purged. - * A device would be reset if a user's application dies without waiting for running kernel(s) - * to finish. - */ +/** + * xclAllocUserPtrBO() - Allocate a BO using userptr provided by the user + * + * @handle: Device handle + * @userptr: Pointer to 4K aligned user memory + * @size: Size of buffer + * @flags: Specify bank information, etc + * Return: BO handle + */ +XCL_DRIVER_DLLESPEC unsigned int xclAllocUserPtrBO(xclDeviceHandle handle, void *userptr, size_t size, + unsigned flags); - XCL_DRIVER_DLLESPEC int xclResetDevice(xclDeviceHandle handle, xclResetKind kind); +/** + * xclFreeBO() - Free a previously allocated BO + * + * @handle: Device handle + * @boHandle: BO handle + */ +XCL_DRIVER_DLLESPEC void xclFreeBO(xclDeviceHandle handle, unsigned int boHandle); - /** - * Set the OCL region clock frequencies. Currently only 2 clocks are supported but - * targetFreqMHz should be an array with 4 elements (for 4 clocks). A value of 0 for - * the frequncy indicates that the particular clock frequency should not be changed. - */ +/** + * xclWriteBO() - Copy-in user data to host backing storage of BO + * + * @handle: Device handle + * @boHandle: BO handle + * @src: Source data pointer + * @size: Size of data to copy + * @seek: Offset within the BO + * Return: 0 on success or appropriate error number + * + * Copy host buffer contents to previously allocated device memory. ``seek`` specifies how many bytes + * to skip at the beginning of the BO before copying-in ``size`` bytes of host buffer. + */ +XCL_DRIVER_DLLESPEC size_t xclWriteBO(xclDeviceHandle handle, unsigned int boHandle, + const void *src, size_t size, size_t seek); - XCL_DRIVER_DLLESPEC int xclReClock2(xclDeviceHandle handle, unsigned short region, - const unsigned short *targetFreqMHz); +/** + * xclReadBO() - Copy-out user data from host backing storage of BO + * + * @handle: Device handle + * @boHandle: BO handle + * @dst: Destination data pointer + * @size: Size of data to copy + * @skip: Offset within the BO + * Return: 0 on success or appropriate error number + * + * Copy contents of previously allocated device memory to host buffer. ``skip`` specifies how many bytes + * to skip from the beginning of the BO before copying-out ``size`` bytes of device buffer. + */ +XCL_DRIVER_DLLESPEC size_t xclReadBO(xclDeviceHandle handle, unsigned int boHandle, + void *dst, size_t size, size_t skip); - /** - * Return a count of devices found in the system - */ - XCL_DRIVER_DLLESPEC unsigned xclProbe(); +/** + * xclMapBO() - Memory map BO into user's address space + * + * @handle: Device handle + * @boHandle: BO handle + * @write: READ only or READ/WRITE mapping + * Return: Memory mapped buffer + * + * Map the contents of the buffer object into host memory + * To unmap the buffer call POSIX unmap() on mapped void * pointer returned from xclMapBO + */ +XCL_DRIVER_DLLESPEC void *xclMapBO(xclDeviceHandle handle, unsigned int boHandle, bool write); - /** - * Get exclusive ownership of the device. The lock is necessary before performing buffer - * migration, register access or bitstream downloads. - */ - XCL_DRIVER_DLLESPEC int xclLockDevice(xclDeviceHandle handle); +/** + * xclSyncBO() - Synchronize buffer contents in requested direction + * + * @handle: Device handle + * @boHandle: BO handle + * @dir: To device or from device + * @size: Size of data to synchronize + * @offset: Offset within the BO + * Return: 0 on success or standard errno + * + * Synchronize the buffer contents between host and device. Depending on the memory model this may + * require DMA to/from device or CPU cache flushing/invalidation + */ +XCL_DRIVER_DLLESPEC int xclSyncBO(xclDeviceHandle handle, unsigned int boHandle, xclBOSyncDirection dir, + size_t size, size_t offset); + +/** + * xclExportBO() - Obtain DMA-BUF file descriptor for a BO + * + * @handle: Device handle + * @boHandle: BO handle which needs to be exported + * Return: File handle to the BO or standard errno + * + * Export a BO for import into another device or Linux subsystem which accepts DMA-BUF fd + * This operation is backed by Linux DMA-BUF framework + */ +XCL_DRIVER_DLLESPEC int xclExportBO(xclDeviceHandle handle, unsigned int boHandle); + +/** + * xclImportBO() - Obtain BO handle for a BO represented by DMA-BUF file descriptor + * + * @handle: Device handle + * @fd: File handle to foreign BO owned by another device which needs to be imported + * @flags: Unused + * Return: BO handle of the imported BO + * + * Import a BO exported by another device. * + * This operation is backed by Linux DMA-BUF framework + */ +XCL_DRIVER_DLLESPEC unsigned int xclImportBO(xclDeviceHandle handle, int fd, unsigned flags); + +/** + * xclGetBOProperties() - Obtain xclBOProperties struct for a BO + * + * @handle: Device handle + * @boHandle: BO handle + * @properties: BO properties struct pointer + * Return: 0 on success + * + * This is the prefered method for obtaining BO property information. + */ +XCL_DRIVER_DLLESPEC int xclGetBOProperties(xclDeviceHandle handle, unsigned int boHandle, xclBOProperties *properties); + +/* + * xclGetBOSize() - Retrieve size of a BO + * + * + * @handle: Device handle + * @boHandle: BO handle + * Return size_t size of the BO on success + * + * This API will be deprecated in the future. New clients should use xclGetBOProperties instead + */ +inline XCL_DRIVER_DLLESPEC size_t xclGetBOSize(xclDeviceHandle handle, unsigned int boHandle) +{ + xclBOProperties p; + return !xclGetBOProperties(handle, boHandle, &p) ? (size_t)p.size : -1; +} + +/* + * Get the physical address on the device + * + * This function will be deprecated in the future. New clinets should use xclGetBOProperties instead. + * + * @handle: Device handle + * @boHandle: BO handle + * @return uint64_t address of the BO on success + */ +inline XCL_DRIVER_DLLESPEC uint64_t xclGetDeviceAddr(xclDeviceHandle handle, unsigned int boHandle) +{ + xclBOProperties p; + return !xclGetBOProperties(handle, boHandle, &p) ? p.paddr : -1; +} + +/* End HAL Buffer Management APIs */ + +/** + * DOC: HAL Legacy Buffer Management APIs + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Do *not* develop new features using the following 5 API's. These are for backwards + * compatibility with classic HAL interface and will be deprecated in future. New clients + * should use BO based APIs defined above + * + */ + +/** + * xclAllocDeviceBuffer() - Allocate a buffer on the device + * + * @handle: Device handle + * @size: Size of buffer + * Return: Physical address of buffer on device or 0xFFFFFFFFFFFFFFFF in case of failure + * + * Allocate a buffer on the device DDR and return its address. This API will be deprecated in future. + * Use xclAllocBO() in all new code. + */ +XCL_DRIVER_DLLESPEC uint64_t xclAllocDeviceBuffer(xclDeviceHandle handle, size_t size); + +/** + * xclAllocDeviceBuffer2() - Allocate a buffer on the device on a specific DDR + * + * @handle: Device handle + * @size: Size of buffer + * @domain: Memory domain + * @flags: Desired DDR bank as a bitmap. + * Return: Physical address of buffer on device or 0xFFFFFFFFFFFFFFFF in case of failure + * + * Allocate a buffer on a specific device DDR and return its address. This API will be deprecated in future. + * Use xclAllocBO() in all new code. + */ +XCL_DRIVER_DLLESPEC uint64_t xclAllocDeviceBuffer2(xclDeviceHandle handle, size_t size, + xclMemoryDomains domain, + unsigned flags); + +/** + * xclFreeDeviceBuffer() - Free a previously buffer on the device + * + * @handle: Device handle + * @buf: Physical address of buffer + * + * The physical address should have been previously allocated by xclAllocDeviceBuffe() or xclAllocDeviceBuffer2(). + * The address should point to the beginning of the buffer and not at an offset in the buffer. This API will + * be deprecated in future. Use xclFreeBO() together with BO allocation APIs. + */ +XCL_DRIVER_DLLESPEC void xclFreeDeviceBuffer(xclDeviceHandle handle, uint64_t buf); + +/** + * xclCopyBufferHost2Device() - Write to device memory + * + * @handle: Device handle + * @dest: Physical address in the device + * @src: Source buffer pointer + * @size: Size of data to synchronize + * @seek: Seek within the segment pointed to physical address + * Return: Size of data moved or standard error number + * + * Copy host buffer contents to previously allocated device memory. ``seek`` specifies how many bytes to skip + * at the beginning of the destination before copying ``size`` bytes of host buffer. This API will be + * deprecated in future. Use xclSyncBO() together with other BO APIs. + */ +XCL_DRIVER_DLLESPEC size_t xclCopyBufferHost2Device(xclDeviceHandle handle, uint64_t dest, + const void *src, size_t size, size_t seek); + +/** + * xclCopyBufferDevice2Host() - Read from device memory + * + * @handle: Device handle + * @dest: Destination buffer pointer + * @src: Physical address in the device + * @size: Size of data to synchronize + * @skip: Skip within the segment pointed to physical address + * Return: Size of data moved or standard error number + * + * Copy contents of previously allocated device memory to host buffer. ``skip`` specifies how many bytes to skip + * from the beginning of the source before copying ``size`` bytes of device buffer. This API will be + * deprecated in future. Use xclSyncBO() together with other BO APIs. + */ +XCL_DRIVER_DLLESPEC size_t xclCopyBufferDevice2Host(xclDeviceHandle handle, void *dest, + uint64_t src, size_t size, size_t skip); + +/* End HAL Legacy Buffer Management APIs */ + + +/** + * DOC: HAL Unmanaged DMA APIs + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Unmanaged DMA APIs are for exclusive use by the debuggers and tools. The APIs allow clinets to read/write + * from/to absolute device address. No checks are performed if a buffer was allocated before at the specified + * location or if the address is valid. Users who want to take over the full memory managemnt of the device + * may use this API to synchronize their buffers between host and device. + */ + +/** + * xclUnmgdPread() - Perform unmanaged device memory read operation + * + * @handle: Device handle + * @flags: Unused + * @buf: Destination data pointer + * @size: Size of data to copy + * @offset: Absolute offset inside device + * Return: size of bytes read or appropriate error number + * + * This API may be used to perform DMA operation from absolute location specified. Users + * may use this if they want to perform their own device memory management -- not using the buffer + * object (BO) framework defined before. + */ +XCL_DRIVER_DLLESPEC ssize_t xclUnmgdPread(xclDeviceHandle handle, unsigned flags, void *buf, + size_t size, uint64_t offset); + +/** + * xclUnmgdPwrite() - Perform unmanaged device memory read operation + * + * @handle: Device handle + * @flags: Unused + * @buf: Source data pointer + * @size: Size of data to copy + * @offset: Absolute offset inside device + * Return: size of bytes written or appropriate error number + * + * This API may be used to perform DMA operation to an absolute location specified. Users + * may use this if they want to perform their own device memory management -- not using the buffer + * object (BO) framework defined before. + */ +XCL_DRIVER_DLLESPEC ssize_t xclUnmgdPwrite(xclDeviceHandle handle, unsigned flags, const void *buf, + size_t size, uint64_t offset); + +/* End HAL Unmanaged DMA APIs */ + +/* + * DOC: HAL Register read/write APIs + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * These functions are used to read and write peripherals sitting on the address map. OpenCL runtime + * will be using the BUFFER MANAGEMNT APIs described above to manage OpenCL buffers. It would use + * xclRead/xclWrite to program and manage peripherals on the card. For programming the Kernel, OpenCL + * runtime uses the kernel control register map generated by the xocc compiler. + * Note that the offset is wrt the address space. + */ + +/** + * xclWrite() - Perform register write operation + * + * @handle: Device handle + * @space: Address space + * @offset: Offset in the address space + * @hostBuf: Source data pointer + * @size: Size of data to copy + * Return: size of bytes written or appropriate error number + * + * This API may be used to write to device registers exposed on PCIe BAR. Offset is relative to the + * the address space. A device may have many address spaces. + */ + +XCL_DRIVER_DLLESPEC size_t xclWrite(xclDeviceHandle handle, xclAddressSpace space, uint64_t offset, + const void *hostBuf, size_t size); + +/** + * xclRead() - Perform register read operation + * + * @handle: Device handle + * @space: Address space + * @offset: Offset in the address space + * @hostbuf: Destination data pointer + * @size: Size of data to copy + * Return: size of bytes written or appropriate error number + * + * This API may be used to read from device registers exposed on PCIe BAR. Offset is relative to the + * the address space. A device may have many address spaces. + */ +XCL_DRIVER_DLLESPEC size_t xclRead(xclDeviceHandle handle, xclAddressSpace space, uint64_t offset, + void *hostbuf, size_t size); + +/* HAL Register read/write APIs */ + +/* + * TODO: + * Define the following APIs + * + * 1. Host accessible pipe APIs: pread/pwrite + * 2. Accelerator status, start, stop APIs + * 3. Context creation APIs to support multiple clients + * 4. Multiple OCL Region support + * 5. DPDK style buffer management and device polling + * + */ + +/** + * DOC: HAL Compute Unit Execution Management APIs + * + * These APIs are under development. These functions will be used to start compute + * units and wait for them to finish. + */ + +/** + * xclExecBuf() - Submit an execution request to the embedded (or software) scheduler + * + * @handle: Device handle + * @cmdBO: BO handle containing command packet + * Return: 0 or standard error number + * + * This API is EXPERIMENTAL in this release. Submit an exec buffer for execution. The exec + * buffer layout is defined by struct ert_packet which is defined in file *ert.h*. The BO + * should been allocated with DRM_XOCL_BO_EXECBUF flag. + */ +XCL_DRIVER_DLLESPEC int xclExecBuf(xclDeviceHandle handle, unsigned int cmdBO); + +/** + * xclExecWait() - Wait for one or more execution events on the device + * + * @handle: Device handle + * @timeoutMilliSec: How long to wait for + * Return: Same code as poll system call + * + * This API is EXPERIMENTAL in this release + * Wait for notification from the hardware. The function essentially calls "poll" system + * call on the driver file handle. The return value has same semantics as poll system call. + * If return value is > 0 caller should check the status of submitted exec buffers + */ +XCL_DRIVER_DLLESPEC int xclExecWait(xclDeviceHandle handle, int timeoutMilliSec); + +/** + * xclRegisterInterruptNotify() - register *eventfd* file handle for a MSIX interrupt + * + * @handle: Device handle + * @userInterrupt: MSIX interrupt number + * @fd: Eventfd handle + * Return: 0 on success or standard errno + * + * Support for non managed interrupts (interrupts from custom IPs). fd should be obtained from + * eventfd system call. Caller should use standard poll/read eventfd framework in order to wait for + * interrupts. The handles are automatically unregistered on process exit. + */ +XCL_DRIVER_DLLESPEC int xclRegisterInterruptNotify(xclDeviceHandle handle, unsigned int userInterrupt, int fd); + +/* HAL Compute Unit Execution Management APIs */ + +/** + * @defgroup perfmon PERFORMANCE MONITORING OPERATIONS + * --------------------------------------------------- + * + * These functions are used to read and write to the performance monitoring infrastructure. + * OpenCL runtime will be using the BUFFER MANAGEMNT APIs described above to manage OpenCL buffers. + * It would use these functions to initialize and sample the performance monitoring on the card. + * Note that the offset is wrt the address space + */ - /** @} */ +/* Write host event to device tracing (Zynq only) */ +XCL_DRIVER_DLLESPEC void xclWriteHostEvent(xclDeviceHandle handle, xclPerfMonEventType type, + xclPerfMonEventID id); - /** - * @defgroup perfmon PERFORMANCE MONITORING OPERATIONS - * --------------------------------------------------- - * - * These functions are used to read and write to the performance monitoring infrastructure. - * OpenCL runtime will be using the BUFFER MANAGEMNT APIs described above to manage OpenCL buffers. - * It would use these functions to initialize and sample the performance monitoring on the card. - * Note that the offset is wrt the address space - */ +XCL_DRIVER_DLLESPEC size_t xclGetDeviceTimestamp(xclDeviceHandle handle); - /* Write host event to device tracing (Zynq only) */ - XCL_DRIVER_DLLESPEC void xclWriteHostEvent(xclDeviceHandle handle, xclPerfMonEventType type, - xclPerfMonEventID id); +XCL_DRIVER_DLLESPEC double xclGetDeviceClockFreqMHz(xclDeviceHandle handle); - XCL_DRIVER_DLLESPEC size_t xclGetDeviceTimestamp(xclDeviceHandle handle); +XCL_DRIVER_DLLESPEC double xclGetReadMaxBandwidthMBps(xclDeviceHandle handle); - XCL_DRIVER_DLLESPEC double xclGetDeviceClockFreqMHz(xclDeviceHandle handle); +XCL_DRIVER_DLLESPEC double xclGetWriteMaxBandwidthMBps(xclDeviceHandle handle); - XCL_DRIVER_DLLESPEC double xclGetReadMaxBandwidthMBps(xclDeviceHandle handle); +XCL_DRIVER_DLLESPEC void xclSetProfilingNumberSlots(xclDeviceHandle handle, xclPerfMonType type, + uint32_t numSlots); - XCL_DRIVER_DLLESPEC double xclGetWriteMaxBandwidthMBps(xclDeviceHandle handle); +XCL_DRIVER_DLLESPEC uint32_t xclGetProfilingNumberSlots(xclDeviceHandle handle, xclPerfMonType type); - XCL_DRIVER_DLLESPEC void xclSetOclRegionProfilingNumberSlots(xclDeviceHandle handle, - uint32_t numSlots); +XCL_DRIVER_DLLESPEC void xclGetProfilingSlotName(xclDeviceHandle handle, xclPerfMonType type, + uint32_t slotnum, char* slotName, uint32_t length); - XCL_DRIVER_DLLESPEC size_t xclPerfMonClockTraining(xclDeviceHandle handle, xclPerfMonType type); +XCL_DRIVER_DLLESPEC size_t xclPerfMonClockTraining(xclDeviceHandle handle, xclPerfMonType type); - XCL_DRIVER_DLLESPEC size_t xclPerfMonStartCounters(xclDeviceHandle handle, xclPerfMonType type); +XCL_DRIVER_DLLESPEC size_t xclPerfMonStartCounters(xclDeviceHandle handle, xclPerfMonType type); - XCL_DRIVER_DLLESPEC size_t xclPerfMonStopCounters(xclDeviceHandle handle, xclPerfMonType type); +XCL_DRIVER_DLLESPEC size_t xclPerfMonStopCounters(xclDeviceHandle handle, xclPerfMonType type); - XCL_DRIVER_DLLESPEC size_t xclPerfMonReadCounters(xclDeviceHandle handle, xclPerfMonType type, - xclCounterResults& counterResults); +XCL_DRIVER_DLLESPEC size_t xclPerfMonReadCounters(xclDeviceHandle handle, xclPerfMonType type, + xclCounterResults& counterResults); - XCL_DRIVER_DLLESPEC size_t xclDebugReadIPStatus(xclDeviceHandle handle, xclDebugReadType type, - void* debugResults); +XCL_DRIVER_DLLESPEC size_t xclDebugReadIPStatus(xclDeviceHandle handle, xclDebugReadType type, + void* debugResults); - XCL_DRIVER_DLLESPEC size_t xclPerfMonStartTrace(xclDeviceHandle handle, xclPerfMonType type, - uint32_t startTrigger); +XCL_DRIVER_DLLESPEC size_t xclPerfMonStartTrace(xclDeviceHandle handle, xclPerfMonType type, + uint32_t startTrigger); - XCL_DRIVER_DLLESPEC size_t xclPerfMonStopTrace(xclDeviceHandle handle, xclPerfMonType type); +XCL_DRIVER_DLLESPEC size_t xclPerfMonStopTrace(xclDeviceHandle handle, xclPerfMonType type); - XCL_DRIVER_DLLESPEC uint32_t xclPerfMonGetTraceCount(xclDeviceHandle handle, xclPerfMonType type); +XCL_DRIVER_DLLESPEC uint32_t xclPerfMonGetTraceCount(xclDeviceHandle handle, xclPerfMonType type); - XCL_DRIVER_DLLESPEC size_t xclPerfMonReadTrace(xclDeviceHandle handle, xclPerfMonType type, - xclTraceResultsVector& traceVector); +XCL_DRIVER_DLLESPEC size_t xclPerfMonReadTrace(xclDeviceHandle handle, xclPerfMonType type, + xclTraceResultsVector& traceVector); - /** @} */ +/** @} */ #ifdef __cplusplus } diff --git a/SDAccel/userspace/include/xclhal2.h b/SDAccel/userspace/include/xclhal2.h deleted file mode 100644 index eed9198c..00000000 --- a/SDAccel/userspace/include/xclhal2.h +++ /dev/null @@ -1,836 +0,0 @@ -/* - * Copyright (C) 2015-2018 Xilinx, Inc - * Xilinx SDAccel HAL userspace driver APIs - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -#ifndef _XCL_HAL2_H_ -#define _XCL_HAL2_H_ - -#ifdef __cplusplus -#include -#include -#else -#include -#include -#endif - -#if defined(_WIN32) -#ifdef XCL_DRIVER_DLL_EXPORT -#define XCL_DRIVER_DLLESPEC __declspec(dllexport) -#else -#define XCL_DRIVER_DLLESPEC __declspec(dllimport) -#endif -#else -#define XCL_DRIVER_DLLESPEC __attribute__((visibility("default"))) -#endif - - -#include "xclperf2.h" -#include "xcl_app_debug2.h" -#include "xclerr.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * DOC: Xilinx Accelerator Hardware Abstraction Library Interface Definitions - * - * Header file *xclhal2.h* defines data structures and function signatures exported by - * Hardware Abstraction Library (HAL). HAL is part of software stack which is integrated - * into Xilinx reference platform. - */ - -/** - * typedef xclDeviceHandle - opaque device handle - * - * A device handle of xclDeviceHandle kind is obtained by opening a device. Clients pass this - * device handle to refer to the opened device in all future interaction with HAL. - */ -typedef void * xclDeviceHandle; - -struct xclBin; -struct axlf; - -/** - * Structure used to obtain various bits of information from the device. - */ - -struct xclDeviceInfo2 { - unsigned mMagic; // = 0X586C0C6C; XL OpenCL X->58(ASCII), L->6C(ASCII), O->0 C->C L->6C(ASCII); - char mName[256]; - unsigned short mHALMajorVersion; - unsigned short mHALMinorVersion; - unsigned short mVendorId; - unsigned short mDeviceId; - unsigned short mSubsystemId; - unsigned short mSubsystemVendorId; - unsigned short mDeviceVersion; - size_t mDDRSize; // Size of DDR memory - size_t mDataAlignment; // Minimum data alignment requirement for host buffers - size_t mDDRFreeSize; // Total unused/available DDR memory - size_t mMinTransferSize; // Minimum DMA buffer size - unsigned short mDDRBankCount; - unsigned short mOCLFrequency[4]; - unsigned short mPCIeLinkWidth; - unsigned short mPCIeLinkSpeed; - unsigned short mDMAThreads; - short mOnChipTemp; - short mFanTemp; - unsigned short mVInt; - unsigned short mVAux; - unsigned short mVBram; - float mCurrent; - unsigned short mNumClocks; - unsigned short mFanSpeed; - bool mMigCalib; - // More properties here -}; - -/** - * xclMemoryDomains is for support of legacy APIs - * It is not used in BO APIs where we instead use xclBOKind - */ -enum xclMemoryDomains { - XCL_MEM_HOST_RAM = 0x00000000, - XCL_MEM_DEVICE_RAM = 0x00000001, - XCL_MEM_DEVICE_BRAM = 0x00000002, - XCL_MEM_SVM = 0x00000003, - XCL_MEM_CMA = 0x00000004, - XCL_MEM_DEVICE_REG = 0x00000005 -}; - -/* byte-0 lower 4 bits for DDR Flags are one-hot encoded */ -enum xclDDRFlags { - XCL_DEVICE_RAM_BANK0 = 0x00000000, - XCL_DEVICE_RAM_BANK1 = 0x00000002, - XCL_DEVICE_RAM_BANK2 = 0x00000004, - XCL_DEVICE_RAM_BANK3 = 0x00000008 -}; - -/** - * xclBOKind defines Buffer Object Kind which represents a fragment of device accesible - * memory and the corresponding backing host memory. - * - * 1. Shared virtual memory (SVM) class of systems like CAPI or MPSoc with SMMU. BOs - * have a common host RAM backing store. - * XCL_BO_SHARED_VIRTUAL - * - * 2. Shared physical memory class of systems like Zynq (or MPSoc with pass though SMMU) - * with Linux CMA buffer allocation. BOs have common host CMA allocated backing store. - * XCL_BO_SHARED_PHYSICAL - * - * 3. Shared virtual memory (SVM) class of systems with dedicated RAM and device MMU. BOs - * have a device RAM dedicated backing store and another host RAM allocated backing store. - * The buffers are sync'd via DMA. Both physical buffers use the same virtual address, - * hence giving the effect of SVM. - * XCL_BO_MIRRORED_VIRTUAL - * - * 4. Dedicated memory class of devices like PCIe card with DDR. BOs have a device RAM - * dedicated backing store and another host RAM allocated backing store. The buffers - * are sync'd via DMA - * XCL_BO_DEVICE_RAM - * - * 5. Dedicated onchip memory class of devices like PCIe card with BRAM. BOs have a device - * BRAM dedicated backing store and another host RAM allocated backing store. The buffers - * are sync'd via DMA - * XCL_BO_DEVICE_BRAM - */ - -enum xclBOKind { - XCL_BO_SHARED_VIRTUAL = 0, - XCL_BO_SHARED_PHYSICAL, - XCL_BO_MIRRORED_VIRTUAL, - XCL_BO_DEVICE_RAM, - XCL_BO_DEVICE_BRAM, - XCL_BO_DEVICE_PREALLOCATED_BRAM, -}; - -enum xclBOSyncDirection { - XCL_BO_SYNC_BO_TO_DEVICE = 0, - XCL_BO_SYNC_BO_FROM_DEVICE, -}; - -/** - * Define address spaces on the device AXI bus. The enums are used in xclRead() and xclWrite() - * to pass relative offsets. - */ - -enum xclAddressSpace { - XCL_ADDR_SPACE_DEVICE_FLAT = 0, // Absolute address space - XCL_ADDR_SPACE_DEVICE_RAM = 1, // Address space for the DDR memory - XCL_ADDR_KERNEL_CTRL = 2, // Address space for the OCL Region control port - XCL_ADDR_SPACE_DEVICE_PERFMON = 3, // Address space for the Performance monitors - XCL_ADDR_SPACE_DEVICE_CHECKER = 5, // Address space for protocol checker - XCL_ADDR_SPACE_MAX = 8 -}; - -/** - * Defines verbosity levels which are passed to xclOpen during device creation time - */ - -enum xclVerbosityLevel { - XCL_QUIET = 0, - XCL_INFO = 1, - XCL_WARN = 2, - XCL_ERROR = 3 -}; - -enum xclResetKind { - XCL_RESET_KERNEL, - XCL_RESET_FULL -}; - -struct xclDeviceUsage { - size_t h2c[8]; - size_t c2h[8]; - size_t ddrMemUsed[8]; - unsigned ddrBOAllocated[8]; - unsigned totalContexts; - uint64_t xclbinId[4]; -}; - -struct xclBOProperties { - uint32_t handle; - uint32_t flags; - uint64_t size; - uint64_t paddr; - xclBOKind domain; // not implemented -}; - -/** - * DOC: HAL Device Management APIs - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -/** - * xclProbe() - Enumerate devices found in the system - * - * Return: count of devices found - */ -XCL_DRIVER_DLLESPEC unsigned xclProbe(); - -/** - * xclOpen() - Open a device and obtain its handle. - * - * @deviceIndex: Slot number of device 0 for first device, 1 for the second device... - * @logFileName: Log file to use for optional logging - * @level: Severity level of messages to log - * - * Return: Device handle - */ -XCL_DRIVER_DLLESPEC xclDeviceHandle xclOpen(unsigned deviceIndex, const char *logFileName, - xclVerbosityLevel level); - -/** - * xclClose() - Close an opened device - * - * @handle: Device handle - */ -XCL_DRIVER_DLLESPEC void xclClose(xclDeviceHandle handle); - -/** - * xclResetDevice() - Reset a device or its CL - * - * @handle: Device handle - * @kind: Reset kind -* Return: 0 on success or appropriate error number - * - * Reset the device. All running kernels will be killed and buffers in DDR will be - * purged. A device may be reset if a user's application dies without waiting for - * running kernel(s) to finish. - */ -XCL_DRIVER_DLLESPEC int xclResetDevice(xclDeviceHandle handle, xclResetKind kind); - -/** - * xclGetDeviceInfo2() - Obtain various bits of information from the device - * - * @handle: Device handle - * @info: Information record - * Return: 0 on success or appropriate error number - */ -XCL_DRIVER_DLLESPEC int xclGetDeviceInfo2(xclDeviceHandle handle, xclDeviceInfo2 *info); - -/** - * xclGetUsageInfo() - Obtain usage information from the device - * - * @handle: Device handle - * @info: Information record - * Return: 0 on success or appropriate error number - */ -XCL_DRIVER_DLLESPEC int xclGetUsageInfo(xclDeviceHandle handle, xclDeviceUsage *info); - -/** - * xclGetErrorStatus() - Obtain error information from the device - * - * @handle: Device handle - * @info: Information record - * Return: 0 on success or appropriate error number - */ -XCL_DRIVER_DLLESPEC int xclGetErrorStatus(xclDeviceHandle handle, xclErrorStatus *info); - -/** - * xclLoadXclBin() - Download FPGA image (xclbin) to the device - * - * @handle: Device handle - * @buffer: Pointer to device image (xclbin) in memory - * Return: 0 on success or appropriate error number - * - * Download FPGA image (AXLF) to the device. The PR bitstream is encapsulated inside - * xclbin as a section. xclbin may also contains other sections which are suitably - * handled by the driver. - */ -XCL_DRIVER_DLLESPEC int xclLoadXclBin(xclDeviceHandle handle, const xclBin *buffer); - -/** - * xclReClock2() - Configure PR region frequncies - * - * @handle: Device handle - * @region: PR region (always 0) - * @targetFreqMHz: Array of target frequencies in order for the Clock Wizards driving - * the PR region - * Return: 0 on success or appropriate error number - */ -XCL_DRIVER_DLLESPEC int xclReClock2(xclDeviceHandle handle, unsigned short region, - const unsigned short *targetFreqMHz); - -/** - * xclLockDevice() - Get exclusive ownership of the device - * - * @handle: Device handle - * Return: 0 on success or appropriate error number - * - * The lock is necessary before performing buffer migration, register access or - * bitstream downloads. - */ -XCL_DRIVER_DLLESPEC int xclLockDevice(xclDeviceHandle handle); - -/** - * xclUnlockDevice() - Release exclusive ownership of the device - * - * @handle: Device handle - * Return: 0 on success or appropriate error number - */ -XCL_DRIVER_DLLESPEC int xclUnlockDevice(xclDeviceHandle handle); - -/* - * Update the device BPI PROM with new image - */ -XCL_DRIVER_DLLESPEC int xclUpgradeFirmware(xclDeviceHandle handle, const char *fileName); - -/* - * Update the device PROM with new image with clearing bitstream - */ -XCL_DRIVER_DLLESPEC int xclUpgradeFirmware2(xclDeviceHandle handle, const char *file1, const char* file2); - -/* - * Update the device SPI PROM with new image - */ -XCL_DRIVER_DLLESPEC int xclUpgradeFirmwareXSpi(xclDeviceHandle handle, const char *fileName, int index); - -/** - * xclBootFPGA() - Boot the FPGA from PROM - * - * @handle: Device handle - * Return: 0 on success or appropriate error number - * - * This should only be called when there are no other clients. It will cause PCIe bus re-enumeration - */ -XCL_DRIVER_DLLESPEC int xclBootFPGA(xclDeviceHandle handle); - -/* - * Write to /sys/bus/pci/devices//remove and initiate a pci rescan by - * writing to /sys/bus/pci/rescan. - */ -XCL_DRIVER_DLLESPEC int xclRemoveAndScanFPGA(); - -/* - * Get the version number. 1 => Hal1 ; 2 => Hal2 - */ -XCL_DRIVER_DLLESPEC unsigned int xclVersion(); - -/* End HAL Device Management APIs */ - -/** - * DOC: HAL Buffer Management APIs - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Buffer management APIs are used for managing device memory and migrating buffers - * between host and device memory - */ - -/** - * xclAllocBO() - Allocate a BO of requested size with appropriate flags - * - * @handle: Device handle - * @size: Size of buffer - * @domain: Memory domain - * @flags: Specify bank information, etc - * Return: BO handle - */ -XCL_DRIVER_DLLESPEC unsigned int xclAllocBO(xclDeviceHandle handle, size_t size, xclBOKind domain, - unsigned flags); - -/** - * xclAllocUserPtrBO() - Allocate a BO using userptr provided by the user - * - * @handle: Device handle - * @userptr: Pointer to 4K aligned user memory - * @size: Size of buffer - * @flags: Specify bank information, etc - * Return: BO handle - */ -XCL_DRIVER_DLLESPEC unsigned int xclAllocUserPtrBO(xclDeviceHandle handle, void *userptr, size_t size, - unsigned flags); - -/** - * xclFreeBO() - Free a previously allocated BO - * - * @handle: Device handle - * @boHandle: BO handle - */ -XCL_DRIVER_DLLESPEC void xclFreeBO(xclDeviceHandle handle, unsigned int boHandle); - -/** - * xclWriteBO() - Copy-in user data to host backing storage of BO - * - * @handle: Device handle - * @boHandle: BO handle - * @src: Source data pointer - * @size: Size of data to copy - * @seek: Offset within the BO - * Return: 0 on success or appropriate error number - * - * Copy host buffer contents to previously allocated device memory. ``seek`` specifies how many bytes - * to skip at the beginning of the BO before copying-in ``size`` bytes of host buffer. - */ -XCL_DRIVER_DLLESPEC size_t xclWriteBO(xclDeviceHandle handle, unsigned int boHandle, - const void *src, size_t size, size_t seek); - -/** - * xclReadBO() - Copy-out user data from host backing storage of BO - * - * @handle: Device handle - * @boHandle: BO handle - * @dst: Destination data pointer - * @size: Size of data to copy - * @skip: Offset within the BO - * Return: 0 on success or appropriate error number - * - * Copy contents of previously allocated device memory to host buffer. ``skip`` specifies how many bytes - * to skip from the beginning of the BO before copying-out ``size`` bytes of device buffer. - */ -XCL_DRIVER_DLLESPEC size_t xclReadBO(xclDeviceHandle handle, unsigned int boHandle, - void *dst, size_t size, size_t skip); - -/** - * xclMapBO() - Memory map BO into user's address space - * - * @handle: Device handle - * @boHandle: BO handle - * @write: READ only or READ/WRITE mapping - * Return: Memory mapped buffer - * - * Map the contents of the buffer object into host memory - * To unmap the buffer call POSIX unmap() on mapped void * pointer returned from xclMapBO - */ -XCL_DRIVER_DLLESPEC void *xclMapBO(xclDeviceHandle handle, unsigned int boHandle, bool write); - -/** - * xclSyncBO() - Synchronize buffer contents in requested direction - * - * @handle: Device handle - * @boHandle: BO handle - * @dir: To device or from device - * @size: Size of data to synchronize - * @offset: Offset within the BO - * Return: 0 on success or standard errno - * - * Synchronize the buffer contents between host and device. Depending on the memory model this may - * require DMA to/from device or CPU cache flushing/invalidation - */ -XCL_DRIVER_DLLESPEC int xclSyncBO(xclDeviceHandle handle, unsigned int boHandle, xclBOSyncDirection dir, - size_t size, size_t offset); - -/** - * xclExportBO() - Obtain DMA-BUF file descriptor for a BO - * - * @handle: Device handle - * @boHandle: BO handle which needs to be exported - * Return: File handle to the BO or standard errno - * - * Export a BO for import into another device or Linux subsystem which accepts DMA-BUF fd - * This operation is backed by Linux DMA-BUF framework - */ -XCL_DRIVER_DLLESPEC int xclExportBO(xclDeviceHandle handle, unsigned int boHandle); - -/** - * xclImportBO() - Obtain BO handle for a BO represented by DMA-BUF file descriptor - * - * @handle: Device handle - * @fd: File handle to foreign BO owned by another device which needs to be imported - * @flags: Unused - * Return: BO handle of the imported BO - * - * Import a BO exported by another device. * - * This operation is backed by Linux DMA-BUF framework - */ -XCL_DRIVER_DLLESPEC unsigned int xclImportBO(xclDeviceHandle handle, int fd, unsigned flags); - -/** - * xclGetBOProperties() - Obtain xclBOProperties struct for a BO - * - * @handle: Device handle - * @boHandle: BO handle - * @properties: BO properties struct pointer - * Return: 0 on success - * - * This is the prefered method for obtaining BO property information. - */ -XCL_DRIVER_DLLESPEC int xclGetBOProperties(xclDeviceHandle handle, unsigned int boHandle, xclBOProperties *properties); - -/* - * xclGetBOSize() - Retrieve size of a BO - * - * - * @handle: Device handle - * @boHandle: BO handle - * Return size_t size of the BO on success - * - * This API will be deprecated in the future. New clients should use xclGetBOProperties instead - */ -inline XCL_DRIVER_DLLESPEC size_t xclGetBOSize(xclDeviceHandle handle, unsigned int boHandle) -{ - xclBOProperties p; - return !xclGetBOProperties(handle, boHandle, &p) ? (size_t)p.size : -1; -} - -/* - * Get the physical address on the device - * - * This function will be deprecated in the future. New clinets should use xclGetBOProperties instead. - * - * @handle: Device handle - * @boHandle: BO handle - * @return uint64_t address of the BO on success - */ -inline XCL_DRIVER_DLLESPEC uint64_t xclGetDeviceAddr(xclDeviceHandle handle, unsigned int boHandle) -{ - xclBOProperties p; - return !xclGetBOProperties(handle, boHandle, &p) ? p.paddr : -1; -} - -/* End HAL Buffer Management APIs */ - -/** - * DOC: HAL Legacy Buffer Management APIs - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Do *not* develop new features using the following 5 API's. These are for backwards - * compatibility with classic HAL interface and will be deprecated in future. New clients - * should use BO based APIs defined above - * - */ - -/** - * xclAllocDeviceBuffer() - Allocate a buffer on the device - * - * @handle: Device handle - * @size: Size of buffer - * Return: Physical address of buffer on device or 0xFFFFFFFFFFFFFFFF in case of failure - * - * Allocate a buffer on the device DDR and return its address. This API will be deprecated in future. - * Use xclAllocBO() in all new code. - */ -XCL_DRIVER_DLLESPEC uint64_t xclAllocDeviceBuffer(xclDeviceHandle handle, size_t size); - -/** - * xclAllocDeviceBuffer2() - Allocate a buffer on the device on a specific DDR - * - * @handle: Device handle - * @size: Size of buffer - * @domain: Memory domain - * @flags: Desired DDR bank as a bitmap. - * Return: Physical address of buffer on device or 0xFFFFFFFFFFFFFFFF in case of failure - * - * Allocate a buffer on a specific device DDR and return its address. This API will be deprecated in future. - * Use xclAllocBO() in all new code. - */ -XCL_DRIVER_DLLESPEC uint64_t xclAllocDeviceBuffer2(xclDeviceHandle handle, size_t size, - xclMemoryDomains domain, - unsigned flags); - -/** - * xclFreeDeviceBuffer() - Free a previously buffer on the device - * - * @handle: Device handle - * @buf: Physical address of buffer - * - * The physical address should have been previously allocated by xclAllocDeviceBuffe() or xclAllocDeviceBuffer2(). - * The address should point to the beginning of the buffer and not at an offset in the buffer. This API will - * be deprecated in future. Use xclFreeBO() together with BO allocation APIs. - */ -XCL_DRIVER_DLLESPEC void xclFreeDeviceBuffer(xclDeviceHandle handle, uint64_t buf); - -/** - * xclCopyBufferHost2Device() - Write to device memory - * - * @handle: Device handle - * @dest: Physical address in the device - * @src: Source buffer pointer - * @size: Size of data to synchronize - * @seek: Seek within the segment pointed to physical address - * Return: Size of data moved or standard error number - * - * Copy host buffer contents to previously allocated device memory. ``seek`` specifies how many bytes to skip - * at the beginning of the destination before copying ``size`` bytes of host buffer. This API will be - * deprecated in future. Use xclSyncBO() together with other BO APIs. - */ -XCL_DRIVER_DLLESPEC size_t xclCopyBufferHost2Device(xclDeviceHandle handle, uint64_t dest, - const void *src, size_t size, size_t seek); - -/** - * xclCopyBufferDevice2Host() - Read from device memory - * - * @handle: Device handle - * @dest: Destination buffer pointer - * @src: Physical address in the device - * @size: Size of data to synchronize - * @skip: Skip within the segment pointed to physical address - * Return: Size of data moved or standard error number - * - * Copy contents of previously allocated device memory to host buffer. ``skip`` specifies how many bytes to skip - * from the beginning of the source before copying ``size`` bytes of device buffer. This API will be - * deprecated in future. Use xclSyncBO() together with other BO APIs. - */ -XCL_DRIVER_DLLESPEC size_t xclCopyBufferDevice2Host(xclDeviceHandle handle, void *dest, - uint64_t src, size_t size, size_t skip); - -/* End HAL Legacy Buffer Management APIs */ - - -/** - * DOC: HAL Unmanaged DMA APIs - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * Unmanaged DMA APIs are for exclusive use by the debuggers and tools. The APIs allow clinets to read/write - * from/to absolute device address. No checks are performed if a buffer was allocated before at the specified - * location or if the address is valid. Users who want to take over the full memory managemnt of the device - * may use this API to synchronize their buffers between host and device. - */ - -/** - * xclUnmgdPread() - Perform unmanaged device memory read operation - * - * @handle: Device handle - * @flags: Unused - * @buf: Destination data pointer - * @size: Size of data to copy - * @offset: Absolute offset inside device - * Return: size of bytes read or appropriate error number - * - * This API may be used to perform DMA operation from absolute location specified. Users - * may use this if they want to perform their own device memory management -- not using the buffer - * object (BO) framework defined before. - */ -XCL_DRIVER_DLLESPEC ssize_t xclUnmgdPread(xclDeviceHandle handle, unsigned flags, void *buf, - size_t size, uint64_t offset); - -/** - * xclUnmgdPwrite() - Perform unmanaged device memory read operation - * - * @handle: Device handle - * @flags: Unused - * @buf: Source data pointer - * @size: Size of data to copy - * @offset: Absolute offset inside device - * Return: size of bytes written or appropriate error number - * - * This API may be used to perform DMA operation to an absolute location specified. Users - * may use this if they want to perform their own device memory management -- not using the buffer - * object (BO) framework defined before. - */ -XCL_DRIVER_DLLESPEC ssize_t xclUnmgdPwrite(xclDeviceHandle handle, unsigned flags, const void *buf, - size_t size, uint64_t offset); - -/* End HAL Unmanaged DMA APIs */ - -/* - * DOC: HAL Register read/write APIs - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * These functions are used to read and write peripherals sitting on the address map. OpenCL runtime - * will be using the BUFFER MANAGEMNT APIs described above to manage OpenCL buffers. It would use - * xclRead/xclWrite to program and manage peripherals on the card. For programming the Kernel, OpenCL - * runtime uses the kernel control register map generated by the xocc compiler. - * Note that the offset is wrt the address space. - */ - -/** - * xclWrite() - Perform register write operation - * - * @handle: Device handle - * @space: Address space - * @offset: Offset in the address space - * @hostBuf: Source data pointer - * @size: Size of data to copy - * Return: size of bytes written or appropriate error number - * - * This API may be used to write to device registers exposed on PCIe BAR. Offset is relative to the - * the address space. A device may have many address spaces. - */ - -XCL_DRIVER_DLLESPEC size_t xclWrite(xclDeviceHandle handle, xclAddressSpace space, uint64_t offset, - const void *hostBuf, size_t size); - -/** - * xclRead() - Perform register read operation - * - * @handle: Device handle - * @space: Address space - * @offset: Offset in the address space - * @hostbuf: Destination data pointer - * @size: Size of data to copy - * Return: size of bytes written or appropriate error number - * - * This API may be used to read from device registers exposed on PCIe BAR. Offset is relative to the - * the address space. A device may have many address spaces. - */ -XCL_DRIVER_DLLESPEC size_t xclRead(xclDeviceHandle handle, xclAddressSpace space, uint64_t offset, - void *hostbuf, size_t size); - -/* HAL Register read/write APIs */ - -/* - * TODO: - * Define the following APIs - * - * 1. Host accessible pipe APIs: pread/pwrite - * 2. Accelerator status, start, stop APIs - * 3. Context creation APIs to support multiple clients - * 4. Multiple OCL Region support - * 5. DPDK style buffer management and device polling - * - */ - -/** - * DOC: HAL Compute Unit Execution Management APIs - * - * These APIs are under development. These functions will be used to start compute - * units and wait for them to finish. - */ - -/** - * xclExecBuf() - Submit an execution request to the embedded (or software) scheduler - * - * @handle: Device handle - * @cmdBO: BO handle containing command packet - * Return: 0 or standard error number - * - * This API is EXPERIMENTAL in this release. Submit an exec buffer for execution. The exec - * buffer layout is defined by struct ert_packet which is defined in file *ert.h*. The BO - * should been allocated with DRM_XOCL_BO_EXECBUF flag. - */ -XCL_DRIVER_DLLESPEC int xclExecBuf(xclDeviceHandle handle, unsigned int cmdBO); - -/** - * xclExecWait() - Wait for one or more execution events on the device - * - * @handle: Device handle - * @timeoutMilliSec: How long to wait for - * Return: Same code as poll system call - * - * This API is EXPERIMENTAL in this release - * Wait for notification from the hardware. The function essentially calls "poll" system - * call on the driver file handle. The return value has same semantics as poll system call. - * If return value is > 0 caller should check the status of submitted exec buffers - */ -XCL_DRIVER_DLLESPEC int xclExecWait(xclDeviceHandle handle, int timeoutMilliSec); - -/** - * xclRegisterInterruptNotify() - register *eventfd* file handle for a MSIX interrupt - * - * @handle: Device handle - * @userInterrupt: MSIX interrupt number - * @fd: Eventfd handle - * Return: 0 on success or standard errno - * - * Support for non managed interrupts (interrupts from custom IPs). fd should be obtained from - * eventfd system call. Caller should use standard poll/read eventfd framework in order to wait for - * interrupts. The handles are automatically unregistered on process exit. - */ -XCL_DRIVER_DLLESPEC int xclRegisterInterruptNotify(xclDeviceHandle handle, unsigned int userInterrupt, int fd); - -/* HAL Compute Unit Execution Management APIs */ - -/** - * @defgroup perfmon PERFORMANCE MONITORING OPERATIONS - * --------------------------------------------------- - * - * These functions are used to read and write to the performance monitoring infrastructure. - * OpenCL runtime will be using the BUFFER MANAGEMNT APIs described above to manage OpenCL buffers. - * It would use these functions to initialize and sample the performance monitoring on the card. - * Note that the offset is wrt the address space - */ - -/* Write host event to device tracing (Zynq only) */ -XCL_DRIVER_DLLESPEC void xclWriteHostEvent(xclDeviceHandle handle, xclPerfMonEventType type, - xclPerfMonEventID id); - -XCL_DRIVER_DLLESPEC size_t xclGetDeviceTimestamp(xclDeviceHandle handle); - -XCL_DRIVER_DLLESPEC double xclGetDeviceClockFreqMHz(xclDeviceHandle handle); - -XCL_DRIVER_DLLESPEC double xclGetReadMaxBandwidthMBps(xclDeviceHandle handle); - -XCL_DRIVER_DLLESPEC double xclGetWriteMaxBandwidthMBps(xclDeviceHandle handle); - -XCL_DRIVER_DLLESPEC void xclSetProfilingNumberSlots(xclDeviceHandle handle, xclPerfMonType type, - uint32_t numSlots); - -XCL_DRIVER_DLLESPEC uint32_t xclGetProfilingNumberSlots(xclDeviceHandle handle, xclPerfMonType type); - -XCL_DRIVER_DLLESPEC void xclGetProfilingSlotName(xclDeviceHandle handle, xclPerfMonType type, - uint32_t slotnum, char* slotName, uint32_t length); - -XCL_DRIVER_DLLESPEC size_t xclPerfMonClockTraining(xclDeviceHandle handle, xclPerfMonType type); - -XCL_DRIVER_DLLESPEC size_t xclPerfMonStartCounters(xclDeviceHandle handle, xclPerfMonType type); - -XCL_DRIVER_DLLESPEC size_t xclPerfMonStopCounters(xclDeviceHandle handle, xclPerfMonType type); - -XCL_DRIVER_DLLESPEC size_t xclPerfMonReadCounters(xclDeviceHandle handle, xclPerfMonType type, - xclCounterResults& counterResults); - -XCL_DRIVER_DLLESPEC size_t xclDebugReadIPStatus(xclDeviceHandle handle, xclDebugReadType type, - void* debugResults); - -XCL_DRIVER_DLLESPEC size_t xclPerfMonStartTrace(xclDeviceHandle handle, xclPerfMonType type, - uint32_t startTrigger); - -XCL_DRIVER_DLLESPEC size_t xclPerfMonStopTrace(xclDeviceHandle handle, xclPerfMonType type); - -XCL_DRIVER_DLLESPEC uint32_t xclPerfMonGetTraceCount(xclDeviceHandle handle, xclPerfMonType type); - -XCL_DRIVER_DLLESPEC size_t xclPerfMonReadTrace(xclDeviceHandle handle, xclPerfMonType type, - xclTraceResultsVector& traceVector); - -/** @} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/SDAccel/userspace/include/xclperf.h b/SDAccel/userspace/include/xclperf.h index d4db9e12..38fe91b3 100644 --- a/SDAccel/userspace/include/xclperf.h +++ b/SDAccel/userspace/include/xclperf.h @@ -1,6 +1,5 @@ /** * Copyright (C) 2015-2018 Xilinx, Inc - * * Xilinx SDAccel HAL userspace driver extension APIs * Performance Monitoring Exposed Parameters * @@ -21,7 +20,7 @@ #define _XCL_PERF_H_ // DSA version (e.g., XCL_PLATFORM=xilinx_adm-pcie-7v3_1ddr_1_1) - +// Simply a default as its read from the device using lspci (see CR 870994) #define DSA_MAJOR_VERSION 1 #define DSA_MINOR_VERSION 1 @@ -34,6 +33,9 @@ #define XPAR_AXI_PERF_MON_0_OCL_REGION_SLOT 0 #define XPAR_AXI_PERF_MON_0_HOST_SLOT 1 +#define XPAR_SPM0_HOST_SLOT 0 +#define XPAR_SPM0_FIRST_KERNEL_SLOT 1 + #define XPAR_AXI_PERF_MON_0_OCL_REGION_SLOT2 2 #define XPAR_AXI_PERF_MON_0_OCL_REGION_SLOT3 3 #define XPAR_AXI_PERF_MON_0_OCL_REGION_SLOT4 4 @@ -72,7 +74,7 @@ /* AXI Stream FIFOs */ #define XPAR_AXI_PERF_MON_0_TRACE_NUMBER_FIFO 3 -#define XPAR_AXI_PERF_MON_0_TRACE_WORD_WIDTH 128 +#define XPAR_AXI_PERF_MON_0_TRACE_WORD_WIDTH 64 #define XPAR_AXI_PERF_MON_0_TRACE_NUMBER_SAMPLES 4096 #define MAX_TRACE_NUMBER_SAMPLES 8192 @@ -81,7 +83,11 @@ #define XPAR_AXI_PERF_MON_0_TRACE_OFFSET_2 0x012000 // CR 877788: the extra 0x80001000 is a bug in Vivado where the AXI4 base address is not set correctly // TODO: remove it once that bug is fixed! -#define XPAR_AXI_PERF_MON_0_TRACE_OFFSET_AXI_FULL (0x2000000000 + 0x80001000) +//#define XPAR_AXI_PERF_MON_0_TRACE_OFFSET_AXI_FULL (0x2000000000 + 0x80001000) +#define XPAR_AXI_PERF_MON_0_TRACE_OFFSET_AXI_FULL 0x2000000000 +// Default for new monitoring +//#define XPAR_AXI_PERF_MON_0_TRACE_OFFSET_AXI_FULL2 (0x0400000000 + 0x80001000) +#define XPAR_AXI_PERF_MON_0_TRACE_OFFSET_AXI_FULL2 0x0400000000 /********************* APM 1: Monitor PCIe DMA Masters ************************/ @@ -167,6 +173,8 @@ /************************ APM Profile Counters ********************************/ #define XAPM_MAX_NUMBER_SLOTS 8 +// Max slots = floor(max slots on trace funnel / 2) = floor(63 / 2) = 31 +#define XSPM_MAX_NUMBER_SLOTS 31 #define XAPM_METRIC_COUNTERS_PER_SLOT 8 /* Metric counters per slot */ @@ -213,6 +221,7 @@ /* Cycles to add to timestamp if overflow occurs */ #define LOOP_ADD_TIME (1<<16) +#define LOOP_ADD_TIME_SPM (1<<44) /********************** Definitions: Enums, Structs ***************************/ @@ -255,12 +264,20 @@ enum xclPerfMonEventType { XCL_PERF_MON_END_EVENT = 0x5 }; +/* + * Xocc follows this convention + * Even IDs are Reads + * Odd IDs are Writes + */ +#define IS_WRITE(x) ((x) & 1) +#define IS_READ(x) (!((x) & 1)) + /* * Performance monitor IDs for host SW events * NOTE: HW events start at 0, SDSoC SW events start at 4000 */ enum xclPerfMonEventID { - XCL_PERF_MON_IGNORE_EVENT = 0, + XCL_PERF_MON_HW_EVENT = 0, XCL_PERF_MON_GENERAL_ID = 3000, XCL_PERF_MON_QUEUE_ID = 3001, XCL_PERF_MON_READ_ID = 3002, @@ -305,46 +322,42 @@ enum xclPerfMonEventID { XCL_PERF_MON_CU5_ID = 3205, XCL_PERF_MON_CU6_ID = 3206, XCL_PERF_MON_CU7_ID = 3207, - XCL_PERF_MON_PROGRAM_END = 4090 + XCL_PERF_MON_PROGRAM_END = 4090, + XCL_PERF_MON_IGNORE_EVENT = 4095 }; /* Performance monitor counter results */ typedef struct { //unsigned int NumSlots; float SampleIntervalUsec; - unsigned int WriteBytes[XAPM_MAX_NUMBER_SLOTS]; - unsigned int WriteTranx[XAPM_MAX_NUMBER_SLOTS]; - unsigned int WriteLatency[XAPM_MAX_NUMBER_SLOTS]; - unsigned short WriteMinLatency[XAPM_MAX_NUMBER_SLOTS]; - unsigned short WriteMaxLatency[XAPM_MAX_NUMBER_SLOTS]; - unsigned int ReadBytes[XAPM_MAX_NUMBER_SLOTS]; - unsigned int ReadTranx[XAPM_MAX_NUMBER_SLOTS]; - unsigned int ReadLatency[XAPM_MAX_NUMBER_SLOTS]; - unsigned short ReadMinLatency[XAPM_MAX_NUMBER_SLOTS]; - unsigned short ReadMaxLatency[XAPM_MAX_NUMBER_SLOTS]; + unsigned int WriteBytes[XSPM_MAX_NUMBER_SLOTS]; + unsigned int WriteTranx[XSPM_MAX_NUMBER_SLOTS]; + unsigned int WriteLatency[XSPM_MAX_NUMBER_SLOTS]; + unsigned short WriteMinLatency[XSPM_MAX_NUMBER_SLOTS]; + unsigned short WriteMaxLatency[XSPM_MAX_NUMBER_SLOTS]; + unsigned int ReadBytes[XSPM_MAX_NUMBER_SLOTS]; + unsigned int ReadTranx[XSPM_MAX_NUMBER_SLOTS]; + unsigned int ReadLatency[XSPM_MAX_NUMBER_SLOTS]; + unsigned short ReadMinLatency[XSPM_MAX_NUMBER_SLOTS]; + unsigned short ReadMaxLatency[XSPM_MAX_NUMBER_SLOTS]; } xclCounterResults; /* Performance monitor trace results */ typedef struct { - unsigned char LogID; /* 0: event flags, 1: host timestamp */ + xclPerfMonEventID EventID; + xclPerfMonEventType EventType; + unsigned long long Timestamp; unsigned char Overflow; - unsigned char WriteStartEvent; - unsigned char WriteEndEvent; - unsigned char ReadStartEvent; - unsigned short Timestamp; - unsigned int HostTimestamp; - unsigned char RID[XAPM_MAX_NUMBER_SLOTS]; - unsigned char ARID[XAPM_MAX_NUMBER_SLOTS]; - unsigned char BID[XAPM_MAX_NUMBER_SLOTS]; - unsigned char AWID[XAPM_MAX_NUMBER_SLOTS]; - unsigned char EventFlags[XAPM_MAX_NUMBER_SLOTS]; - unsigned char ExtEventFlags[XAPM_MAX_NUMBER_SLOTS]; - unsigned char WriteAddrLen[XAPM_MAX_NUMBER_SLOTS]; - unsigned char ReadAddrLen[XAPM_MAX_NUMBER_SLOTS]; - unsigned short WriteBytes[XAPM_MAX_NUMBER_SLOTS]; - unsigned short ReadBytes[XAPM_MAX_NUMBER_SLOTS]; - unsigned short WriteAddrId[XAPM_MAX_NUMBER_SLOTS]; - unsigned short ReadAddrId[XAPM_MAX_NUMBER_SLOTS]; + unsigned int TraceID; + unsigned char Error; + unsigned char Reserved; + // Used in HW Emulation + unsigned long long HostTimestamp; + unsigned char EventFlags; + unsigned char WriteAddrLen; + unsigned char ReadAddrLen; + unsigned short WriteBytes; + unsigned short ReadBytes; } xclTraceResults; typedef struct { diff --git a/SDAccel/userspace/include/xclperf2.h b/SDAccel/userspace/include/xclperf2.h deleted file mode 100755 index 38fe91b3..00000000 --- a/SDAccel/userspace/include/xclperf2.h +++ /dev/null @@ -1,369 +0,0 @@ -/** - * Copyright (C) 2015-2018 Xilinx, Inc - * Xilinx SDAccel HAL userspace driver extension APIs - * Performance Monitoring Exposed Parameters - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -#ifndef _XCL_PERF_H_ -#define _XCL_PERF_H_ - -// DSA version (e.g., XCL_PLATFORM=xilinx_adm-pcie-7v3_1ddr_1_1) -// Simply a default as its read from the device using lspci (see CR 870994) -#define DSA_MAJOR_VERSION 1 -#define DSA_MINOR_VERSION 1 - -/************************ APM 0: Monitor MIG Ports ****************************/ - -#define XPAR_AXI_PERF_MON_0_NUMBER_SLOTS 2 - -#define XPAR_AXI_PERF_MON_0_SLOT0_NAME "OCL Region" -#define XPAR_AXI_PERF_MON_0_SLOT1_NAME "Host" -#define XPAR_AXI_PERF_MON_0_OCL_REGION_SLOT 0 -#define XPAR_AXI_PERF_MON_0_HOST_SLOT 1 - -#define XPAR_SPM0_HOST_SLOT 0 -#define XPAR_SPM0_FIRST_KERNEL_SLOT 1 - -#define XPAR_AXI_PERF_MON_0_OCL_REGION_SLOT2 2 -#define XPAR_AXI_PERF_MON_0_OCL_REGION_SLOT3 3 -#define XPAR_AXI_PERF_MON_0_OCL_REGION_SLOT4 4 -#define XPAR_AXI_PERF_MON_0_OCL_REGION_SLOT5 5 -#define XPAR_AXI_PERF_MON_0_OCL_REGION_SLOT6 6 -#define XPAR_AXI_PERF_MON_0_OCL_REGION_SLOT7 7 - -#define XPAR_AXI_PERF_MON_0_SLOT2_NAME "OCL Region Master 2" -#define XPAR_AXI_PERF_MON_0_SLOT3_NAME "OCL Region Master 3" -#define XPAR_AXI_PERF_MON_0_SLOT4_NAME "OCL Region Master 4" -#define XPAR_AXI_PERF_MON_0_SLOT5_NAME "OCL Region Master 5" -#define XPAR_AXI_PERF_MON_0_SLOT6_NAME "OCL Region Master 6" -#define XPAR_AXI_PERF_MON_0_SLOT7_NAME "OCL Region Master 7" - -#define XPAR_AXI_PERF_MON_0_SLOT0_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_0_SLOT1_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_0_SLOT2_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_0_SLOT3_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_0_SLOT4_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_0_SLOT5_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_0_SLOT6_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_0_SLOT7_DATA_WIDTH 512 - -/* Profile */ -#define XPAR_AXI_PERF_MON_0_IS_EVENT_COUNT 1 -#define XPAR_AXI_PERF_MON_0_HAVE_SAMPLED_COUNTERS 1 -#define XPAR_AXI_PERF_MON_0_NUMBER_COUNTERS (XPAR_AXI_PERF_MON_0_NUMBER_SLOTS * XAPM_METRIC_COUNTERS_PER_SLOT) - -/* Trace */ -#define XPAR_AXI_PERF_MON_0_IS_EVENT_LOG 1 -#define XPAR_AXI_PERF_MON_0_SHOW_AXI_IDS 1 -#define XPAR_AXI_PERF_MON_0_SHOW_AXI_LEN 1 -// 2 DDR platform -#define XPAR_AXI_PERF_MON_0_SHOW_AXI_IDS_2DDR 0 -#define XPAR_AXI_PERF_MON_0_SHOW_AXI_LEN_2DDR 1 - -/* AXI Stream FIFOs */ -#define XPAR_AXI_PERF_MON_0_TRACE_NUMBER_FIFO 3 -#define XPAR_AXI_PERF_MON_0_TRACE_WORD_WIDTH 64 -#define XPAR_AXI_PERF_MON_0_TRACE_NUMBER_SAMPLES 4096 -#define MAX_TRACE_NUMBER_SAMPLES 8192 - -#define XPAR_AXI_PERF_MON_0_TRACE_OFFSET_0 0x010000 -#define XPAR_AXI_PERF_MON_0_TRACE_OFFSET_1 0x011000 -#define XPAR_AXI_PERF_MON_0_TRACE_OFFSET_2 0x012000 -// CR 877788: the extra 0x80001000 is a bug in Vivado where the AXI4 base address is not set correctly -// TODO: remove it once that bug is fixed! -//#define XPAR_AXI_PERF_MON_0_TRACE_OFFSET_AXI_FULL (0x2000000000 + 0x80001000) -#define XPAR_AXI_PERF_MON_0_TRACE_OFFSET_AXI_FULL 0x2000000000 -// Default for new monitoring -//#define XPAR_AXI_PERF_MON_0_TRACE_OFFSET_AXI_FULL2 (0x0400000000 + 0x80001000) -#define XPAR_AXI_PERF_MON_0_TRACE_OFFSET_AXI_FULL2 0x0400000000 - -/********************* APM 1: Monitor PCIe DMA Masters ************************/ - -#define XPAR_AXI_PERF_MON_1_NUMBER_SLOTS 2 - -#define XPAR_AXI_PERF_MON_1_SLOT0_NAME "DMA AXI4 Master" -#define XPAR_AXI_PERF_MON_1_SLOT1_NAME "DMA AXI4-Lite Master" -#define XPAR_AXI_PERF_MON_1_SLOT2_NAME "Null" -#define XPAR_AXI_PERF_MON_1_SLOT3_NAME "Null" -#define XPAR_AXI_PERF_MON_1_SLOT4_NAME "Null" -#define XPAR_AXI_PERF_MON_1_SLOT5_NAME "Null" -#define XPAR_AXI_PERF_MON_1_SLOT6_NAME "Null" -#define XPAR_AXI_PERF_MON_1_SLOT7_NAME "Null" - -#define XPAR_AXI_PERF_MON_1_SLOT0_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_1_SLOT1_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_1_SLOT2_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_1_SLOT3_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_1_SLOT4_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_1_SLOT5_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_1_SLOT6_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_1_SLOT7_DATA_WIDTH 512 - -/* Profile */ -#define XPAR_AXI_PERF_MON_1_IS_EVENT_COUNT 1 -#define XPAR_AXI_PERF_MON_1_HAVE_SAMPLED_COUNTERS 1 -#define XPAR_AXI_PERF_MON_1_NUMBER_COUNTERS (XPAR_AXI_PERF_MON_1_NUMBER_SLOTS * XAPM_METRIC_COUNTERS_PER_SLOT) -#define XPAR_AXI_PERF_MON_1_SCALE_FACTOR 1 - -/* Trace */ -#define XPAR_AXI_PERF_MON_1_IS_EVENT_LOG 0 -#define XPAR_AXI_PERF_MON_1_SHOW_AXI_IDS 0 -#define XPAR_AXI_PERF_MON_1_SHOW_AXI_LEN 0 - -/* AXI Stream FIFOs */ -#define XPAR_AXI_PERF_MON_1_TRACE_NUMBER_FIFO 0 -#define XPAR_AXI_PERF_MON_1_TRACE_WORD_WIDTH 0 -#define XPAR_AXI_PERF_MON_1_TRACE_NUMBER_SAMPLES 0 - -/************************ APM 2: Monitor OCL Region ***************************/ - -#define XPAR_AXI_PERF_MON_2_NUMBER_SLOTS 1 - -#define XPAR_AXI_PERF_MON_2_SLOT0_NAME "Kernel0" -#define XPAR_AXI_PERF_MON_2_SLOT1_NAME "Kernel1" -#define XPAR_AXI_PERF_MON_2_SLOT2_NAME "Kernel2" -#define XPAR_AXI_PERF_MON_2_SLOT3_NAME "Kernel3" -#define XPAR_AXI_PERF_MON_2_SLOT4_NAME "Kernel4" -#define XPAR_AXI_PERF_MON_2_SLOT5_NAME "Kernel5" -#define XPAR_AXI_PERF_MON_2_SLOT6_NAME "Kernel6" -#define XPAR_AXI_PERF_MON_2_SLOT7_NAME "Kernel7" - -#define XPAR_AXI_PERF_MON_2_SLOT0_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_2_SLOT1_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_2_SLOT2_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_2_SLOT3_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_2_SLOT4_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_2_SLOT5_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_2_SLOT6_DATA_WIDTH 512 -#define XPAR_AXI_PERF_MON_2_SLOT7_DATA_WIDTH 512 - -/* Profile */ -#define XPAR_AXI_PERF_MON_2_IS_EVENT_COUNT 0 -#define XPAR_AXI_PERF_MON_2_HAVE_SAMPLED_COUNTERS 0 -#define XPAR_AXI_PERF_MON_2_NUMBER_COUNTERS 0 -#define XPAR_AXI_PERF_MON_2_SCALE_FACTOR 1 - -/* Trace */ -#define XPAR_AXI_PERF_MON_2_IS_EVENT_LOG 1 -#define XPAR_AXI_PERF_MON_2_SHOW_AXI_IDS 0 -#define XPAR_AXI_PERF_MON_2_SHOW_AXI_LEN 0 - -/* AXI Stream FIFOs */ -/* NOTE: number of FIFOs is dependent upon the number of compute units being monitored */ -//#define XPAR_AXI_PERF_MON_2_TRACE_NUMBER_FIFO 2 -#define XPAR_AXI_PERF_MON_2_TRACE_WORD_WIDTH 64 -#define XPAR_AXI_PERF_MON_2_TRACE_NUMBER_SAMPLES 4096 - -#define XPAR_AXI_PERF_MON_2_TRACE_OFFSET_0 0x01000 -#define XPAR_AXI_PERF_MON_2_TRACE_OFFSET_1 0x02000 -#define XPAR_AXI_PERF_MON_2_TRACE_OFFSET_2 0x03000 - -/************************ APM Profile Counters ********************************/ - -#define XAPM_MAX_NUMBER_SLOTS 8 -// Max slots = floor(max slots on trace funnel / 2) = floor(63 / 2) = 31 -#define XSPM_MAX_NUMBER_SLOTS 31 -#define XAPM_METRIC_COUNTERS_PER_SLOT 8 - -/* Metric counters per slot */ -#define XAPM_METRIC_WRITE_BYTES 0 -#define XAPM_METRIC_WRITE_TRANX 1 -#define XAPM_METRIC_WRITE_LATENCY 2 -#define XAPM_METRIC_READ_BYTES 3 -#define XAPM_METRIC_READ_TRANX 4 -#define XAPM_METRIC_READ_LATENCY 5 -#define XAPM_METRIC_WRITE_MIN_MAX 6 -#define XAPM_METRIC_READ_MIN_MAX 7 - -#define XAPM_METRIC_COUNT0_NAME "Write Byte Count" -#define XAPM_METRIC_COUNT1_NAME "Write Transaction Count" -#define XAPM_METRIC_COUNT2_NAME "Total Write Latency" -#define XAPM_METRIC_COUNT3_NAME "Read Byte Count" -#define XAPM_METRIC_COUNT4_NAME "Read Transaction Count" -#define XAPM_METRIC_COUNT5_NAME "Total Read Latency" -#define XAPM_METRIC_COUNT6_NAME "Min/Max Write Latency" -#define XAPM_METRIC_COUNT7_NAME "Min/Max Read Latency" - -/************************ APM Debug Counters ********************************/ -#define XAPM_DEBUG_METRIC_COUNTERS_PER_SLOT 4 //debug is only interested in 4 metric counters - -/************************ APM Trace Stream ************************************/ - -/* Bit locations of trace flags */ -#define XAPM_READ_LAST 6 -#define XAPM_READ_FIRST 5 -#define XAPM_READ_ADDR 4 -#define XAPM_RESPONSE 3 -#define XAPM_WRITE_LAST 2 -#define XAPM_WRITE_FIRST 1 -#define XAPM_WRITE_ADDR 0 - -/* Bit locations of external event flags */ -#define XAPM_EXT_START 2 -#define XAPM_EXT_STOP 1 -#define XAPM_EXT_EVENT 0 - -/* Total number of bits per slot */ -#define FLAGS_PER_SLOT 7 -#define EXT_EVENTS_PER_SLOT 3 - -/* Cycles to add to timestamp if overflow occurs */ -#define LOOP_ADD_TIME (1<<16) -#define LOOP_ADD_TIME_SPM (1<<44) - -/********************** Definitions: Enums, Structs ***************************/ - -/* Performance monitor type or location */ -enum xclPerfMonType { - XCL_PERF_MON_MEMORY = 0, - XCL_PERF_MON_HOST_INTERFACE = 1, - XCL_PERF_MON_OCL_REGION = 2, - XCL_PERF_MON_TOTAL_PROFILE = 3 -}; - -/* Performance monitor start event */ -enum xclPerfMonStartEvent { - XCL_PERF_MON_START_ADDR = 0, - XCL_PERF_MON_START_FIRST_DATA = 1 -}; - -/* Performance monitor end event */ -enum xclPerfMonEndEvent { - XCL_PERF_MON_END_LAST_DATA = 0, - XCL_PERF_MON_END_RESPONSE = 1 -}; - -/* Performance monitor counter types */ -enum xclPerfMonCounterType { - XCL_PERF_MON_WRITE_BYTES = 0, - XCL_PERF_MON_WRITE_TRANX = 1, - XCL_PERF_MON_WRITE_LATENCY = 2, - XCL_PERF_MON_READ_BYTES = 3, - XCL_PERF_MON_READ_TRANX = 4, - XCL_PERF_MON_READ_LATENCY = 5 -}; - -/* - * Performance monitor event types - * NOTE: these are the same values used by SDSoC - */ -enum xclPerfMonEventType { - XCL_PERF_MON_START_EVENT = 0x4, - XCL_PERF_MON_END_EVENT = 0x5 -}; - -/* - * Xocc follows this convention - * Even IDs are Reads - * Odd IDs are Writes - */ -#define IS_WRITE(x) ((x) & 1) -#define IS_READ(x) (!((x) & 1)) - -/* - * Performance monitor IDs for host SW events - * NOTE: HW events start at 0, SDSoC SW events start at 4000 - */ -enum xclPerfMonEventID { - XCL_PERF_MON_HW_EVENT = 0, - XCL_PERF_MON_GENERAL_ID = 3000, - XCL_PERF_MON_QUEUE_ID = 3001, - XCL_PERF_MON_READ_ID = 3002, - XCL_PERF_MON_WRITE_ID = 3003, - XCL_PERF_MON_API_GET_PLATFORM_ID = 3005, - XCL_PERF_MON_API_GET_PLATFORM_INFO_ID = 3006, - XCL_PERF_MON_API_GET_DEVICE_ID = 3007, - XCL_PERF_MON_API_GET_DEVICE_INFO_ID = 3008, - XCL_PERF_MON_API_BUILD_PROGRAM_ID = 3009, - XCL_PERF_MON_API_CREATE_CONTEXT_ID = 3010, - XCL_PERF_MON_API_CREATE_CONTEXT_TYPE_ID = 3011, - XCL_PERF_MON_API_CREATE_COMMAND_QUEUE_ID = 3012, - XCL_PERF_MON_API_CREATE_PROGRAM_BINARY_ID = 3013, - XCL_PERF_MON_API_CREATE_BUFFER_ID = 3014, - XCL_PERF_MON_API_CREATE_IMAGE_ID = 3015, - XCL_PERF_MON_API_CREATE_KERNEL_ID = 3016, - XCL_PERF_MON_API_KERNEL_ARG_ID = 3017, - XCL_PERF_MON_API_WAIT_FOR_EVENTS_ID = 3018, - XCL_PERF_MON_API_READ_BUFFER_ID = 3019, - XCL_PERF_MON_API_WRITE_BUFFER_ID = 3020, - XCL_PERF_MON_API_READ_IMAGE_ID = 3021, - XCL_PERF_MON_API_WRITE_IMAGE_ID = 3022, - XCL_PERF_MON_API_MIGRATE_MEM_ID = 3023, - XCL_PERF_MON_API_MIGRATE_MEM_OBJECTS_ID = 3024, - XCL_PERF_MON_API_MAP_BUFFER_ID = 3025, - XCL_PERF_MON_API_UNMAP_MEM_OBJECT_ID = 3026, - XCL_PERF_MON_API_NDRANGE_KERNEL_ID = 3027, - XCL_PERF_MON_API_TASK_ID = 3028, - XCL_PERF_MON_KERNEL0_ID = 3100, - XCL_PERF_MON_KERNEL1_ID = 3101, - XCL_PERF_MON_KERNEL2_ID = 3102, - XCL_PERF_MON_KERNEL3_ID = 3103, - XCL_PERF_MON_KERNEL4_ID = 3104, - XCL_PERF_MON_KERNEL5_ID = 3105, - XCL_PERF_MON_KERNEL6_ID = 3106, - XCL_PERF_MON_KERNEL7_ID = 3107, - XCL_PERF_MON_CU0_ID = 3200, - XCL_PERF_MON_CU1_ID = 3201, - XCL_PERF_MON_CU2_ID = 3202, - XCL_PERF_MON_CU3_ID = 3203, - XCL_PERF_MON_CU4_ID = 3204, - XCL_PERF_MON_CU5_ID = 3205, - XCL_PERF_MON_CU6_ID = 3206, - XCL_PERF_MON_CU7_ID = 3207, - XCL_PERF_MON_PROGRAM_END = 4090, - XCL_PERF_MON_IGNORE_EVENT = 4095 -}; - -/* Performance monitor counter results */ -typedef struct { - //unsigned int NumSlots; - float SampleIntervalUsec; - unsigned int WriteBytes[XSPM_MAX_NUMBER_SLOTS]; - unsigned int WriteTranx[XSPM_MAX_NUMBER_SLOTS]; - unsigned int WriteLatency[XSPM_MAX_NUMBER_SLOTS]; - unsigned short WriteMinLatency[XSPM_MAX_NUMBER_SLOTS]; - unsigned short WriteMaxLatency[XSPM_MAX_NUMBER_SLOTS]; - unsigned int ReadBytes[XSPM_MAX_NUMBER_SLOTS]; - unsigned int ReadTranx[XSPM_MAX_NUMBER_SLOTS]; - unsigned int ReadLatency[XSPM_MAX_NUMBER_SLOTS]; - unsigned short ReadMinLatency[XSPM_MAX_NUMBER_SLOTS]; - unsigned short ReadMaxLatency[XSPM_MAX_NUMBER_SLOTS]; -} xclCounterResults; - -/* Performance monitor trace results */ -typedef struct { - xclPerfMonEventID EventID; - xclPerfMonEventType EventType; - unsigned long long Timestamp; - unsigned char Overflow; - unsigned int TraceID; - unsigned char Error; - unsigned char Reserved; - // Used in HW Emulation - unsigned long long HostTimestamp; - unsigned char EventFlags; - unsigned char WriteAddrLen; - unsigned char ReadAddrLen; - unsigned short WriteBytes; - unsigned short ReadBytes; -} xclTraceResults; - -typedef struct { - unsigned int mLength; - //unsigned int mNumSlots; - xclTraceResults mArray[MAX_TRACE_NUMBER_SAMPLES]; -} xclTraceResultsVector; - -#endif diff --git a/SDAccel/userspace/src/Makefile b/SDAccel/userspace/src/Makefile index aa0c8195..f95abfd6 100644 --- a/SDAccel/userspace/src/Makefile +++ b/SDAccel/userspace/src/Makefile @@ -1,6 +1,6 @@ # Amazon FPGA Hardware Development Kit # -# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Amazon Software License (the "License"). You may not use # this file except in compliance with the License. A copy of the License is @@ -14,7 +14,7 @@ # limitations under the License. -# AWS HAL Driver Makefile +# AWS Bare-metal HAL Driver Makefile # set ec2=1 to compile for F1 instance CXX := g++ @@ -23,25 +23,24 @@ AR := ar ARFLAGS := rcv ifeq ($(ec2),1) - CXXFLAGS := -Werror -std=c++11 - STLIB = libawsxcldrv.a - SHLIB = libawsxcldrv.so + CXXFLAGS := -Werror -std=c++11 + STLIB = libxrt-aws.a + SHLIB = libxrt-aws.so else # For bare metal testing, i.e. in non EC2 environment - CXXFLAGS := -Werror -std=c++11 -DINTERNAL_TESTING - STLIB = libawsbmdrv.a - SHLIB = libawsbmdrv.so + CXXFLAGS := -Werror -std=c++11 -DINTERNAL_TESTING + STLIB = libxrtbm-aws.a + SHLIB = libxrtbm-aws.so endif LIBS := $(STLIB) $(SHLIB) -XCLHAL_VER =-DXCLHAL_MAJOR_VER=1 -DXCLHAL_MINOR_VER=1 +XCLHAL_VER = -DXCLHAL_MAJOR_VER=2 -DXCLHAL_MINOR_VER=1 # Include XCLHAL includes, AWS fpga_pci/mgmt and AWS kernel drivers SHIM_INC := -I../include -I$(SDK_DIR)/userspace/include -I$(SDK_DIR)/linux_kernel_drivers - -CXXFLAGS += $(CXXFLAGS) $(XCLHAL_VER) $(SHIM_INC) -fpic -fvisibility=hidden -lrt +CXXFLAGS += $(CXXFLAGS) $(XCLHAL_VER) $(SHIM_INC) -fpic -fvisibility=hidden -lrt -Wall ifeq ($(debug),1) CXXFLAGS += -g -DDEBUG @@ -50,7 +49,7 @@ else endif SRCS := $(wildcard *.$(CXX_EXT)) -OBJS := $(patsubst %.$(CXX_EXT), %.o , $(SRCS)) +OBJS := $(patsubst %.$(CXX_EXT), %.o, $(SRCS)) -include $(OBJS:.o=.d) diff --git a/SDAccel/userspace/src2/README.md b/SDAccel/userspace/src/README.md similarity index 91% rename from SDAccel/userspace/src2/README.md rename to SDAccel/userspace/src/README.md index b1c756fa..624b1504 100644 --- a/SDAccel/userspace/src2/README.md +++ b/SDAccel/userspace/src/README.md @@ -1,6 +1,6 @@ # SDAccel Hardware Abstraction Layer for AWS FPGA -This directory includes the source code and binary files for mapping SDAccel/OpenCL runtime library call to AWS specific hardware. This API is documented in [xclhal2.h](../include/xclhal2.h). +This directory includes the source code and binary files for mapping SDAccel/OpenCL runtime library call to AWS specific hardware. This API is documented in [xclhal.h](../include/xclhal.h). It supports the following functionality. diff --git a/SDAccel/userspace/src2/awssak.cpp b/SDAccel/userspace/src/awssak.cpp similarity index 100% rename from SDAccel/userspace/src2/awssak.cpp rename to SDAccel/userspace/src/awssak.cpp diff --git a/SDAccel/userspace/src2/awssak.h b/SDAccel/userspace/src/awssak.h similarity index 99% rename from SDAccel/userspace/src2/awssak.h rename to SDAccel/userspace/src/awssak.h index 930567ee..47c26e5e 100644 --- a/SDAccel/userspace/src2/awssak.h +++ b/SDAccel/userspace/src/awssak.h @@ -38,7 +38,7 @@ #include #include -#include "xclbin2.h" +#include "xclbin.h" #include "xcl_axi_checker_codes.h" #include "scan.h" #include "dmatest.h" diff --git a/SDAccel/userspace/src2/awssak_debug.cpp b/SDAccel/userspace/src/awssak_debug.cpp similarity index 99% rename from SDAccel/userspace/src2/awssak_debug.cpp rename to SDAccel/userspace/src/awssak_debug.cpp index 2e4820cb..a03aba32 100644 --- a/SDAccel/userspace/src2/awssak_debug.cpp +++ b/SDAccel/userspace/src/awssak_debug.cpp @@ -29,7 +29,7 @@ #include #include -#include "xclbin2.h" +#include "xclbin.h" #include "scan.h" #include "awssak.h" diff --git a/SDAccel/userspace/src2/awssak_utils.cpp b/SDAccel/userspace/src/awssak_utils.cpp similarity index 100% rename from SDAccel/userspace/src2/awssak_utils.cpp rename to SDAccel/userspace/src/awssak_utils.cpp diff --git a/SDAccel/userspace/src2/awssak_utils.h b/SDAccel/userspace/src/awssak_utils.h similarity index 100% rename from SDAccel/userspace/src2/awssak_utils.h rename to SDAccel/userspace/src/awssak_utils.h diff --git a/SDAccel/userspace/src/datamover.h b/SDAccel/userspace/src/datamover.h deleted file mode 100644 index 1572fc3c..00000000 --- a/SDAccel/userspace/src/datamover.h +++ /dev/null @@ -1,198 +0,0 @@ -/** - * Copyright (C) 2016-2018 Xilinx, Inc - * Author: Sonal Santan - * XDMA HAL multi-threading safe, multi-channel DMA read/write support - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -#ifndef _XDMA_DATA_MOVER_H_ -#define _XDMA_DATA_MOVER_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Work around GCC 4.8 + XDMA BAR implementation bugs -// With -O3 PCIe BAR read/write are not reliable hence force -O2 as max -// optimization level for pcieBarRead() and pcieBarWrite() -#if defined(__GNUC__) && defined(NDEBUG) -#define SHIM_O2 __attribute__ ((optimize("-O2"))) -#else -#define SHIM_O2 -#endif - -#if defined(AWS_EDMA) - #define DMA_PATHNAME "/dev/edma" - #define DMA_PATHH2C "_queue_" - #define DMA_PATHC2H "_queue_" -#else - #define DMA_PATHNAME "/dev/xdma" - #define DMA_PATHH2C "_h2c_" - #define DMA_PATHC2H "_c2h_" -#endif - -namespace awsbwhal { - class DMAChannelManager - { - public: - DMAChannelManager(unsigned deviceIndex, unsigned count, std::ios_base::openmode mode) : mCount(count) { - std::string baseName(DMA_PATHNAME); - baseName += std::to_string(deviceIndex); - assert((mode == std::ios_base::in) || (mode == std::ios_base::out)); - const char *suffix = (mode == std::ios_base::out) ? DMA_PATHH2C : DMA_PATHC2H; - baseName += suffix; - for (mIndex = 0; mIndex < static_cast(mCount); ++mIndex) { - std::string fileName(baseName); - fileName += std::to_string(mIndex); - mChannel.push_back(open(fileName.c_str(), (mode == std::ios_base::out) ? O_WRONLY : O_RDONLY)); - } - --mIndex; - } - - ~DMAChannelManager() { - unlock(); - for (unsigned i = 0; i < mCount; i++) { - close(mChannel[i]); - } - } - - bool isGood() const { - for (unsigned i = 0; i < mCount; i++) { - if (mChannel[i] < 0) - return false; - } - return true; - } - - void releaseDMAChannel(int channel) { - std::lock_guard lck(mMtx); - mChannel[++mIndex] = channel; - mCV.notify_one(); - } - - int acquireDMAChannel() { - std::unique_lock lck(mMtx); - while(mIndex < 0) { - mCV.wait(lck); - } - return mChannel[mIndex--]; - } - - bool lock() const { - for (unsigned i = 0; i < mCount; i++) { - if (!flock(mChannel[i], LOCK_EX | LOCK_NB)) - continue; - // Unable to lock channel i, unlock all channels locked so far - for (unsigned j = 0; j < i; j++) { - flock(mChannel[j], LOCK_UN); - } - return false; - } - return true; - } - - void unlock() const { - for (unsigned i = 0; i < mCount; i++) { - flock(mChannel[i], LOCK_UN); - } - } - - unsigned channelCount() const { - return mCount; - } - - private: - std::mutex mMtx; - std::condition_variable mCV; - std::vector mChannel; - const unsigned mCount; - int mIndex; - }; - - class DataMover { - public: - DataMover(unsigned index, unsigned count) : mWrite(index, count, std::ios_base::out), - mRead(index, count, std::ios_base::in) {} - - // TODO: Make pwrite64 and pread64 use RAII for the channel resource - ssize_t pwrite64(const void* buf, size_t count, off64_t offset) { - if(count == 0) // Nothing to do - return 0; - int fd = mWrite.acquireDMAChannel(); - ssize_t rc = pwrite(fd, buf, count, offset); - mWrite.releaseDMAChannel(fd); - return rc; - } - ssize_t pread64(void* buf, size_t count, off64_t offset) { - if(count == 0) // Nothing to do - return 0; - int fd = mRead.acquireDMAChannel(); - ssize_t rc = pread(fd, buf, count, offset); - mRead.releaseDMAChannel(fd); - return rc; - } - // Like memset but using pwrite - void pset64(const void* buf, size_t count, off64_t offset, unsigned rep) { - if(count == 0) // Nothing to do - return; - int fd = mWrite.acquireDMAChannel(); - off64_t curr = offset; - while (rep-- > 0) { -#ifndef RDI_COVERITY -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-result" - pwrite(fd, buf, count, curr); -# pragma GCC diagnostic pop - curr += count; -#endif - } - mWrite.releaseDMAChannel(fd); - } - bool isGood() { - return (mWrite.isGood() && mRead.isGood()); - } - - int lock() { - if (mWrite.lock() && mRead.lock()) - return true; - unlock(); - return false; - } - - void unlock() { - mWrite.unlock(); - mRead.unlock(); - } - - unsigned channelCount() const { - return mWrite.channelCount() + mRead.channelCount(); - } - - private: - DMAChannelManager mWrite; - DMAChannelManager mRead; - }; -} - - -#endif diff --git a/SDAccel/userspace/src2/dd.cpp b/SDAccel/userspace/src/dd.cpp similarity index 100% rename from SDAccel/userspace/src2/dd.cpp rename to SDAccel/userspace/src/dd.cpp diff --git a/SDAccel/userspace/src2/dd.h b/SDAccel/userspace/src/dd.h similarity index 100% rename from SDAccel/userspace/src2/dd.h rename to SDAccel/userspace/src/dd.h diff --git a/SDAccel/userspace/src/debug.cpp b/SDAccel/userspace/src/debug.cpp index 3cfbb202..2c28ba8e 100644 --- a/SDAccel/userspace/src/debug.cpp +++ b/SDAccel/userspace/src/debug.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2017-2018 Xilinx, Inc * Debug functionality to AWS hal driver + * * Licensed under the Apache License, Version 2.0 (the "License"). You may * not use this file except in compliance with the License. A copy of the * License is located at @@ -16,8 +17,8 @@ #include "shim.h" -#include "datamover.h" #include "perfmon_parameters.h" +#include "xclbin.h" #include #include @@ -30,6 +31,7 @@ #include #include #include +#include #ifndef _WINDOWS // TODO: Windows build support @@ -47,22 +49,69 @@ namespace awsbwhal { // Helper functions // **************** - uint64_t AwsXcl::getProtocolCheckerBaseAddress(int type) { - switch (type) { - case 0: - return LAPC0_BASE; - case 1: - return LAPC1_BASE; - case 2: - return LAPC2_BASE; - case 3: - return LAPC3_BASE; - }; - return 0; + void AwsXcl::readDebugIpLayout() + { + if (mIsDebugIpLayoutRead) + return; + + // + // Profiling - addresses and names + // Parsed from debug_ip_layout.rtd contained in xclbin + if (mLogStream.is_open()) { + mLogStream << "debug_ip_layout: reading profile addresses and names..." << std::endl; + } + mMemoryProfilingNumberSlots = getIPCountAddrNames(AXI_MM_MONITOR, mPerfMonBaseAddress, mPerfMonSlotName); + mIsDeviceProfiling = (mMemoryProfilingNumberSlots > 0); + + std::string fifoName; + uint64_t fifoCtrlBaseAddr = mOffsets[XCL_ADDR_SPACE_DEVICE_PERFMON]; + getIPCountAddrNames(AXI_MONITOR_FIFO_LITE, &fifoCtrlBaseAddr, &fifoName); + mPerfMonFifoCtrlBaseAddress = fifoCtrlBaseAddr; + + uint64_t fifoReadBaseAddr = XPAR_AXI_PERF_MON_0_TRACE_OFFSET_AXI_FULL2; + getIPCountAddrNames(AXI_MONITOR_FIFO_FULL, &fifoReadBaseAddr, &fifoName); + mPerfMonFifoReadBaseAddress = fifoReadBaseAddr; + + if (mLogStream.is_open()) { + for (unsigned int i = 0; i < mMemoryProfilingNumberSlots; ++i) { + mLogStream << "debug_ip_layout: AXI_MM_MONITOR slot " << i << ": " + << "base address = 0x" << std::hex << mPerfMonBaseAddress[i] + << ", name = " << mPerfMonSlotName[i] << std::endl; + } + mLogStream << "debug_ip_layout: AXI_MONITOR_FIFO_LITE: " + << "base address = 0x" << std::hex << fifoCtrlBaseAddr << std::endl; + mLogStream << "debug_ip_layout: AXI_MONITOR_FIFO_FULL: " + << "base address = 0x" << std::hex << fifoReadBaseAddr << std::endl; + } + + // Only need to read it once + mIsDebugIpLayoutRead = true; } - uint32_t AwsXcl::getCheckerNumberSlots(int type) { - return getBankCount(); + // Gets the information about the specified IP from the sysfs debug_ip_table. + // The IP types are defined in xclbin.h + uint32_t AwsXcl::getIPCountAddrNames(int type, uint64_t *baseAddress, std::string * portNames) { + debug_ip_layout *map; + std::string path = "/sys/bus/pci/devices/" + mDevUserName + "/debug_ip_layout"; + std::ifstream ifs(path.c_str(), std::ifstream::binary); + uint32_t count = 0; + char buffer[4096]; + if( ifs ) { + //sysfs max file size is 4096 + ifs.read(buffer, 4096); + if (ifs.gcount() > 0) { + map = (debug_ip_layout*)(buffer); + for( unsigned int i = 0; i < map->m_count; i++ ) { + if (map->m_debug_ip_data[i].m_type == type) { + if(baseAddress)baseAddress[count] = map->m_debug_ip_data[i].m_base_address; + if(portNames) portNames[count] = (char*)map->m_debug_ip_data[i].m_name; + ++count; + } + } + } + ifs.close(); + } + return count; } // Read APM performance counters @@ -85,13 +134,14 @@ namespace awsbwhal { LAPC_SNAPSHOT_STATUS_2_OFFSET, LAPC_SNAPSHOT_STATUS_3_OFFSET }; - uint32_t numSlots = getCheckerNumberSlots(0); - + uint64_t baseAddress[XLAPC_MAX_NUMBER_SLOTS]; + uint32_t numSlots = getIPCountAddrNames(LAPC, baseAddress, nullptr); uint32_t temp[XLAPC_STATUS_PER_SLOT]; - for (int s = 0; s < numSlots; ++s) { - uint64_t baseAddress = getProtocolCheckerBaseAddress(s); + aCheckerResults->NumSlots = numSlots; + snprintf(aCheckerResults->DevUserName, 256, "%s", mDevUserName.c_str()); + for (uint32_t s = 0; s < numSlots; ++s) { for (int c=0; c < XLAPC_STATUS_PER_SLOT; c++) - size += xclRead(XCL_ADDR_SPACE_DEVICE_CHECKER, baseAddress+statusRegisters[c], &temp[c], 4); + size += xclRead(XCL_ADDR_SPACE_DEVICE_CHECKER, baseAddress[s]+statusRegisters[c], &temp[c], 4); aCheckerResults->OverallStatus[s] = temp[XLAPC_OVERALL_STATUS]; std::copy(temp+XLAPC_CUMULATIVE_STATUS_0, temp+XLAPC_SNAPSHOT_STATUS_0, aCheckerResults->CumulativeStatus[s]); @@ -102,6 +152,7 @@ namespace awsbwhal { } // Read APM performance counters + size_t AwsXcl::xclDebugReadCounters(xclDebugCountersResults* aCounterResults) { if (mLogStream.is_open()) { mLogStream << __func__ << ", " << std::this_thread::get_id() @@ -110,51 +161,47 @@ namespace awsbwhal { } size_t size = 0; - uint32_t scaleFactor = getPerfMonByteScaleFactor(XCL_PERF_MON_MEMORY); - uint64_t baseAddress = getPerfMonBaseAddress(XCL_PERF_MON_MEMORY); - - uint64_t metricAddress[] = { - // Slot 0 - baseAddress + XAPM_MC0_OFFSET, baseAddress + XAPM_MC1_OFFSET, - baseAddress + XAPM_MC3_OFFSET, baseAddress + XAPM_MC4_OFFSET, - // Slot 1 - baseAddress + XAPM_MC6_OFFSET, baseAddress + XAPM_MC7_OFFSET, - baseAddress + XAPM_MC9_OFFSET, baseAddress + XAPM_MC10_OFFSET, - // Slot 2 - baseAddress + XAPM_MC12_OFFSET, baseAddress + XAPM_MC13_OFFSET, - baseAddress + XAPM_MC15_OFFSET, baseAddress + XAPM_MC16_OFFSET, - // Slot 3 - baseAddress + XAPM_MC18_OFFSET, baseAddress + XAPM_MC19_OFFSET, - baseAddress + XAPM_MC21_OFFSET, baseAddress + XAPM_MC22_OFFSET, - // Slot 4 - baseAddress + XAPM_MC24_OFFSET, baseAddress + XAPM_MC25_OFFSET, - baseAddress + XAPM_MC27_OFFSET, baseAddress + XAPM_MC28_OFFSET, - // Slot 5 - baseAddress + XAPM_MC30_OFFSET, baseAddress + XAPM_MC31_OFFSET, - baseAddress + XAPM_MC33_OFFSET, baseAddress + XAPM_MC34_OFFSET, - // Slot 6 - baseAddress + XAPM_MC36_OFFSET, baseAddress + XAPM_MC37_OFFSET, - baseAddress + XAPM_MC39_OFFSET, baseAddress + XAPM_MC40_OFFSET, - // Slot 7 - baseAddress + XAPM_MC42_OFFSET, baseAddress + XAPM_MC43_OFFSET, - baseAddress + XAPM_MC45_OFFSET, baseAddress + XAPM_MC46_OFFSET, + + uint64_t spm_offsets[] = { + XSPM_SAMPLE_WRITE_BYTES_OFFSET, + XSPM_SAMPLE_WRITE_TRANX_OFFSET, + XSPM_SAMPLE_READ_BYTES_OFFSET, + XSPM_SAMPLE_READ_TRANX_OFFSET, + XSPM_SAMPLE_OUTSTANDING_COUNTS_OFFSET, + XSPM_SAMPLE_LAST_WRITE_ADDRESS_OFFSET, + XSPM_SAMPLE_LAST_WRITE_DATA_OFFSET, + XSPM_SAMPLE_LAST_READ_ADDRESS_OFFSET, + XSPM_SAMPLE_LAST_READ_DATA_OFFSET }; // Read all metric counters - uint32_t countnum = 0; - uint32_t numSlots = getPerfMonNumberSlots(XCL_PERF_MON_MEMORY); + uint64_t baseAddress[XSPM_MAX_NUMBER_SLOTS]; + uint32_t numSlots = getIPCountAddrNames(AXI_MM_MONITOR, baseAddress, nullptr); - uint32_t temp[XAPM_DEBUG_METRIC_COUNTERS_PER_SLOT]; + uint32_t temp[XSPM_DEBUG_SAMPLE_COUNTERS_PER_SLOT]; + aCounterResults->NumSlots = numSlots; + snprintf(aCounterResults->DevUserName, 256, "%s", mDevUserName.c_str()); for (uint32_t s=0; s < numSlots; s++) { - for (int c=0; c < XAPM_DEBUG_METRIC_COUNTERS_PER_SLOT; c++) - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, metricAddress[countnum++], &temp[c], 4); + uint32_t sampleInterval; + // Read sample interval register to latch the sampled metric counters + size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, + baseAddress[s] + XSPM_SAMPLE_OFFSET, + &sampleInterval, 4); + + for (int c=0; c < XSPM_DEBUG_SAMPLE_COUNTERS_PER_SLOT; c++) + size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress[s]+spm_offsets[c], &temp[c], 4); - aCounterResults->WriteBytes[s] = temp[0] * scaleFactor; + aCounterResults->WriteBytes[s] = temp[0]; aCounterResults->WriteTranx[s] = temp[1]; - aCounterResults->ReadBytes[s] = temp[2] * scaleFactor; + aCounterResults->ReadBytes[s] = temp[2]; aCounterResults->ReadTranx[s] = temp[3]; + aCounterResults->OutStandCnts[s] = temp[4]; + aCounterResults->LastWriteAddr[s] = temp[5]; + aCounterResults->LastWriteData[s] = temp[6]; + aCounterResults->LastReadAddr[s] = temp[7]; + aCounterResults->LastReadData[s] = temp[8]; } return size; } @@ -166,10 +213,12 @@ size_t xclDebugReadIPStatus(xclDeviceHandle handle, xclDebugReadType type, void* if (!drv) return -1; switch (type) { - case XCL_DEBUG_READ_TYPE_APM : - return drv->xclDebugReadCounters(reinterpret_cast(debugResults)); case XCL_DEBUG_READ_TYPE_LAPC : return drv->xclDebugReadCheckers(reinterpret_cast(debugResults)); + case XCL_DEBUG_READ_TYPE_SPM : + return drv->xclDebugReadCounters(reinterpret_cast(debugResults)); + default : + break; }; return -1; } diff --git a/SDAccel/userspace/src2/dmatest.h b/SDAccel/userspace/src/dmatest.h similarity index 99% rename from SDAccel/userspace/src2/dmatest.h rename to SDAccel/userspace/src/dmatest.h index de98ff80..3793a275 100644 --- a/SDAccel/userspace/src2/dmatest.h +++ b/SDAccel/userspace/src/dmatest.h @@ -25,7 +25,7 @@ #include #include -#include "xclhal2.h" +#include "xclhal.h" namespace xcldev { class Timer { diff --git a/SDAccel/userspace/src2/memaccess.h b/SDAccel/userspace/src/memaccess.h similarity index 99% rename from SDAccel/userspace/src2/memaccess.h rename to SDAccel/userspace/src/memaccess.h index 5d2b5715..abfc6826 100644 --- a/SDAccel/userspace/src2/memaccess.h +++ b/SDAccel/userspace/src/memaccess.h @@ -29,8 +29,9 @@ #include #include -#include "xclhal2.h" -#include "xclbin2.h" +#include "xclhal.h" +#include "xclbin.h" + namespace xcldev { class memaccess { xclDeviceHandle mHandle; diff --git a/SDAccel/userspace/src/memorymanager.cpp b/SDAccel/userspace/src/memorymanager.cpp deleted file mode 100644 index 748fea01..00000000 --- a/SDAccel/userspace/src/memorymanager.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/** - * Copyright (C) 2015-2018 Xilinx, Inc - * Author: Sonal Santan - * XDMA HAL Driver layered on top of XDMA kernel driver - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -#include "memorymanager.h" -#include -#include - -/* - * Define GCC version macro so we can use newer C++11 features - * if possible - */ -#define GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) - - -awsbwhal::MemoryManager::MemoryManager(uint64_t size, uint64_t start, - unsigned alignment) : mSize(size), mStart(start), mAlignment(alignment), - mCoalesceThreshold(4), mFreeSize(0) -{ - assert(start % alignment == 0); - mFreeBufferList.push_back(std::make_pair(mStart, mSize)); - mFreeSize = mSize; -} - -awsbwhal::MemoryManager::~MemoryManager() -{ - - -} - -uint64_t -awsbwhal::MemoryManager::alloc(size_t size) -{ - if (size == 0) - size = mAlignment; - - uint64_t result = mNull; - const size_t mod_size = size % mAlignment; - const size_t pad = (mod_size > 0) ? (mAlignment - mod_size) : 0; - size += pad; - - std::lock_guard lock(mMemManagerMutex); - for (PairList::iterator i = mFreeBufferList.begin(), e = mFreeBufferList.end(); i != e; ++i) { - if (i->second < size) - continue; - result = i->first; - if (i->second > size) { - // Resize the existing entry in freelist - i->first += size; - i->second -= size; - } - else { - // remove the exact match found - mFreeBufferList.erase(i); - } - mBusyBufferList.push_back(std::make_pair(result, size)); - mFreeSize -= size; - break; - } - return result; -} - -void -awsbwhal::MemoryManager::free(uint64_t buf) -{ - std::lock_guard lock(mMemManagerMutex); - PairList::iterator i = find(buf); - if (i == mBusyBufferList.end()) - return; - mFreeSize += i->second; - mFreeBufferList.push_back(std::make_pair(i->first, i->second)); - mBusyBufferList.erase(i); - if (mFreeBufferList.size() > mCoalesceThreshold) { - coalesce(); - } -} - - -void -awsbwhal::MemoryManager::coalesce() -{ - // First sort the free buffers and then attempt to coalesce the neighbors - mFreeBufferList.sort(); - - PairList::iterator curr = mFreeBufferList.begin(); - PairList::iterator next = curr; - ++next; - PairList::iterator last = mFreeBufferList.end(); - while (next != last) { - if ((curr->first + curr->second) != next->first) { - // Non contiguous blocks - curr = next; - ++next; - continue; - } - // Coalesce curr and next - curr->second += next->second; - mFreeBufferList.erase(next); - next = curr; - ++next; - } -} - -// Caller should have acquired the mutex lock before calling find(); -awsbwhal::MemoryManager::PairList::iterator -awsbwhal::MemoryManager::find(uint64_t buf) -{ -#if GCC_VERSION >= 40800 - PairList::iterator i = std::find_if(mBusyBufferList.begin(), mBusyBufferList.end(), [&] (const PairList::value_type& s) - { return s.first == buf; }); -#else - PairList::iterator i = mBusyBufferList.begin(); - PairList::iterator last = mBusyBufferList.end(); - while(i != last) { - if (i->first == buf) - break; - ++i; - } -#endif - return i; -} - -void -awsbwhal::MemoryManager::reset() -{ - std::lock_guard lock(mMemManagerMutex); - mFreeBufferList.clear(); - mBusyBufferList.clear(); - mFreeBufferList.push_back(std::make_pair(mStart, mSize)); - mFreeSize = 0; -} - -std::pair -awsbwhal::MemoryManager::lookup(uint64_t buf) -{ - std::lock_guard lock(mMemManagerMutex); - PairList::iterator i = find(buf); - if (i != mBusyBufferList.end()) - return *i; - // Compiler bug -- Some versions of GCC C++11 compiler do not - // like mNull directly inside std::make_pair, so capture mNull - // in a temporary - const uint64_t v = mNull; - return std::make_pair(v, v); -} - - -bool -awsbwhal::MemoryManager::reserve(uint64_t base, size_t size) -{ - assert(size); - if (size > mSize) - return false; - - if (base < mStart) - return false; - - if (base > (mStart + mSize)) - return false; - - const size_t mod_size = size % mAlignment; - const size_t pad = (mod_size > 0) ? (mAlignment - mod_size) : 0; - size += pad; - - std::lock_guard lock(mMemManagerMutex); - for (PairList::iterator i = mFreeBufferList.begin(), e = mFreeBufferList.end(); i != e; ++i) { - if (i->second < size) - continue; - if (i->first > base) - continue; - if ((base + size) > (i->first + i->second)) - continue; - uint64_t a = i->first; - uint64_t b = i->second; - - i->second = base - i->first; - if ((i->first == base) && (i->second == 0)) { - //Exact match - mFreeBufferList.erase(i); - break; - } - if (i->first == base) { - // Hole at the end; Resize exisiting entry - i->first = base + size; - break; - } - if ((i->first + i->second) == (base + size)) { - // Hole in the beginning; Resize exisiting entry - i->second -= size; - break; - } - // We have holes on both sides - // Resize hole in the beginning - i->second = base - i->first; - - // Now create an entry for the hole at the end - b = b + a - base - size; - a = base + size; - mFreeBufferList.insert(++i, std::make_pair(a, b)); - } - mBusyBufferList.push_back(std::make_pair(base, size)); - mFreeSize -= size; - return true; -} diff --git a/SDAccel/userspace/src/memorymanager.h b/SDAccel/userspace/src/memorymanager.h deleted file mode 100644 index 44dbf25e..00000000 --- a/SDAccel/userspace/src/memorymanager.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (C) 2015-2018 Xilinx, Inc - * Author: Sonal Santan - * Simple usermode XDMA DDR memory manager used by HAL - * Eventually the common code here will be used by all HAL drivers. - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -#ifndef _XDMA_MEMORY_MANAGER_H_ -#define _XDMA_MEMORY_MANAGER_H_ - -#include -#include -#include "xclhal.h" - -namespace awsbwhal { - class MemoryManager { - std::mutex mMemManagerMutex; - std::list > mFreeBufferList; - std::list > mBusyBufferList; - const uint64_t mSize; - const uint64_t mStart; - const uint64_t mAlignment; - const unsigned mCoalesceThreshold; - uint64_t mFreeSize; - - typedef std::list > PairList; - - public: - static const uint64_t mNull = 0xffffffffffffffffull; - - public: - MemoryManager(uint64_t size, uint64_t start, unsigned alignment); - ~MemoryManager(); - uint64_t alloc(size_t size); - void free(uint64_t buf); - void reset(); - std::pairlookup(uint64_t buf); - bool reserve(uint64_t base, size_t size); - - uint64_t size() const { - return mSize; - } - - uint64_t start() const { - return mStart; - } - - uint64_t freeSize() const { - return mFreeSize; - } - - static bool isNullAlloc(const std::pair& buf) { - return ((buf.first == mNull) || (buf.second == mNull)); - } - - private: - /* Note that these should be called after acquiring mMemManagerMutex */ - void coalesce(); - PairList::iterator find(uint64_t buf); - }; -} - -#endif diff --git a/SDAccel/userspace/src/perf.cpp b/SDAccel/userspace/src/perf.cpp index f26815c6..74a0d994 100644 --- a/SDAccel/userspace/src/perf.cpp +++ b/SDAccel/userspace/src/perf.cpp @@ -1,8 +1,7 @@ -/** +/* * Copyright (C) 2017-2018 Xilinx, Inc * Performance Monitoring using PCIe for AWS HAL Driver - * Author: Paul Schumacher - * + * * Licensed under the Apache License, Version 2.0 (the "License"). You may * not use this file except in compliance with the License. A copy of the * License is located at @@ -17,11 +16,12 @@ */ #include "shim.h" -#include "datamover.h" #include "perfmon_parameters.h" +#include "xocl/xocl_ioctl.h" #include #include +#include #include #include @@ -31,12 +31,20 @@ #include #include #include +#include #ifdef _WINDOWS #define __func__ __FUNCTION__ #endif namespace awsbwhal { + + static int unmgdPread(int fd, void *buffer, size_t size, uint64_t addr) + { + drm_xocl_pread_unmgd unmgd = { 0, 0, addr, size, reinterpret_cast(buffer) }; + return ioctl(fd, DRM_IOCTL_XOCL_PREAD_UNMGD, &unmgd); + } + // **************** // Helper functions // **************** @@ -45,8 +53,9 @@ namespace awsbwhal { return mDeviceInfo.mDDRBankCount; } - void AwsXcl::xclSetOclRegionProfilingNumberSlots(uint32_t numSlots) { - mOclRegionProfilingNumberSlots = numSlots; + void AwsXcl::xclSetProfilingNumberSlots(xclPerfMonType type, uint32_t numSlots) { + if (type == XCL_PERF_MON_OCL_REGION) + mOclRegionProfilingNumberSlots = numSlots; } // Get host timestamp to write to APM @@ -61,37 +70,18 @@ namespace awsbwhal { return (uint64_t) now.tv_sec * 1000000000UL + (uint64_t) now.tv_nsec; } - uint64_t AwsXcl::getPerfMonBaseAddress(xclPerfMonType type) { - if (type == XCL_PERF_MON_MEMORY) return PERFMON0_OFFSET; - if (type == XCL_PERF_MON_HOST_INTERFACE) return PERFMON1_OFFSET; - if (type == XCL_PERF_MON_OCL_REGION) return PERFMON2_OFFSET; + uint64_t AwsXcl::getPerfMonBaseAddress(xclPerfMonType type, uint32_t slotNum) { + if (type == XCL_PERF_MON_MEMORY) return mPerfMonBaseAddress[slotNum]; return 0; } uint64_t AwsXcl::getPerfMonFifoBaseAddress(xclPerfMonType type, uint32_t fifonum) { - if (type == XCL_PERF_MON_MEMORY) { - return PERFMON0_OFFSET + XPAR_AXI_PERF_MON_0_TRACE_OFFSET_0; - } - if (type == XCL_PERF_MON_OCL_REGION) { - if (fifonum == 0) return (PERFMON2_OFFSET + XPAR_AXI_PERF_MON_2_TRACE_OFFSET_0); - if (fifonum == 1) return (PERFMON2_OFFSET + XPAR_AXI_PERF_MON_2_TRACE_OFFSET_1); - if (fifonum == 2) return (PERFMON2_OFFSET + XPAR_AXI_PERF_MON_2_TRACE_OFFSET_2); - return 0; - } + if (type == XCL_PERF_MON_MEMORY) return mPerfMonFifoCtrlBaseAddress; return 0; } uint64_t AwsXcl::getPerfMonFifoReadBaseAddress(xclPerfMonType type, uint32_t fifonum) { - if (type == XCL_PERF_MON_MEMORY) { - // Use AXI-MM to access trace FIFO - return XPAR_AXI_PERF_MON_0_TRACE_OFFSET_AXI_FULL; - } - if (type == XCL_PERF_MON_OCL_REGION) { - if (fifonum == 0) return (PERFMON2_OFFSET + XPAR_AXI_PERF_MON_2_TRACE_OFFSET_0); - if (fifonum == 1) return (PERFMON2_OFFSET + XPAR_AXI_PERF_MON_2_TRACE_OFFSET_1); - if (fifonum == 2) return (PERFMON2_OFFSET + XPAR_AXI_PERF_MON_2_TRACE_OFFSET_2); - return 0; - } + if (type == XCL_PERF_MON_MEMORY) return mPerfMonFifoReadBaseAddress; return 0; } @@ -296,33 +286,39 @@ namespace awsbwhal { size_t AwsXcl::xclPerfMonStartCounters(xclPerfMonType type) { if (mLogStream.is_open()) { mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " - << type << ", Start device counters..." << std::endl; + << type << ", Start device counters..." << std::endl; } + // Update addresses for debug/profile IP + readDebugIpLayout(); + + if (!mIsDeviceProfiling) + return 0; + size_t size = 0; uint32_t regValue; - uint64_t baseAddress = getPerfMonBaseAddress(type); - - // 1. Reset APM metric counters - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XAPM_CTL_OFFSET, ®Value, 4); + uint64_t baseAddress; + uint32_t numSlots = getPerfMonNumberSlots(type); - regValue = regValue | XAPM_CR_MCNTR_RESET_MASK; - size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XAPM_CTL_OFFSET, ®Value, 4); + for (uint32_t i = 0; i < numSlots; i++) { + baseAddress = getPerfMonBaseAddress(type, i); - regValue = regValue & ~(XAPM_CR_MCNTR_RESET_MASK); - size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XAPM_CTL_OFFSET, ®Value, 4); + // 1. Reset AXI - MM monitor metric counters + size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_CONTROL_OFFSET, ®Value, 4); - // 2. Start APM metric counters - regValue = regValue | XAPM_CR_MCNTR_ENABLE_MASK; - size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XAPM_CTL_OFFSET, ®Value, 4); + regValue = regValue | XSPM_CR_COUNTER_RESET_MASK; + size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_CONTROL_OFFSET, ®Value, 4); - // 3. Specify APM metric counters to _not_ reset after reading - regValue = 0x0; - size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XAPM_SICR_OFFSET, ®Value, 4); + regValue = regValue & ~(XSPM_CR_COUNTER_RESET_MASK); + size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_CONTROL_OFFSET, ®Value, 4); - // 4. Read from sample register to ensure total time is read again at end - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XAPM_SR_OFFSET, ®Value, 4); + // 2. Start AXI-MM monitor metric counters + regValue = regValue | XSPM_CR_COUNTER_ENABLE_MASK; + size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_CONTROL_OFFSET, ®Value, 4); + // 3. Read from sample register to ensure total time is read again at end + size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_SAMPLE_OFFSET, ®Value, 4); + } return size; } @@ -330,19 +326,26 @@ namespace awsbwhal { size_t AwsXcl::xclPerfMonStopCounters(xclPerfMonType type) { if (mLogStream.is_open()) { mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " - << type << ", Stop and reset device counters..." << std::endl; + << type << ", Stop and reset device counters..." << std::endl; } + if (!mIsDeviceProfiling) + return 0; + size_t size = 0; uint32_t regValue; - uint64_t baseAddress = getPerfMonBaseAddress(type); + uint64_t baseAddress; + uint32_t numSlots = getPerfMonNumberSlots(type); - // 1. Stop APM metric counters - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XAPM_CTL_OFFSET, ®Value, 4); + for (uint32_t i = 0; i < numSlots; i++) { + baseAddress = getPerfMonBaseAddress(type, i); - regValue = regValue & ~(XAPM_CR_MCNTR_ENABLE_MASK); - size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XAPM_CTL_OFFSET, ®Value, 4); + // 1. Stop SPM metric counters + size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_CONTROL_OFFSET, ®Value, 4); + regValue = regValue & ~(XSPM_CR_COUNTER_ENABLE_MASK); + size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_CONTROL_OFFSET, ®Value, 4); + } return size; } @@ -350,92 +353,63 @@ namespace awsbwhal { size_t AwsXcl::xclPerfMonReadCounters(xclPerfMonType type, xclCounterResults& counterResults) { if (mLogStream.is_open()) { mLogStream << __func__ << ", " << std::this_thread::get_id() - << ", " << type << ", " << &counterResults - << ", Read device counters..." << std::endl; + << ", " << type << ", " << &counterResults + << ", Read device counters..." << std::endl; } // Initialize all values in struct to 0 memset(&counterResults, 0, sizeof(xclCounterResults)); - size_t size = 0; - uint32_t scaleFactor = getPerfMonByteScaleFactor(type); - uint64_t baseAddress = getPerfMonBaseAddress(type); - - uint64_t intervalAddress = baseAddress + XAPM_SR_OFFSET; - uint64_t metricAddress[] = { - // Slot 0 - baseAddress + XAPM_SMC0_OFFSET, baseAddress + XAPM_SMC1_OFFSET, - baseAddress + XAPM_SMC2_OFFSET, baseAddress + XAPM_SMC3_OFFSET, - baseAddress + XAPM_SMC4_OFFSET, baseAddress + XAPM_SMC5_OFFSET, - baseAddress + XAPM_SMC48_OFFSET, baseAddress + XAPM_SMC49_OFFSET, - // Slot 1 - baseAddress + XAPM_SMC6_OFFSET, baseAddress + XAPM_SMC7_OFFSET, - baseAddress + XAPM_SMC8_OFFSET, baseAddress + XAPM_SMC9_OFFSET, - baseAddress + XAPM_SMC10_OFFSET, baseAddress + XAPM_SMC11_OFFSET, - baseAddress + XAPM_SMC50_OFFSET, baseAddress + XAPM_SMC51_OFFSET, - // Slot 2 - baseAddress + XAPM_SMC12_OFFSET, baseAddress + XAPM_SMC13_OFFSET, - baseAddress + XAPM_SMC14_OFFSET, baseAddress + XAPM_SMC15_OFFSET, - baseAddress + XAPM_SMC16_OFFSET, baseAddress + XAPM_SMC17_OFFSET, - baseAddress + XAPM_SMC52_OFFSET, baseAddress + XAPM_SMC53_OFFSET, - // Slot 3 - baseAddress + XAPM_SMC18_OFFSET, baseAddress + XAPM_SMC19_OFFSET, - baseAddress + XAPM_SMC20_OFFSET, baseAddress + XAPM_SMC21_OFFSET, - baseAddress + XAPM_SMC22_OFFSET, baseAddress + XAPM_SMC23_OFFSET, - baseAddress + XAPM_SMC54_OFFSET, baseAddress + XAPM_SMC55_OFFSET, - // Slot 4 - baseAddress + XAPM_SMC24_OFFSET, baseAddress + XAPM_SMC25_OFFSET, - baseAddress + XAPM_SMC26_OFFSET, baseAddress + XAPM_SMC27_OFFSET, - baseAddress + XAPM_SMC28_OFFSET, baseAddress + XAPM_SMC29_OFFSET, - baseAddress + XAPM_SMC56_OFFSET, baseAddress + XAPM_SMC57_OFFSET, - // Slot 5 - baseAddress + XAPM_SMC30_OFFSET, baseAddress + XAPM_SMC31_OFFSET, - baseAddress + XAPM_SMC32_OFFSET, baseAddress + XAPM_SMC33_OFFSET, - baseAddress + XAPM_SMC34_OFFSET, baseAddress + XAPM_SMC35_OFFSET, - baseAddress + XAPM_SMC58_OFFSET, baseAddress + XAPM_SMC59_OFFSET, - // Slot 6 - baseAddress + XAPM_SMC36_OFFSET, baseAddress + XAPM_SMC37_OFFSET, - baseAddress + XAPM_SMC38_OFFSET, baseAddress + XAPM_SMC39_OFFSET, - baseAddress + XAPM_SMC40_OFFSET, baseAddress + XAPM_SMC41_OFFSET, - baseAddress + XAPM_SMC60_OFFSET, baseAddress + XAPM_SMC61_OFFSET, - // Slot 7 - baseAddress + XAPM_SMC42_OFFSET, baseAddress + XAPM_SMC43_OFFSET, - baseAddress + XAPM_SMC44_OFFSET, baseAddress + XAPM_SMC45_OFFSET, - baseAddress + XAPM_SMC46_OFFSET, baseAddress + XAPM_SMC47_OFFSET, - baseAddress + XAPM_SMC62_OFFSET, baseAddress + XAPM_SMC63_OFFSET - }; + if (!mIsDeviceProfiling) + return 0; - // Read sample interval register - // NOTE: this also latches the sampled metric counters + size_t size = 0; + uint64_t baseAddress; uint32_t sampleInterval; - size_t ret = xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, intervalAddress, &sampleInterval, 4); - if (ret < 0) return ret; - counterResults.SampleIntervalUsec = sampleInterval / xclGetDeviceClockFreqMHz(); - - // Read all sampled metric counters - uint32_t countnum = 0; uint32_t numSlots = getPerfMonNumberSlots(type); - //counterResults.NumSlots = numSlots; - - uint32_t temp[XAPM_METRIC_COUNTERS_PER_SLOT]; - for (uint32_t s=0; s < numSlots; s++) { - for (int c=0; c < XAPM_METRIC_COUNTERS_PER_SLOT; c++) - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, metricAddress[countnum++], &temp[c], 4); + for (uint32_t s = 0; s < numSlots; s++) { + baseAddress = getPerfMonBaseAddress(type, s); + + // Read sample interval register + // NOTE: this also latches the sampled metric counters + size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, + baseAddress + XSPM_SAMPLE_OFFSET, + &sampleInterval, 4); + // Need to do this for every xilmon + if (s == 0) { + counterResults.SampleIntervalUsec = sampleInterval / xclGetDeviceClockFreqMHz(); + } - counterResults.WriteBytes[s] = temp[XAPM_METRIC_WRITE_BYTES] * scaleFactor; - counterResults.WriteTranx[s] = temp[XAPM_METRIC_WRITE_TRANX]; - counterResults.WriteLatency[s] = temp[XAPM_METRIC_WRITE_LATENCY]; - counterResults.WriteMinLatency[s] = (temp[XAPM_METRIC_WRITE_MIN_MAX] & XAPM_MIN_LATENCY_MASK) >> XAPM_MIN_LATENCY_SHIFT; - counterResults.WriteMaxLatency[s] = (temp[XAPM_METRIC_WRITE_MIN_MAX] & XAPM_MAX_LATENCY_MASK) >> XAPM_MAX_LATENCY_SHIFT; + size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, + baseAddress + XSPM_SAMPLE_WRITE_BYTES_OFFSET, + &counterResults.WriteBytes[s], 4); + size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, + baseAddress + XSPM_SAMPLE_WRITE_TRANX_OFFSET, + &counterResults.WriteTranx[s], 4); + size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, + baseAddress + XSPM_SAMPLE_WRITE_LATENCY_OFFSET, + &counterResults.WriteLatency[s], 4); + size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, + baseAddress + XSPM_SAMPLE_READ_BYTES_OFFSET, + &counterResults.ReadBytes[s], 4); + size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, + baseAddress + XSPM_SAMPLE_READ_TRANX_OFFSET, + &counterResults.ReadTranx[s], 4); + size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, + baseAddress + XSPM_SAMPLE_READ_LATENCY_OFFSET, + &counterResults.ReadLatency[s], 4); - counterResults.ReadBytes[s] = temp[XAPM_METRIC_READ_BYTES] * scaleFactor; - counterResults.ReadTranx[s] = temp[XAPM_METRIC_READ_TRANX]; - counterResults.ReadLatency[s] = temp[XAPM_METRIC_READ_LATENCY]; - counterResults.ReadMinLatency[s] = (temp[XAPM_METRIC_READ_MIN_MAX] & XAPM_MIN_LATENCY_MASK) >> XAPM_MIN_LATENCY_SHIFT; - counterResults.ReadMaxLatency[s] = (temp[XAPM_METRIC_READ_MIN_MAX] & XAPM_MAX_LATENCY_MASK) >> XAPM_MAX_LATENCY_SHIFT; + if (mLogStream.is_open()) { + mLogStream << "Reading ...SlotNum : " << s << std::endl; + mLogStream << "Reading ...WriteBytes : " << counterResults.WriteBytes[s] << std::endl; + mLogStream << "Reading ...WriteTranx : " << counterResults.WriteTranx[s] << std::endl; + mLogStream << "Reading ...WriteLatency : " << counterResults.WriteLatency[s] << std::endl; + mLogStream << "Reading ...ReadBytes : " << counterResults.ReadBytes[s] << std::endl; + mLogStream << "Reading ...ReadTranx : " << counterResults.ReadTranx[s] << std::endl; + mLogStream << "Reading ...ReadLatency : " << counterResults.ReadLatency[s] << std::endl; + } } - return size; } @@ -447,85 +421,30 @@ namespace awsbwhal { size_t AwsXcl::xclPerfMonClockTraining(xclPerfMonType type) { if (mLogStream.is_open()) { mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " - << type << ", Send clock training..." << std::endl; - } - - size_t size = 0; - uint64_t baseAddress = getPerfMonBaseAddress(type); - - // Send host timestamps to target device - // NOTE: this is used for training to interpolate between time domains - for (int i=0; i < 3; i++) { -#if 1 - uint64_t hostTimeNsec = getHostTraceTimeNsec(); - - uint32_t hostTimeHigh = hostTimeNsec >> 32; - uint32_t hostTimeLow = hostTimeNsec & 0xffffffff; -#else - // Test values - uint32_t hostTimeHigh = 0xf00df00d; - uint32_t hostTimeLow = 0xdeadbeef; -#endif - - // Send upper then lower 32 bits of host timestamp to APM SW data register - size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XAPM_SWD_OFFSET, &hostTimeHigh, 4); - size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XAPM_SWD_OFFSET, &hostTimeLow, 4); - - if (mLogStream.is_open()) { - mLogStream << " Host timestamp: 0x" << std::hex << hostTimeHigh - << " " << hostTimeLow << std::dec << std::endl; - } + << type << ", Send clock training..." << std::endl; } - - return size; + // We're snapping first event to start of cu. + return 1; } // Start trace performance monitoring size_t AwsXcl::xclPerfMonStartTrace(xclPerfMonType type, uint32_t startTrigger) { if (mLogStream.is_open()) { mLogStream << __func__ << ", " << std::this_thread::get_id() - << ", " << type << ", " << startTrigger - << ", Start device tracing..." << std::endl; + << ", " << type << ", " << startTrigger + << ", Start device tracing..." << std::endl; } - size_t size = 0; - uint32_t regValue; - uint64_t ctrlAddress = getPerfMonBaseAddress(type) + XAPM_CTL_OFFSET; - xclAddressSpace addressSpace = (type == XCL_PERF_MON_OCL_REGION) ? - XCL_ADDR_KERNEL_CTRL : XCL_ADDR_SPACE_DEVICE_PERFMON; - - // 1. Reset APM trace stream FIFO - size += xclRead(addressSpace, ctrlAddress, ®Value, 4); - - regValue = regValue | XAPM_CR_FIFO_RESET_MASK; - size += xclWrite(addressSpace, ctrlAddress, ®Value, 4); + // Update addresses for debug/profile IP + readDebugIpLayout(); - regValue = regValue & ~(XAPM_CR_FIFO_RESET_MASK); - size += xclWrite(addressSpace, ctrlAddress, ®Value, 4); - - // 2. Start APM event log - regValue = regValue | XAPM_CR_EVENTLOG_ENABLE_MASK; - size += xclWrite(addressSpace, ctrlAddress, ®Value, 4); + if (!mIsDeviceProfiling) + return 0; - // 3. Reset trace FIFOs + size_t size = 0; + xclPerfMonGetTraceCount(type); size += resetFifos(type); - - // 4. Send host timestamps to target device - size += xclPerfMonClockTraining(type); - - // 5. Disable host monitoring on slot 1 - // TODO: replace check for value of startTrigger (temp way - // of keeping slot 1 enabled in 06_perfmon test) - if ((type == XCL_PERF_MON_MEMORY) && (startTrigger == 0)) { - regValue = 0xFFFFFF0F; - uint64_t enableTraceAddress = getPerfMonBaseAddress(type) + XAPM_ENT_OFFSET; - size += xclWrite(addressSpace, enableTraceAddress, ®Value, 4); - } - - // 6. Write to event trace trigger register - // TODO: add support for triggering in device here - //size += xclWrite(addressSpace, TBD, &startTrigger, 4); - + xclPerfMonGetTraceCount(type); return size; } @@ -533,23 +452,15 @@ namespace awsbwhal { size_t AwsXcl::xclPerfMonStopTrace(xclPerfMonType type) { if (mLogStream.is_open()) { mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " - << type << ", Stop and reset device tracing..." << std::endl; + << type << ", Stop and reset device tracing..." << std::endl; } - size_t size = 0; - uint32_t regValue; - uint64_t ctrlAddress = getPerfMonBaseAddress(type) + XAPM_CTL_OFFSET; - xclAddressSpace addressSpace = (type == XCL_PERF_MON_OCL_REGION) ? - XCL_ADDR_KERNEL_CTRL : XCL_ADDR_SPACE_DEVICE_PERFMON; - - // 1. Stop APM event log and metric counters - size += xclRead(addressSpace, ctrlAddress, ®Value, 4); - - regValue = regValue & ~(XAPM_CR_EVENTLOG_ENABLE_MASK); - size += xclWrite(addressSpace, ctrlAddress, ®Value, 4); + if (!mIsDeviceProfiling) + return 0; + size_t size = 0; + xclPerfMonGetTraceCount(type); size += resetFifos(type); - return size; } @@ -557,28 +468,26 @@ namespace awsbwhal { uint32_t AwsXcl::xclPerfMonGetTraceCount(xclPerfMonType type) { if (mLogStream.is_open()) { mLogStream << __func__ << ", " << std::this_thread::get_id() - << ", " << type << std::endl; + << ", " << type << std::endl; } + if (!mIsDeviceProfiling) + return 0; + xclAddressSpace addressSpace = (type == XCL_PERF_MON_OCL_REGION) ? - XCL_ADDR_KERNEL_CTRL : XCL_ADDR_SPACE_DEVICE_PERFMON; + XCL_ADDR_KERNEL_CTRL : XCL_ADDR_SPACE_DEVICE_PERFMON; - // Only read first FIFO (and assume the others have the same # words) - // NOTE: we do this for speed improvements - uint32_t fifoCount; + uint32_t fifoCount = 0; + uint32_t numSamples = 0; + uint32_t numBytes = 0; xclRead(addressSpace, getPerfMonFifoBaseAddress(type, 0) + AXI_FIFO_RLR, &fifoCount, 4); // Read bits 22:0 per AXI-Stream FIFO product guide (PG080, 10/1/14) - uint32_t numBytes = fifoCount & 0x7FFFFF; - - uint32_t numSamples = 0; - if (type == XCL_PERF_MON_MEMORY) - numSamples = numBytes / (XPAR_AXI_PERF_MON_0_TRACE_WORD_WIDTH/8); - else - numSamples = numBytes >> 2; + numBytes = fifoCount & 0x7FFFFF; + numSamples = numBytes / (XPAR_AXI_PERF_MON_0_TRACE_WORD_WIDTH / 8); if (mLogStream.is_open()) { mLogStream << " No. of trace samples = " << std::dec << numSamples - << " (fifoCount = 0x" << std::hex << fifoCount << ")" << std::dec << std::endl; + << " (fifoCount = 0x" << std::hex << fifoCount << ")" << std::dec << std::endl; } return numSamples; @@ -588,40 +497,28 @@ namespace awsbwhal { size_t AwsXcl::xclPerfMonReadTrace(xclPerfMonType type, xclTraceResultsVector& traceVector) { if (mLogStream.is_open()) { mLogStream << __func__ << ", " << std::this_thread::get_id() - << ", " << type << ", " << &traceVector - << ", Reading device trace stream..." << std::endl; + << ", " << type << ", " << &traceVector + << ", Reading device trace stream..." << std::endl; } traceVector.mLength = 0; + if (!mIsDeviceProfiling) + return 0; uint32_t numSamples = xclPerfMonGetTraceCount(type); if (numSamples == 0) return 0; - uint64_t fifoReadAddress[] = {0, 0, 0}; + uint64_t fifoReadAddress[] = { 0, 0, 0 }; if (type == XCL_PERF_MON_MEMORY) { fifoReadAddress[0] = getPerfMonFifoReadBaseAddress(type, 0) + AXI_FIFO_RDFD_AXI_FULL; } else { - for (int i=0; i < 3; i++) + for (int i = 0; i < 3; i++) fifoReadAddress[i] = getPerfMonFifoReadBaseAddress(type, i) + AXI_FIFO_RDFD; } - xclAddressSpace addressSpace = (type == XCL_PERF_MON_OCL_REGION) ? - XCL_ADDR_KERNEL_CTRL : XCL_ADDR_SPACE_DEVICE_PERFMON; - uint32_t numSlots = getPerfMonNumberSlots(type); - uint32_t numFifos = getPerfMonNumberFifos(type); - size_t size = 0; -#ifndef _WINDOWS - // TODO: Windows build support - // runtime array size is not supported - uint32_t temp[numFifos]; - memset(&temp, 0, numFifos*sizeof(uint32_t)); -#else - uint32_t temp[3]; - memset(&temp, 0, 3*sizeof(uint32_t)); -#endif // Limit to max number of samples so we don't overrun trace buffer on host uint32_t maxSamples = getPerfMonNumberSamples(type); @@ -636,23 +533,12 @@ namespace awsbwhal { // Create trace buffer on host (requires alignment) const int BUFFER_BYTES = MAX_TRACE_NUMBER_SAMPLES * bytesPerSample; const int BUFFER_WORDS = MAX_TRACE_NUMBER_SAMPLES * wordsPerSample; -#ifndef _WINDOWS -// TODO: Windows build support -// alignas is defined in c++11 #if GCC_VERSION >= 40800 - alignas(AXI_FIFO_RDFD_AXI_FULL) uint32_t hostbuf[BUFFER_WORDS]; + alignas(AXI_FIFO_RDFD_AXI_FULL)uint32_t hostbuf[BUFFER_WORDS]; #else AlignedAllocator alignedBuffer(AXI_FIFO_RDFD_AXI_FULL, BUFFER_WORDS); uint32_t* hostbuf = alignedBuffer.getBuffer(); #endif -#else - uint32_t hostbuf[BUFFER_WORDS]; -#endif - - // ****************************** - // Read all words from trace FIFO - // ****************************** - if (type == XCL_PERF_MON_MEMORY) { memset((void *)hostbuf, 0, BUFFER_BYTES); // Iterate over chunks @@ -660,18 +546,18 @@ namespace awsbwhal { uint32_t chunkSizeWords = 256 * wordsPerSample; if (chunkSizeWords > 1024) chunkSizeWords = 1024; uint32_t chunkSizeBytes = 4 * chunkSizeWords; - uint32_t words=0; + uint32_t words = 0; // Read trace a chunk of bytes at a time if (numWords > chunkSizeWords) { - for (; words < (numWords-chunkSizeWords); words += chunkSizeWords) { + for (; words < (numWords - chunkSizeWords); words += chunkSizeWords) { if (mLogStream.is_open()) { mLogStream << __func__ << ": reading " << chunkSizeBytes << " bytes from 0x" - << std::hex << fifoReadAddress[0] << " and writing it to 0x" - << (void *)(hostbuf + words) << std::dec << std::endl; + << std::hex << fifoReadAddress[0] << " and writing it to 0x" + << (void *)(hostbuf + words) << std::dec << std::endl; } - if (mDataMover->pread64((void *)(hostbuf + words), chunkSizeBytes, fifoReadAddress[0]) < 0) + if (awsbwhal::unmgdPread(mUserHandle, (void *)(hostbuf + words), chunkSizeBytes, fifoReadAddress[0]) < 0) return 0; size += chunkSizeBytes; @@ -684,11 +570,11 @@ namespace awsbwhal { if (mLogStream.is_open()) { mLogStream << __func__ << ": reading " << chunkSizeBytes << " bytes from 0x" - << std::hex << fifoReadAddress[0] << " and writing it to 0x" - << (void *)(hostbuf + words) << std::dec << std::endl; + << std::hex << fifoReadAddress[0] << " and writing it to 0x" + << (void *)(hostbuf + words) << std::dec << std::endl; } - if (mDataMover->pread64((void *)(hostbuf + words), chunkSizeBytes, fifoReadAddress[0]) < 0) + if (awsbwhal::unmgdPread(mUserHandle, (void *)(hostbuf + words), chunkSizeBytes, fifoReadAddress[0]) < 0) return 0; size += chunkSizeBytes; @@ -697,127 +583,45 @@ namespace awsbwhal { if (mLogStream.is_open()) { mLogStream << __func__ << ": done reading " << size << " bytes " << std::endl; } - } // ****************************** // Read & process all trace FIFOs // ****************************** - for (uint32_t wordnum=0; wordnum < numSamples; wordnum++) { - if (type == XCL_PERF_MON_MEMORY) { - uint32_t index = wordsPerSample * wordnum; - bool allZeros = true; - for (uint32_t fifonum=0; fifonum < numFifos; fifonum++) { - temp[fifonum] = *(hostbuf + index + fifonum); - allZeros &= (temp[fifonum] == 0); - } - if (allZeros) - continue; - } - else { - // NOTE: Using AXI-Lite so we use the same address with burst length of 1 word - for (uint32_t fifonum=0; fifonum < numFifos; fifonum++) - size += xclRead(addressSpace, fifoReadAddress[fifonum], &temp[fifonum], 4); - } - + for (uint32_t wordnum = 0; wordnum < numSamples; wordnum++) { + uint32_t index = wordsPerSample * wordnum; xclTraceResults results; - // Assign to all 0s to avoid uninitialized variables - memset(&results, 0, sizeof(xclTraceResults)); + uint64_t temp = 0; - uint64_t temp64 = ((uint64_t)temp[1] << 32) | temp[0]; - results.LogID = temp64 & 0x1; - results.Timestamp = (temp64 >> 1) & 0xFFFF; - results.Overflow = (temp64 >> 17) & 0x1; - results.ReadStartEvent = XCL_PERF_MON_START_ADDR; - results.WriteStartEvent = XCL_PERF_MON_START_ADDR; - results.WriteEndEvent = XCL_PERF_MON_END_LAST_DATA; - - if (results.LogID != 0) { - results.HostTimestamp = (temp64 >> 18) & 0xFFFFFFFF; - } - else { - for (uint32_t s=0; s < numSlots; s++) { - uint32_t b = getPerfMonSlotStartBit(type, s); - - if (b >= 32) - temp64 = ((((uint64_t)temp[2] << 32) | temp[1]) >> (b-32)); - else - temp64 = ((((uint64_t)temp[1] << 32) | temp[0]) >> b); - - results.ExtEventFlags[s] = temp64 & 0x7; - results.EventFlags[s] = (temp64 >> 3) & 0x7F; - - if (getPerfMonShowIDS(type)) { - if (getPerfMonShowLEN(type)) { - results.ReadAddrLen[s] = (temp64 >> 10) & 0xFF; - results.WriteAddrLen[s] = (temp64 >> 18) & 0xFF; - - // TODO: assumes AXI ID width of 5 - results.RID[s] = (temp64 >> 26) & 0x1F; - results.ARID[s] = (temp64 >> 31) & 0x1F; - results.BID[s] = (temp64 >> 36) & 0x1F; - results.AWID[s] = (temp64 >> 41) & 0x1F; - } - else { - // TODO: assumes AXI ID width of 5 - results.RID[s] = (temp64 >> 10) & 0x1F; - results.ARID[s] = (temp64 >> 15) & 0x1F; - results.BID[s] = (temp64 >> 20) & 0x1F; - results.AWID[s] = (temp64 >> 25) & 0x1F; - } - } - else { - if (getPerfMonShowLEN(type)) { - results.ReadAddrLen[s] = (temp64 >> 10) & 0xFF; - results.WriteAddrLen[s] = (temp64 >> 18) & 0xFF; - } - } - - // # bytes = burst length * bytes/burst = (addr len + 1) * bytes/burst - uint32_t dataWidth = getPerfMonSlotDataWidth(type, s); - results.ReadBytes[s] = (results.ReadAddrLen[s] + 1) * (dataWidth/8); - results.WriteBytes[s] = (results.WriteAddrLen[s] + 1) * (dataWidth/8); - } // for slot - } // if-else logID != 0 + temp = *(hostbuf + index) | (uint64_t)*(hostbuf + index + 1) << 32; + if (!temp) + continue; + // Initialize result to 0 + memset(&results, 0, sizeof(xclTraceResults)); + // SDSoC Packet Format + results.Timestamp = temp & 0x1FFFFFFFFFFF; + results.EventType = ((temp >> 45) & 0xF) ? XCL_PERF_MON_END_EVENT : + XCL_PERF_MON_START_EVENT; + results.TraceID = (temp >> 49) & 0xFFF; + results.Reserved = (temp >> 61) & 0x1; + results.Overflow = (temp >> 62) & 0x1; + results.Error = (temp >> 63) & 0x1; + results.EventID = XCL_PERF_MON_HW_EVENT; traceVector.mArray[wordnum] = results; - // Log values (if requested) -#if 1 if (mLogStream.is_open()) { mLogStream << " Trace sample " << std::dec << wordnum << ": "; - for (int fifonum=numFifos-1; fifonum >= 0; fifonum--) - mLogStream << dec2bin(temp[fifonum]) << " "; + mLogStream << dec2bin(uint32_t(temp >> 32)) << " " << dec2bin(uint32_t(temp & 0xFFFFFFFF)); + mLogStream << std::endl; + mLogStream << " Timestamp : " << results.Timestamp << " "; + mLogStream << "Event Type : " << results.EventType << " "; + mLogStream << "slotID : " << results.TraceID << " "; + mLogStream << "Start, Stop : " << static_cast(results.Reserved) << " "; + mLogStream << "Overflow : " << static_cast(results.Overflow) << " "; + mLogStream << "Error : " << static_cast(results.Error) << " "; mLogStream << std::endl; - - if (results.LogID == 1) { - mLogStream << std::hex << " Host Timestamp: " << results.HostTimestamp << std::endl; - } - else { - if (type == XCL_PERF_MON_OCL_REGION) { - mLogStream << " Ext Event flags: "; - for (int slot=numSlots-1; slot >= 0; slot--) - mLogStream << dec2bin(results.ExtEventFlags[slot], 3) << " "; - } - else { - mLogStream << " Event flags: "; - for (int slot=numSlots-1; slot >= 0; slot--) - mLogStream << dec2bin(results.EventFlags[slot], 7) << " "; - } - - mLogStream << "(ReadAddrLen[0] = " << (int)(results.ReadAddrLen[0]) - << ", WriteAddrLen[0] = " << (int)(results.WriteAddrLen[0]) - << ", ReadAddrLen[1] = " << (int)(results.ReadAddrLen[1]) - << ", WriteAddrLen[1] = " << (int)(results.WriteAddrLen[1]); - - if (getPerfMonShowIDS(type)) { - mLogStream << ", RID: " << (int)results.RID[0] << ", ARID: " << (int)results.ARID[0] - << ", BID: " << (int)results.BID[0] << ", AWID: " << (int)results.AWID[0]; - } - mLogStream << ")" << std::endl; - } } -#endif - } // for wordnum + } return size; } // end xclPerfMonReadTrace @@ -930,12 +734,26 @@ size_t xclGetDeviceTimestamp(xclDeviceHandle handle) } -void xclSetOclRegionProfilingNumberSlots(xclDeviceHandle handle, uint32_t numSlots) +void xclSetProfilingNumberSlots(xclDeviceHandle handle, xclPerfMonType type, uint32_t numSlots) { awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); if (!drv) return; - return drv->xclSetOclRegionProfilingNumberSlots(numSlots); + return drv->xclSetProfilingNumberSlots(type, numSlots); +} + + +uint32_t xclGetProfilingNumberSlots(xclDeviceHandle handle, xclPerfMonType type) +{ + return 2; +} + + +void xclGetProfilingSlotName(xclDeviceHandle handle, xclPerfMonType type, uint32_t slotnum, + char* slotName, uint32_t length) +{ + const char* name = (slotnum == XPAR_SPM0_HOST_SLOT) ? "Host" : "Kernels"; + strncpy(slotName, name, length); } @@ -944,3 +762,5 @@ void xclWriteHostEvent(xclDeviceHandle handle, xclPerfMonEventType type, { // don't do anything } + +// 67d7842dbbe25473c3c32b93c0da8047785f30d78e8a024de1b57352245f9689 diff --git a/SDAccel/userspace/src/perfmon_parameters.h b/SDAccel/userspace/src/perfmon_parameters.h index 0fc547c8..4a2f417b 100644 --- a/SDAccel/userspace/src/perfmon_parameters.h +++ b/SDAccel/userspace/src/perfmon_parameters.h @@ -1,8 +1,7 @@ -/** - * Copyright (C) 2016-2018 Xilinx, Inc - * Author: Sonal Santan - * Performance Monitoring Internal Parameters - * XDMA HAL multi-threading safe, multi-channel DMA read/write support +/* + * Copyright (C) 2018 Xilinx, Inc + * Performance Monitoring Internal Parameters using PCIe for AWS HAL Driver. + * NOTE: partially taken from file xaxipmon_hw.h in v5.0 of APM driver * * Licensed under the Apache License, Version 2.0 (the "License"). You may * not use this file except in compliance with the License. A copy of the @@ -28,12 +27,57 @@ /* Address offsets in core */ #define AXI_FIFO_RDFR 0x18 +#define AXI_FIFO_RDFO 0x1c #define AXI_FIFO_RDFD 0x20 #define AXI_FIFO_RDFD_AXI_FULL 0x1000 +#define AXI_FIFO_TDFD 0x10 #define AXI_FIFO_RLR 0x24 #define AXI_FIFO_SRR 0x28 #define AXI_FIFO_RESET_VALUE 0xA5 +/************************ SDx Performance Monitor(SPM) ************************/ + +/* Address offsets in core */ +#define XSPM_CONTROL_OFFSET 0x08 +#define XSPM_TRACE_CTRL_OFFSET 0x10 +#define XSPM_EVENT_OFFSET 0x18 +#define XSPM_SAMPLE_OFFSET 0x20 +#define XSPM_FIFO_COUNTS_OFFSET 0x28 +#define XSPM_FIFO_READ_COUNTS_OFFSET 0x30 +#define XSPM_WRITE_BYTES_OFFSET 0x40 +#define XSPM_WRITE_TRANX_OFFSET 0x44 +#define XSPM_WRITE_LATENCY_OFFSET 0x48 +#define XSPM_READ_BYTES_OFFSET 0x4C +#define XSPM_READ_TRANX_OFFSET 0x50 +#define XSPM_READ_LATENCY_OFFSET 0x54 +//#define XSPM_MIN_MAX_WRITE_LATENCY_OFFSET 0x58 +//#define XSPM_MIN_MAX_READ_LATENCY_OFFSET 0x5C +#define XSPM_OUTSTANDING_COUNTS_OFFSET 0x58 +#define XSPM_LAST_WRITE_ADDRESS_OFFSET 0x5C +#define XSPM_LAST_WRITE_DATA_OFFSET 0x60 +#define XSPM_LAST_READ_ADDRESS_OFFSET 0x64 +#define XSPM_LAST_READ_DATA_OFFSET 0x68 +#define XSPM_SAMPLE_WRITE_BYTES_OFFSET 0x80 +#define XSPM_SAMPLE_WRITE_TRANX_OFFSET 0x84 +#define XSPM_SAMPLE_WRITE_LATENCY_OFFSET 0x88 +#define XSPM_SAMPLE_READ_BYTES_OFFSET 0x8C +#define XSPM_SAMPLE_READ_TRANX_OFFSET 0x90 +#define XSPM_SAMPLE_READ_LATENCY_OFFSET 0x94 +//#define XSPM_SAMPLE_MIN_MAX_WRITE_LATENCY_OFFSET 0x98 +//#define XSPM_SAMPLE_MIN_MAX_READ_LATENCY_OFFSET 0x9C +#define XSPM_SAMPLE_OUTSTANDING_COUNTS_OFFSET 0x98 +#define XSPM_SAMPLE_LAST_WRITE_ADDRESS_OFFSET 0x9C +#define XSPM_SAMPLE_LAST_WRITE_DATA_OFFSET 0xA0 +#define XSPM_SAMPLE_LAST_READ_ADDRESS_OFFSET 0xA4 +#define XSPM_SAMPLE_LAST_READ_DATA_OFFSET 0xA8 + +/* SPM Control Register masks */ +#define XSPM_CR_RESET_ON_SAMPLE_MASK 0x00000010 +#define XSPM_CR_FIFO_RESET_MASK 0x00000008 +#define XSPM_CR_TRACE_ENABLE_MASK 0x00000004 +#define XSPM_CR_COUNTER_RESET_MASK 0x00000002 +#define XSPM_CR_COUNTER_ENABLE_MASK 0x00000001 + /************************ APM Constant Definitions ****************************/ /* Register offsets of AXIMONITOR in the Device Config */ @@ -113,7 +157,7 @@ #define XAPM_SINC8_OFFSET 0x0284 /**< Sampled Incrementer 8 Register */ #define XAPM_SMC9_OFFSET 0x0290 /**< Sampled Metric Counter 9 Register */ #define XAPM_SINC9_OFFSET 0x0294 /**< Sampled Incrementer 9 Register */ - + #define XAPM_MC10_OFFSET 0x01A0 /**< Metric Counter 10 Register */ #define XAPM_MC11_OFFSET 0x01B0 /**< Metric Counter 11 Register */ #define XAPM_MC12_OFFSET 0x0500 /**< Metric Counter 12 Register */ @@ -152,7 +196,7 @@ #define XAPM_MC45_OFFSET 0x0990 /**< Metric Counter 45 Register */ #define XAPM_MC46_OFFSET 0x09A0 /**< Metric Counter 46 Register */ #define XAPM_MC47_OFFSET 0x09B0 /**< Metric Counter 47 Register */ - + #define XAPM_SMC10_OFFSET 0x02A0 /**< Sampled Metric Counter 10 Register */ #define XAPM_SMC11_OFFSET 0x02B0 /**< Sampled Metric Counter 11 Register */ #define XAPM_SMC12_OFFSET 0x0600 /**< Sampled Metric Counter 12 Register */ @@ -208,7 +252,7 @@ #define XAPM_SMC61_OFFSET 0x0A58 /**< Sampled Metric Counter 61 Register */ #define XAPM_SMC62_OFFSET 0x0AB4 /**< Sampled Metric Counter 62 Register */ #define XAPM_SMC63_OFFSET 0x0AB8 /**< Sampled Metric Counter 63 Register */ - + #define XAPM_CTL_OFFSET 0x0300 /**< Control Register */ #define XAPM_ID_OFFSET 0x0304 /**< Latency ID Register */ #define XAPM_IDMASK_OFFSET 0x0308 /**< ID Mask Register */ diff --git a/SDAccel/userspace/src2/scan.cpp b/SDAccel/userspace/src/scan.cpp similarity index 100% rename from SDAccel/userspace/src2/scan.cpp rename to SDAccel/userspace/src/scan.cpp diff --git a/SDAccel/userspace/src2/scan.h b/SDAccel/userspace/src/scan.h similarity index 100% rename from SDAccel/userspace/src2/scan.h rename to SDAccel/userspace/src/scan.h diff --git a/SDAccel/userspace/src/shim.cpp b/SDAccel/userspace/src/shim.cpp index 5b81680a..2441035b 100644 --- a/SDAccel/userspace/src/shim.cpp +++ b/SDAccel/userspace/src/shim.cpp @@ -19,24 +19,21 @@ */ #include "shim.h" -#include "memorymanager.h" -#include "datamover.h" #include /* * Define GCC version macro so we can use newer C++11 features * if possible */ -#define GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ +#define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) -//TODO: umang #ifdef INTERNAL_TESTING #define ACCELERATOR_BAR 0 #define MMAP_SIZE_USER 0x400000 #endif -/* Kernels expect all buffers to be aligned at 4KB for AXI burst to/fro DDR */ +/* Aligning access to FPGA DRAM space to 4096 Byte */ #define DDR_BUFFER_ALIGNMENT 0x1000 #include @@ -55,206 +52,216 @@ #include #include #include +#include #include #include "xclbin.h" -#include "xdma/xdma_ioctl.h" +#include "xocl/xocl_ioctl.h" +#include "scan.h" +#include "awssak.h" #ifdef INTERNAL_TESTING - -#include "internal_use_only_mgmt/mgmt-ioctl.h" - +#include "driver/aws/kernel/include/mgmt-ioctl.h" #else - -#define XCLBIN_DOWNLOAD_RETRY 10 -#define XCLBIN_DOWNLOAD_WAIT 1 -#include -#include +#define AWSMGMT_NUM_SUPPORTED_CLOCKS 4 +#define AWSMGMT_NUM_ACTUAL_CLOCKS 3 // TODO - define this in a header file -extern const char* get_afi_from_xclBin(const xclBin *buffer); -extern const char *get_afi_from_axlf(const axlf *buffer); - +extern char* get_afi_from_xclBin(const xclBin *); +extern char* get_afi_from_axlf(const axlf *); +// define DEFAULT_GLOBAL_AFI "agfi-069ddd533a748059b" // 1.4 shell +#define DEFAULT_GLOBAL_AFI "agfi-0cc0ac6a40aa73ce8" // 1.4 shell 4-ddr data retention enabled #endif namespace awsbwhal { - const unsigned AwsXcl::TAG = 0X586C0C6C; // XL OpenCL X->58(ASCII), L->6C(ASCII), O->0 C->C L->6C(ASCII); + // This list will get populated in xclProbe + // 0 -> /dev/dri/renderD129 + // 1 -> /dev/dri/renderD130 static std::mutex deviceListMutex; - static std::vector deviceList; - - - static int findDMADevice(unsigned short domain, unsigned char bus, unsigned char dev, unsigned char func) - { - int i; - char file_name_buf[128]; - for (i = 0; i < 16; i++) { - std::sprintf((char *)&file_name_buf, "/dev/xdma%d_user", i); - int fd = open(file_name_buf, O_RDWR); - if (fd < 0) - continue; - xdma_ioc_info obj; - std::memset(&obj, 0, sizeof(xdma_ioc_info)); - obj.base.command = XDMA_IOCINFO; - obj.base.magic = 0X586C0C6C; - int ret = ioctl(fd, XDMA_IOCINFO, &obj); - close(fd); - if (ret) - continue; - if (obj.domain != domain) - continue; - if (obj.bus != bus) - continue; - if (obj.dev != dev) - continue; - if (obj.func != func) - continue; - return i; - } - return -1; - } + // static std::vector> deviceList; - int AwsXcl::setDDRCount(const axlf* buffer) - { - const char* str = (const char*) buffer->m_header.m_platformVBNV; - if(strstr(str, "1ddr-xpr")) { - m4DDR = false; - } else - m4DDR = true; - return 0; - } + const unsigned AwsXcl::TAG = 0X586C0C6C; // XL OpenCL X->58(ASCII), L->6C(ASCII), O->0 C->C L->6C(ASCII); +#ifdef INTERNAL_TESTING int AwsXcl::xclLoadAxlf(const axlf *buffer) { + if ( mLogStream.is_open()) { + mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << buffer << std::endl; + } + + if ( !mLocked) + return -EPERM; + + std::cout << "Downloading xclbin ...\n" << std::endl; + const unsigned cmd = AWSMGMT_IOCICAPDOWNLOAD_AXLF; + awsmgmt_ioc_bitstream_axlf obj = { const_cast(buffer) }; + int ret = ioctl(mMgtHandle, cmd, &obj); + if ( 0 != ret) + return ret; + + // If it is an XPR DSA, zero out the DDR again as downloading the XCLBIN + // reinitializes the DDR and results in ECC error. + if ( isXPR()) { if ( mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << buffer << std::endl; + mLogStream << __func__ << "XPR Device found, zeroing out DDR again.." << std::endl; } - if ( !mLocked) - return -EPERM; - - //set 1 or 4 ddr. - if(setDDRCount(buffer)) - return -EINVAL; - -#ifdef INTERNAL_TESTING - const unsigned cmd = AWSMGMT_IOCICAPDOWNLOAD_AXLF; - awsmgmt_ioc_bitstream_axlf obj = { const_cast(buffer) }; - return ioctl(mMgtHandle, cmd, &obj); -#else - const char* afi_id = get_afi_from_axlf(buffer); - if (!afi_id) - return -EINVAL; - - //skip redownload. - fpga_mgmt_image_info info; - int result = fpga_mgmt_describe_local_image(mBoardNumber, &info, 0); - if(!result && (info.status == FPGA_STATUS_LOADED)) { - if(strncmp(afi_id, info.ids.afi_id, sizeof(info.ids.afi_id)) == 0) { - //existing afi matched. - uint16_t status = 0; - result = fpga_mgmt_get_vDIP_status(mBoardNumber, &status); - if(result) { - printf("Error: can not get virtual DIP Switch state\n"); - return result; - } - //Set bit 0 to 1 - status |= (1 << 0); - result = fpga_mgmt_set_vDIP(mBoardNumber, status); - if(result) { - printf("Error trying to set virtual DIP Switch \n"); - return result; - } - std::this_thread::sleep_for(std::chrono::microseconds(250)); - //pulse the changes in. - result = fpga_mgmt_get_vDIP_status(mBoardNumber, &status); - if(result) { - printf("Error: can not get virtual DIP Switch state\n"); - return result; - } - //Set bit 0 to 0 - status &= ~(1 << 0); - result = fpga_mgmt_set_vDIP(mBoardNumber, status); - if(result) { - printf("Error trying to set virtual DIP Switch \n"); - return result; - } - std::this_thread::sleep_for(std::chrono::microseconds(250)); - - printf("Successfully skipped reloading of local image.\n"); - return result; - } - } - - //proceed with download. - result = fpga_mgmt_load_local_image(mBoardNumber, const_cast(afi_id)); - if (result) - return -EBUSY; - for (int i = 0; i < XCLBIN_DOWNLOAD_RETRY; i++) { - std::this_thread::sleep_for(std::chrono::seconds(XCLBIN_DOWNLOAD_WAIT)); - //fpga_mgmt_image_info info; - std::memset(&info, 0, sizeof(struct fpga_mgmt_image_info)); - result = fpga_mgmt_describe_local_image(mBoardNumber, &info, 0); - if (result) - return -EBUSY; - if ((info.status == FPGA_STATUS_LOADED) && !std::strcmp(info.ids.afi_id, afi_id)) - return 0; + if ( zeroOutDDR() == false) { + if ( mLogStream.is_open()) { + mLogStream << __func__ << "zeroing out DDR failed" << std::endl; + } + return -EIO; } - return -EBUSY; + } + + drm_xocl_axlf axlf_obj = {const_cast(buffer)}; + ret = ioctl(mUserHandle, DRM_IOCTL_XOCL_READ_AXLF, &axlf_obj); + return ret; + } #endif + + int AwsXcl::xclGetXclBinIdFromSysfs(uint64_t &xclbin_id_from_sysfs) + { + const std::string devPath = "/sys/bus/pci/devices/" + xcldev::pci_device_scanner::device_list[ mBoardNumber ].user_name; + std::string binid_path = devPath + "/xclbinid"; + struct stat sb; + if( stat( binid_path.c_str(), &sb ) < 0 ) { + std::cout << "ERROR: failed to stat " << binid_path << std::endl; + return errno; + } + std::ifstream ifs( binid_path.c_str(), std::ifstream::binary ); + if( !ifs.good() ) { + return errno; + } + char* fileReadBuf = new char[sb.st_size]; + memset(fileReadBuf, 0, sb.st_size); + ifs.read( fileReadBuf, sb.st_size ); + if( ifs.gcount() > 0 ) { + std::string tmp_hex_string = fileReadBuf; + xclbin_id_from_sysfs = std::stoi(std::string(fileReadBuf),nullptr,16); + } else { // xclbinid exists, but no data read or reported + std::cout << "WARNING: 'xclbinid' invalid, unable to report xclbinid. Has the bitstream been loaded? See 'xbsak program'.\n"; + } + delete [] fileReadBuf; + ifs.close(); + return 0; } int AwsXcl::xclLoadXclBin(const xclBin *buffer) { - const char *xclbininmemory = reinterpret_cast(buffer); - - if (!memcmp(xclbininmemory, "xclbin2", 8)){ - return xclLoadAxlf(reinterpret_cast(xclbininmemory)); - } + char *xclbininmemory = reinterpret_cast (const_cast (buffer)); +#ifdef INTERNAL_TESTING + if (!memcmp(xclbininmemory, "xclbin2", 8)) { + return xclLoadAxlf(reinterpret_cast(xclbininmemory)); + } - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << buffer << std::endl; - } + if (mLogStream.is_open()) { + mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << buffer << std::endl; + } - if (!mLocked) - return -EPERM; + if (!mLocked) + return -EPERM; -#ifdef INTERNAL_TESTING - const unsigned cmd = AWSMGMT_IOCICAPDOWNLOAD; - awsmgmt_ioc_bitstream obj = {const_cast(buffer)}; - return ioctl(mMgtHandle, cmd, &obj); + const unsigned cmd = AWSMGMT_IOCICAPDOWNLOAD; + awsmgmt_ioc_bitstream obj = {const_cast(buffer)}; + return ioctl(mMgtHandle, cmd, &obj); #else - const char* afi_id = get_afi_from_xclBin(buffer); - if (!afi_id) - return -EINVAL; - int result = fpga_mgmt_load_local_image(mBoardNumber, const_cast(afi_id)); - if (result) - return -EBUSY; - for (int i = 0; i < 10; i++) { - std::this_thread::sleep_for(std::chrono::seconds(1)); - fpga_mgmt_image_info info; - std::memset(&info, 0, sizeof(struct fpga_mgmt_image_info)); - result = fpga_mgmt_describe_local_image(mBoardNumber, &info, 0); - if (result) - return -EBUSY; - if (!std::strcmp(info.ids.afi_id, afi_id)) - return 0; - } - return -EBUSY; - // TODO - add printout and eror case handing + if (!memcmp(xclbininmemory, "xclbin2", 8)) { + int retVal = 0; + axlf *axlfbuffer = reinterpret_cast(const_cast (buffer)); + fpga_mgmt_image_info orig_info; + char* afi_id = get_afi_from_axlf(axlfbuffer); + std::memset(&orig_info, 0, sizeof(struct fpga_mgmt_image_info)); + fpga_mgmt_describe_local_image(mBoardNumber, &orig_info, 0); + + uint64_t xclbin_id_from_sysfs; + if( int retVal = xclGetXclBinIdFromSysfs( xclbin_id_from_sysfs ) != 0 ) + return retVal; + + if ( (xclbin_id_from_sysfs == 0) || (axlfbuffer->m_uniqueId != xclbin_id_from_sysfs) || checkAndSkipReload(afi_id, &orig_info) ) { + // force data retention option + union fpga_mgmt_load_local_image_options opt; + fpga_mgmt_init_load_local_image_options(&opt); + opt.flags = FPGA_CMD_DRAM_DATA_RETENTION; + opt.afi_id = afi_id; + opt.slot_id = mBoardNumber; + retVal = fpga_mgmt_load_local_image_with_options(&opt); + if (retVal == FPGA_ERR_DRAM_DATA_RETENTION_NOT_POSSIBLE || + retVal == FPGA_ERR_DRAM_DATA_RETENTION_FAILED || + retVal == FPGA_ERR_DRAM_DATA_RETENTION_SETUP_FAILED) { + std::cout << "INFO: Could not load AFI for data retention, code: " << retVal + << " - Loading in classic mode." << std::endl; + retVal = fpga_mgmt_load_local_image(mBoardNumber, afi_id); + } + // check retVal from image load + if (retVal) { + std::cout << "Failed to load AFI, error: " << retVal << std::endl; + return -retVal; + } + retVal = sleepUntilLoaded( std::string(afi_id) ); + if (!retVal) { + drm_xocl_axlf axlf_obj = { reinterpret_cast(const_cast(buffer)) }; + retVal = ioctl(mUserHandle, DRM_IOCTL_XOCL_READ_AXLF, &axlf_obj); + if (retVal) { + std::cout << "IOCTL DRM_IOCTL_XOCL_READ_AXLF Failed: " << retVal << std::endl; + } else { + std::cout << "AFI load complete." << std::endl; + } + } + } + return retVal; + } else { + char* afi_id = get_afi_from_xclBin(buffer); + return fpga_mgmt_load_local_image(mBoardNumber, afi_id); + } #endif } - /* Accessing F1 FPGA memory space (i.e. OpenCL Global Memory) is mapped through AppPF BAR4 * all offsets are relative to the base address available in AppPF BAR4 * SDAcell XCL_ADDR_SPACE_DEVICE_RAM enum maps to AwsXcl::ocl_global_mem_bar, which is the * handle for AppPF BAR4 */ + size_t AwsXcl::xclReadModifyWrite(uint64_t offset, const void *hostBuf, size_t size) { + if (mLogStream.is_open()) { + mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " + << offset << ", " << hostBuf << ", " << size << std::endl; + } +#if GCC_VERSION >= 40800 + alignas(DDR_BUFFER_ALIGNMENT) char buffer[DDR_BUFFER_ALIGNMENT]; +#else + AlignedAllocator alignedBuffer(DDR_BUFFER_ALIGNMENT, DDR_BUFFER_ALIGNMENT); + char* buffer = alignedBuffer.getBuffer(); +#endif + + const size_t mod_size = offset % DDR_BUFFER_ALIGNMENT; + // Read back one full aligned block starting from preceding aligned address + const uint64_t mod_offset = offset - mod_size; + if (xclRead(XCL_ADDR_SPACE_DEVICE_RAM, mod_offset, buffer, DDR_BUFFER_ALIGNMENT) != DDR_BUFFER_ALIGNMENT) + return -1; + + // Update the local copy of buffer with user requested data + const size_t copy_size = (size + mod_size > DDR_BUFFER_ALIGNMENT) ? DDR_BUFFER_ALIGNMENT - mod_size : size; + std::memcpy(buffer + mod_size, hostBuf, copy_size); + + // Write back the updated aligned block + if (xclWrite(XCL_ADDR_SPACE_DEVICE_RAM, mod_offset, buffer, DDR_BUFFER_ALIGNMENT) != DDR_BUFFER_ALIGNMENT) + return -1; + + // Write any remaining blocks over DDR_BUFFER_ALIGNMENT size + if (size + mod_size > DDR_BUFFER_ALIGNMENT) { + size_t write_size = xclWrite(XCL_ADDR_SPACE_DEVICE_RAM, mod_offset + DDR_BUFFER_ALIGNMENT, + (const char *)hostBuf + copy_size, size - copy_size); + if (write_size != (size - copy_size)) + return -1; + } + return size; + } /* Accessing F1 FPGA memory space mapped through AppPF PCIe BARs - * space = XCL_ADDR_SPACE_DEVICE_RAM maps to AppPF PCIe BAR4, (sh_cl_dma_pcis_ bus), with AwsXcl::ocl_global_mem_bar as handle - * space = XCL_ADDR_KERNEL_CTRL maps to AppPF PCIe BAR0 (sh_cl_ocl bus), with AwsXcl::ocl_kernel_bar as handle - * all offsets are relative to the base address available in AppPF - */ + * space = XCL_ADDR_SPACE_DEVICE_RAM maps to AppPF PCIe BAR4, (sh_cl_dma_pcis_ bus), with AwsXcl::ocl_global_mem_bar as handle + * space = XCL_ADDR_KERNEL_CTRL maps to AppPF PCIe BAR0 (sh_cl_ocl bus), with AwsXcl::ocl_kernel_bar as handle + * all offsets are relative to the base address available in AppPF + */ size_t AwsXcl::xclWrite(xclAddressSpace space, uint64_t offset, const void *hostBuf, size_t size) { if (mLogStream.is_open()) { mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << space << ", " @@ -262,35 +269,23 @@ namespace awsbwhal { } if (!mLocked) - return -EPERM; + return -1; switch (space) { - case XCL_ADDR_SPACE_DEVICE_RAM: - { - const size_t totalSize = size; - const char *curr = static_cast(hostBuf); - while (size > maxDMASize) { - if (mDataMover->pwrite64(curr,maxDMASize,offset) < 0) - return -EIO; - offset += maxDMASize; - curr += maxDMASize; - size -= maxDMASize; - } - if (mDataMover->pwrite64(curr,size,offset) < 0) - return -EIO; - return totalSize; - } + + /* Current release now includes performance monitors */ case XCL_ADDR_SPACE_DEVICE_PERFMON: { #ifdef INTERNAL_TESTING - const unsigned int pf_bar = ACCELERATOR_BAR; + if (pcieBarWrite(ACCELERATOR_BAR, offset, hostBuf, size) == 0) { + return size; + } #else - const unsigned int pf_bar = APP_PF_BAR0; -#endif - if (pcieBarWrite(pf_bar, offset, hostBuf, size) == 0) { + if (pcieBarWrite(APP_PF_BAR0, offset, hostBuf, size) == 0) { return size; } - return -EIO; +#endif + return -1; } case XCL_ADDR_KERNEL_CTRL: { @@ -306,22 +301,23 @@ namespace awsbwhal { } } #ifdef INTERNAL_TESTING - const unsigned int pf_bar = ACCELERATOR_BAR; + if (pcieBarWrite(ACCELERATOR_BAR, offset, hostBuf, size) == 0) { #else - const unsigned int pf_bar = APP_PF_BAR0; + if (pcieBarWrite(APP_PF_BAR0, offset, hostBuf, size) == 0) { + #endif - if (pcieBarWrite(pf_bar, offset, hostBuf, size) == 0) { return size; } - return -EIO; + return -1; } default: { - return -EINVAL; + return -1; } } } + size_t AwsXcl::xclRead(xclAddressSpace space, uint64_t offset, void *hostBuf, size_t size) { if (mLogStream.is_open()) { mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << space << ", " @@ -329,41 +325,26 @@ namespace awsbwhal { } switch (space) { - case XCL_ADDR_SPACE_DEVICE_RAM: - { - const size_t totalSize = size; - char *curr = static_cast(hostBuf); - while (size > maxDMASize) { - if (mDataMover->pread64(curr,maxDMASize,offset) < 0) - return -EIO; - offset += maxDMASize; - curr += maxDMASize; - size -= maxDMASize; - } - if (mDataMover->pread64(curr,size,offset) < 0) - return -EIO; - return totalSize; - } case XCL_ADDR_SPACE_DEVICE_PERFMON: { -#ifdef INTERNAL_TESTING - const unsigned int pf_bar = ACCELERATOR_BAR; +#ifdef INTERNAL_TESTING + if (pcieBarRead(ACCELERATOR_BAR, offset, hostBuf, size) == 0) { + return size; + } #else - const unsigned int pf_bar = APP_PF_BAR0; -#endif - if (pcieBarRead(pf_bar, offset, hostBuf, size) == 0) { + if (pcieBarRead(APP_PF_BAR0, offset, hostBuf, size) == 0) { return size; } - return -EIO; +#endif + return -1; } case XCL_ADDR_KERNEL_CTRL: { -#ifdef INTERNAL_TESTING - const unsigned int pf_bar = ACCELERATOR_BAR; +#ifdef INTERNAL_TESTING + int result = pcieBarRead(ACCELERATOR_BAR, offset, hostBuf, size); #else - const unsigned int pf_bar = APP_PF_BAR0; + int result = pcieBarRead(APP_PF_BAR0, offset, hostBuf, size); #endif - int result = pcieBarRead(pf_bar, offset, hostBuf, size); if (mLogStream.is_open()) { const unsigned *reg = static_cast(hostBuf); size_t regSize = size / 4; @@ -374,138 +355,116 @@ namespace awsbwhal { << std::hex << offset + i << std::dec << ", 0x" << std::hex << reg[i] << std::dec << std::endl; } } - return !result ? size : -EIO; + return !result ? size : 0; } default: { - return -EINVAL; + return -1; } } } uint64_t AwsXcl::xclAllocDeviceBuffer(size_t size) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << size << std::endl; - } - - if (size == 0) - size = DDR_BUFFER_ALIGNMENT; + if (mLogStream.is_open()) { + mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << size << std::endl; + } - uint64_t result = MemoryManager::mNull; + uint64_t result = mNullAddr; + unsigned boHandle = xclAllocBO(size, XCL_BO_DEVICE_RAM, 0x0); + if (boHandle == mNullBO) + return result; - if(!is4DDR()) { - return mDDRMemoryManager[0]->alloc(size); - } - - for (auto i : mDDRMemoryManager) { - result = i->alloc(size); - if (result != MemoryManager::mNull) - break; - } + drm_xocl_info_bo boInfo = {boHandle, 0, 0, 0}; + if (ioctl(mUserHandle, DRM_IOCTL_XOCL_INFO_BO, &boInfo)) return result; + + void *hbuf = xclMapBO(boHandle, true); + if (hbuf == MAP_FAILED) { + xclFreeBO(boHandle); + return mNullAddr; + } + mLegacyAddressTable.insert(boInfo.paddr, size, std::make_pair(boHandle, (char *)hbuf)); + return boInfo.paddr; } uint64_t AwsXcl::xclAllocDeviceBuffer2(size_t size, xclMemoryDomains domain, unsigned flags) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << size << ", " - << domain << ", " << flags << std::endl; - } + if (mLogStream.is_open()) { + mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << size << ", " + << domain << ", " << flags << std::endl; + } - if (domain != XCL_MEM_DEVICE_RAM) - return MemoryManager::mNull; + uint64_t result = mNullAddr; + if (domain != XCL_MEM_DEVICE_RAM) + return result; - if (size == 0) - size = DDR_BUFFER_ALIGNMENT; + unsigned ddr = 1; + ddr <<= flags; + unsigned boHandle = xclAllocBO(size, XCL_BO_DEVICE_RAM, ddr); + if (boHandle == mNullBO) + return result; - if(!is4DDR() && flags > 0) { - std::cout << "Trying to allocate past the 1 bank on the 1 DDR device " << std::endl; - return MemoryManager::mNull; - } + drm_xocl_info_bo boInfo = {boHandle, 0, 0, 0}; + if (ioctl(mUserHandle, DRM_IOCTL_XOCL_INFO_BO, &boInfo)) + return result; - if (flags >= mDDRMemoryManager.size()) { - return MemoryManager::mNull; - } - return mDDRMemoryManager[flags]->alloc(size); + void *hbuf = xclMapBO(boHandle, true); + if (hbuf == MAP_FAILED) { + xclFreeBO(boHandle); + return mNullAddr; + } + mLegacyAddressTable.insert(boInfo.paddr, size, std::make_pair(boHandle, (char *)hbuf)); + return boInfo.paddr; } - void AwsXcl::xclFreeDeviceBuffer(uint64_t buf) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << buf << std::endl; - } - - uint64_t size = 0; - for (auto i : mDDRMemoryManager) { - size += i->size(); - if (buf < size) { - i->free(buf); - } - } + void AwsXcl::xclFreeDeviceBuffer(uint64_t buf) + { + if (mLogStream.is_open()) { + mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << buf << std::endl; + } + + std::pair bo = mLegacyAddressTable.erase(buf); + drm_xocl_info_bo boInfo = {bo.first, 0, 0, 0}; + if (!ioctl(mUserHandle, DRM_IOCTL_XOCL_INFO_BO, &boInfo)) { + munmap(bo.second, boInfo.size); + } + xclFreeBO(bo.first); } - size_t AwsXcl::xclCopyBufferHost2Device(uint64_t dest, const void *src, size_t size, size_t seek) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << dest << ", " - << src << ", " << size << ", " << seek << std::endl; - } -#ifdef DEBUG - { - // Ensure that this buffer was allocated by memory manager before - const uint64_t v = MemoryManager::mNull; - std::pair buf = std::make_pair(v, v); - uint64_t high = 0; - for (auto i : mDDRMemoryManager) { - high += i->size(); - if (dest < high) { - buf = i->lookup(dest); - break; - } - } - if (MemoryManager::isNullAlloc(buf)) - return -1; - - if (buf.second < (size + seek)) - return -1; - } -#endif - dest += seek; - return xclWrite(XCL_ADDR_SPACE_DEVICE_RAM, dest, src, size); + size_t AwsXcl::xclCopyBufferHost2Device(uint64_t dest, const void *src, size_t size, size_t seek) + { + if (mLogStream.is_open()) { + mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << dest << ", " + << src << ", " << size << ", " << seek << std::endl; + } + + std::pair bo = mLegacyAddressTable.find(dest); + std::memcpy(bo.second + seek, src, size); + int result = xclSyncBO(bo.first, XCL_BO_SYNC_BO_TO_DEVICE, size, seek); + if (result) + return result; + return size; } - size_t AwsXcl::xclCopyBufferDevice2Host(void *dest, uint64_t src, size_t size, size_t skip) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << dest << ", " - << src << ", " << size << ", " << skip << std::endl; - } - - -#ifdef DEBUG - { - // Ensure that this buffer was allocated by memory manager before - const uint64_t v = MemoryManager::mNull; - std::pair buf = std::make_pair(v, v); - uint64_t high = 0; - for (auto i : mDDRMemoryManager) { - high += i->size(); - if (src < high) { - buf = i->lookup(src); - break; - } - } - if (MemoryManager::isNullAlloc(buf)) - return -1; - - if (buf.second < (size + skip)) - return -1; - } -#endif - src += skip; - return xclRead(XCL_ADDR_SPACE_DEVICE_RAM, src, dest, size); + size_t AwsXcl::xclCopyBufferDevice2Host(void *dest, uint64_t src, size_t size, size_t skip) + { + if (mLogStream.is_open()) { + mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << dest << ", " + << src << ", " << size << ", " << skip << std::endl; + } + + std::pair bo = mLegacyAddressTable.find(src); + int result = xclSyncBO(bo.first, XCL_BO_SYNC_BO_FROM_DEVICE, size, skip); + if (result) + return result; + std::memcpy(dest, bo.second + skip, size); + return size; } + AwsXcl *AwsXcl::handleCheck(void *handle) { // Sanity checks if (!handle) @@ -520,46 +479,37 @@ namespace awsbwhal { } unsigned AwsXcl::xclProbe() { -#if 0 - char file_name_buf[128]; - unsigned i = 0; - for (i = 0; i < 16; i++) { -#if defined(INTERNAL_TESTING) - std::sprintf((char *)&file_name_buf, "/dev/awsmgmt%d", i); -#elif defined(AWS_EDMA) - std::sprintf((char *)&file_name_buf, "/dev/edma%u_queue0", i); -#else - std::sprintf((char *)&file_name_buf, "/dev/xdma%u_user", i); + std::lock_guard lock(awsbwhal::deviceListMutex); + if(xcldev::pci_device_scanner::device_list.size() == 0) { + xcldev::pci_device_scanner devices; + devices.scan(true); + } + + unsigned i = 0; +#ifdef INTERNAL_TESTING + char file_name_buf[128]; + for (i = 0; i < 16; i++) { + std::sprintf((char *)&file_name_buf, "/dev/awsmgmt%d", i); + int fd = open(file_name_buf, O_RDWR); + if (fd < 0) { + return i; + } + close(fd); + } + if (i != xcldev::pci_device_scanner::device_list.size()) { + std::cout << "ERROR xclProbe: Num of FPGA userPF device do not match num of mgmtPF devices" << std::endl; + std::cout << "ERROR xclProbe: Num of userPF, mgmtPF devices = " << std::dec << xcldev::pci_device_scanner::device_list.size() << std::dec << i << std::endl; + return 0; + } #endif - int fd = open(file_name_buf, O_RDWR); - if (fd < 0) { - return i; - } - close(fd); - } + i = xcldev::pci_device_scanner::device_list.size(); + #ifndef INTERNAL_TESTING - if (fpga_mgmt_init() || fpga_pci_init() ) { - std::cout << "xclProbe failed to initialized fpga libraries" << std::endl; - return 0; - } - std::cout << "xclProbe found " << i << "FPGA slots with EDMA driver running" << std::endl; + std::cout << "xclProbe found " << std::dec << i << " FPGA slots with xocl driver running" << std::endl; #else - std::cout << "xclProbe found " << i << "FPGA slots with baremetal driver running" << std::endl; -#endif - return i; + std::cout << "xclProbe found " << std::dec << i << " FPGA slots with awsmgmt & xocl driver running" << std::endl; #endif - } - - void AwsXcl::initMemoryManager() - { - if (!mDeviceInfo.mDDRBankCount) - return; - const uint64_t bankSize = mDeviceInfo.mDDRSize / mDeviceInfo.mDDRBankCount; - uint64_t start = 0x0; - for (unsigned i = 0; i < mDeviceInfo.mDDRBankCount; i++) { - mDDRMemoryManager.push_back(new MemoryManager(bankSize, start, DDR_BUFFER_ALIGNMENT)); - start += bankSize; - } + return i; } AwsXcl::~AwsXcl() @@ -574,124 +524,158 @@ namespace awsbwhal { if (mMgtHandle > 0) close(mMgtHandle); #else - if (ocl_kernel_bar > PCI_BAR_HANDLE_INIT) +//# error "INTERNAL_TESTING macro disabled. AMZN code goes here. " + if (ocl_kernel_bar >=0) fpga_pci_detach(ocl_kernel_bar); - if (ocl_global_mem_bar > PCI_BAR_HANDLE_INIT) + if (ocl_global_mem_bar>=0) fpga_pci_detach(ocl_global_mem_bar); - if (sda_mgmt_bar > PCI_BAR_HANDLE_INIT) + if (sda_mgmt_bar>=0) fpga_pci_detach(sda_mgmt_bar); - ocl_kernel_bar = PCI_BAR_HANDLE_INIT; - ocl_global_mem_bar = PCI_BAR_HANDLE_INIT; - sda_mgmt_bar = PCI_BAR_HANDLE_INIT; + ocl_kernel_bar = -1; + ocl_global_mem_bar = -1; + sda_mgmt_bar = -1; #endif - delete mDataMover; - - for (auto i : mDDRMemoryManager) { - delete i; - } if (mLogStream.is_open()) { mLogStream << __func__ << ", " << std::this_thread::get_id() << std::endl; mLogStream.close(); } + + fpga_mgmt_close(); } AwsXcl::AwsXcl(unsigned index, const char *logfileName, xclVerbosityLevel verbosity) : mTag(TAG), mBoardNumber(index), - mDMADeviceNodeNumber(deviceList[index]), - maxDMASize(0xfa0000), - mLocked(false), - mOffsets{0x0, 0x0, 0x0, 0x0}, - mOclRegionProfilingNumberSlots(XPAR_AXI_PERF_MON_2_NUMBER_SLOTS), - m4DDR(true) + maxDMASize(0xfa0000), + mLocked(false), + mOffsets{0x0, 0x0, 0x0, 0x0}, + mOclRegionProfilingNumberSlots(XPAR_AXI_PERF_MON_2_NUMBER_SLOTS) { - int slot_id = mBoardNumber; - mDataMover = new DataMover(mDMADeviceNodeNumber, 4 /* 1 channel each dir */); - if (logfileName && (logfileName[0] != '\0')) { - mLogStream.open(logfileName); - mLogStream << "FUNCTION, THREAD ID, ARG..." << std::endl; - mLogStream << __func__ << ", " << std::this_thread::get_id() << std::endl; +#ifndef INTERNAL_TESTING + loadDefaultAfiIfCleared(); +#endif + const std::string devName = "/dev/dri/renderD" + std::to_string(xcldev::pci_device_scanner::device_list[mBoardNumber].user_instance); +#ifndef INTERNAL_TESTING + mUserHandle = open(devName.c_str(), O_RDWR); + if(mUserHandle <= 0) { + std::cout << "WARNING: AwsXcl - Cannot open userPF: " << devName << std::endl; } +#endif + + fpga_mgmt_init(); #ifdef INTERNAL_TESTING - char file_name_buf[128]; - std::sprintf((char *)&file_name_buf, "/dev/xdma%d_user", mDMADeviceNodeNumber); - mUserHandle = open(file_name_buf, O_RDWR | O_SYNC); - mUserMap = (char *)mmap(0, MMAP_SIZE_USER, PROT_READ | PROT_WRITE, MAP_SHARED, mUserHandle, 0); - if (mUserMap == MAP_FAILED) { - close(mUserHandle); - mUserHandle = -1; + if(mUserHandle > 0) { + mUserMap = (char *)mmap(0, MMAP_SIZE_USER, PROT_READ | PROT_WRITE, MAP_SHARED, mUserHandle, 0); + if (mUserMap == MAP_FAILED) { + std::cout << "Map failed: " << devName << std::endl; + close(mUserHandle); + mUserHandle = -1; + } } + char file_name_buf[128]; std::fill(&file_name_buf[0], &file_name_buf[0] + 128, 0); std::sprintf((char *)&file_name_buf, "/dev/awsmgmt%d", mBoardNumber); mMgtHandle = open(file_name_buf, O_RDWR | O_SYNC); - if (xclGetDeviceInfo2(&mDeviceInfo)) { - close(mUserHandle); - mUserHandle = -1; + if(mMgtHandle > 0) { + if (xclGetDeviceInfo2(&mDeviceInfo)) { + close(mMgtHandle); + mMgtHandle = -1; + } + } else { + std::cout << "Cannot open mgmtPF: " << devName << std::endl; } #else - ocl_kernel_bar = PCI_BAR_HANDLE_INIT; - ocl_global_mem_bar = PCI_BAR_HANDLE_INIT; - sda_mgmt_bar = PCI_BAR_HANDLE_INIT; + int slot_id = mBoardNumber; + ocl_kernel_bar = -1; + ocl_global_mem_bar = -1; + sda_mgmt_bar = -1; if (xclGetDeviceInfo2(&mDeviceInfo)) { - // print error; - } - else - if (fpga_pci_attach(slot_id, FPGA_APP_PF, APP_PF_BAR0, 0, &ocl_kernel_bar) ) { - ocl_kernel_bar = PCI_BAR_HANDLE_INIT; - // print error - } - else - if (fpga_pci_attach(slot_id, FPGA_APP_PF, APP_PF_BAR4, 0, &ocl_global_mem_bar) ) { - fpga_pci_detach(ocl_kernel_bar); - ocl_kernel_bar = PCI_BAR_HANDLE_INIT; - ocl_global_mem_bar = PCI_BAR_HANDLE_INIT; - sda_mgmt_bar = PCI_BAR_HANDLE_INIT; - // print error - } - else - if (fpga_pci_attach(slot_id, FPGA_MGMT_PF, MGMT_PF_BAR4, 0, &sda_mgmt_bar) ) { - // print error + std::cout << "ERROR AwsXcl: DeviceInfo failed for slot# " << std::dec << slot_id << std::endl; + } else if (fpga_pci_attach(slot_id, FPGA_APP_PF, APP_PF_BAR0, 0, &ocl_kernel_bar) ) { + ocl_kernel_bar = -1; + std::cout << "ERROR AwsXcl: PCI kernel bar attach failed for slot# " << std::dec << slot_id << std::endl; + } else if (fpga_pci_attach(slot_id, FPGA_APP_PF, APP_PF_BAR4, 0, &ocl_global_mem_bar) ) { + fpga_pci_detach(ocl_kernel_bar); + ocl_kernel_bar = -1; + ocl_global_mem_bar = -1; + sda_mgmt_bar = -1; + std::cout << "ERROR AwsXcl: PCI global bar attach failed for slot# " << std::dec << slot_id << std::endl; + } else if (fpga_pci_attach(slot_id, FPGA_MGMT_PF, MGMT_PF_BAR4, 0, &sda_mgmt_bar) ) { fpga_pci_detach(ocl_kernel_bar); fpga_pci_detach(ocl_global_mem_bar); - ocl_kernel_bar = PCI_BAR_HANDLE_INIT; - ocl_global_mem_bar = PCI_BAR_HANDLE_INIT; - sda_mgmt_bar = PCI_BAR_HANDLE_INIT; - } + ocl_kernel_bar = -1; + ocl_global_mem_bar = -1; + sda_mgmt_bar = -1; + std::cout << "ERROR AwsXcl: PCI mgmt bar attach failed for slot# " << std::dec << slot_id << std::endl; + } #endif - initMemoryManager(); + + // + // Profiling - defaults + // Class-level defaults: mIsDebugIpLayoutRead = mIsDeviceProfiling = false + mDevUserName = xcldev::pci_device_scanner::device_list[mBoardNumber].user_name; + mMemoryProfilingNumberSlots = 0; + mPerfMonFifoCtrlBaseAddress = 0x00; + mPerfMonFifoReadBaseAddress = 0x00; + // + // Profiling - defaults + // Class-level defaults: mIsDebugIpLayoutRead = mIsDeviceProfiling = false + mDevUserName = xcldev::pci_device_scanner::device_list[mBoardNumber].user_name; + mMemoryProfilingNumberSlots = 0; + mPerfMonFifoCtrlBaseAddress = 0x00; + mPerfMonFifoReadBaseAddress = 0x00; + + // + // Profiling - defaults + // Class-level defaults: mIsDebugIpLayoutRead = mIsDeviceProfiling = false + mDevUserName = xcldev::pci_device_scanner::device_list[mBoardNumber].user_name; + mMemoryProfilingNumberSlots = 0; + mPerfMonFifoCtrlBaseAddress = 0x00; + mPerfMonFifoReadBaseAddress = 0x00; } bool AwsXcl::isGood() const { - if (!mDataMover) - return false; #ifdef INTERNAL_TESTING - if (mUserHandle < 0) + if (mUserHandle < 0) { + std::cout << "AwsXcl: Bad handle. No userPF Handle" << std::endl; return false; - if (mMgtHandle < 0) + } + if (mMgtHandle < 0) { + std::cout << "AwsXcl: Bad handle. No mgmtPF Handle" << std::endl; return false; + } #else - if (ocl_kernel_bar < 0) - return false; - if (ocl_global_mem_bar < 0) - return false; - if (sda_mgmt_bar < 0) + if (ocl_kernel_bar < 0) { + std::cout << "WARNING: AwsXcl isGood: kernel, global & mgmt bar are: " << std::hex << ocl_kernel_bar << ", " << std::hex << ocl_global_mem_bar << ", " << sda_mgmt_bar << std::endl; + return false; + } + if (ocl_global_mem_bar < 0) { + std::cout << "WARNING: AwsXcl isGood: kernel, global & mgmt bar are: " << std::hex << ocl_kernel_bar << ", " << std::hex << ocl_global_mem_bar << ", " << sda_mgmt_bar << std::endl; + return false; + } + if (sda_mgmt_bar < 0) { + std::cout << "WARNING: AwsXcl isGood: kernel, global & mgmt bar are: " << std::hex << ocl_kernel_bar << ", " << std::hex << ocl_global_mem_bar << ", " << sda_mgmt_bar << std::endl; + return false; + } + if (mUserHandle <= 0) { + std::cout << "WARNING: AwsXcl isGood: invalid user handle." << std::endl; return false; + } #endif - return mDataMover->isGood(); - // TODO: Add sanity check for card state + return true; } - int AwsXcl::pcieBarRead(unsigned int pf_bar, unsigned long long offset, void* buffer, unsigned long long length) { - const char *mem = 0; + int AwsXcl::pcieBarRead(int bar_num, unsigned long long offset, void* buffer, unsigned long long length) { char *qBuf = (char *)buffer; - switch (pf_bar) { + switch (bar_num) { #ifdef INTERNAL_TESTING + const char *mem = 0; case 0: { if ((length + offset) > MMAP_SIZE_USER) { @@ -714,7 +698,7 @@ namespace awsbwhal { #ifdef INTERNAL_TESTING *(unsigned *)qBuf = *(unsigned *)(mem + offset); #else - fpga_pci_peek(ocl_kernel_bar, (uint64_t)offset,(uint32_t*)qBuf); + fpga_pci_peek(ocl_kernel_bar, (uint64_t)offset,(uint32_t*)qBuf); #endif offset += 4; qBuf += 4; @@ -725,7 +709,7 @@ namespace awsbwhal { *qBuf = *(mem + offset); #else - // TODO - add support for sub 4-byte read in AWS platform + // TODO - add support for sub 4-byte read in AWS platform #endif offset++; qBuf++; @@ -734,210 +718,197 @@ namespace awsbwhal { // std::memcpy(buffer, mem + offset, length); return 0; - } + } - int AwsXcl::pcieBarWrite(unsigned int pf_bar, unsigned long long offset, const void* buffer, - unsigned long long length) { - char *mem = 0; - char *qBuf = (char *)buffer; - switch (pf_bar) { + int AwsXcl::pcieBarWrite(int bar_num, unsigned long long offset, const void* buffer, unsigned long long length) { + char *qBuf = (char *)buffer; + switch (bar_num) { #ifdef INTERNAL_TESTING - case ACCELERATOR_BAR: - { - if ((length + offset) > MMAP_SIZE_USER) { - return -1; - } - mem = mUserMap; - break; - } + char *mem = 0; + case 0: + { + if ((length + offset) > MMAP_SIZE_USER) { + return -1; + } + mem = mUserMap; #else - case APP_PF_BAR0: - { - - break; - } + case APP_PF_BAR0: + { #endif - default: - { - return -1; - } - } + break; + } + default: + { + return -1; + } + } - while (length >= 4) { + while (length >= 4) { #ifdef INTERNAL_TESTING - *(unsigned *)(mem + offset) = *(unsigned *)qBuf; + *(unsigned *)(mem + offset) = *(unsigned *)qBuf; #else - fpga_pci_poke(ocl_kernel_bar, uint64_t (offset), *((uint32_t*) qBuf)); + fpga_pci_poke(ocl_kernel_bar, uint64_t (offset), *((uint32_t*) qBuf)); #endif - offset += 4; - qBuf += 4; - length -= 4; - } - while (length) { + offset += 4; + qBuf += 4; + length -= 4; + } + while (length) { #ifdef INTERNEL_TESTING - *(mem + offset) = *qBuf; + *(mem + offset) = *qBuf; #else - std::cout << "xclWrite - unsupported write with length not multiple of 4-bytes" << std::endl; + std::cout << "xclWrite - unsupported write with length not multiple of 4-bytes" << std::endl; #endif - offset++; - qBuf++; - length--; - } - return 0; + offset++; + qBuf++; + length--; } - bool AwsXcl::zeroOutDDR() - { - // Zero out the FPGA external DRAM Content so memory controller - // will not complain about ECC error from memory regions not - // initialized before - // In AWS F1 FPGA, the DRAM is clear before loading new AFI - // hence this API is redundant and will return false to - // make sure developers dont assume it works - - // static const unsigned long long BLOCK_SIZE = 0x4000000; +// std::memcpy(mem + offset, buffer, length); + return 0; + } + + bool AwsXcl::zeroOutDDR() + { + // Zero out the FPGA external DRAM Content so memory controller + // will not complain about ECC error from memory regions not + // initialized before + // In AWS F1 FPGA, the DRAM is clear before loading new AFI + // hence this API is redundant and will return false to + // make sure developers dont assume it works + + // static const unsigned long long BLOCK_SIZE = 0x4000000; // void *buf = 0; // if (posix_memalign(&buf, DDR_BUFFER_ALIGNMENT, BLOCK_SIZE)) // return false; // memset(buf, 0, BLOCK_SIZE); // mDataMover->pset64(buf, BLOCK_SIZE, 0, mDeviceInfo.mDDRSize/BLOCK_SIZE); // free(buf); - return false; - } + return false; + } - /* Locks a given FPGA Slot - * By levering the available lock infrastrucutre for the DMA - * Driver associated with the given FPGA slot - */ - bool AwsXcl::xclLockDevice() - { - if (mDataMover->lock() == false) - return false; + /* Locks a given FPGA Slot + * By levering the available lock infrastrucutre for the DMA + * Driver associated with the given FPGA slot + */ + bool AwsXcl::xclLockDevice() + { #ifdef INTERNAL_TESTING - if (flock(mUserHandle, LOCK_EX | LOCK_NB) == -1) { - mDataMover->unlock(); - return false; - } #else // FIXME: do we need to flock the ocl_kernel interface as well ? // #endif - mLocked = true; + mLocked = true; // return zeroOutDDR(); - return true; - } + return true; + } - const std::string AwsXcl::getDSAName(unsigned short deviceId, unsigned short subsystemId) - { - // Hard coded to AWS DSA name - return "xilinx:aws-vu9p-f1:4ddr-xpr-2pr:4.0"; - } + std::string AwsXcl::getDSAName(unsigned short deviceId, unsigned short subsystemId) + { + std::string dsa("xilinx_aws-vu9p-f1-04261818_dynamic_5_0"); + return dsa; + } - int AwsXcl::xclGetDeviceInfo2(xclDeviceInfo2 *info) - { - std::memset(info, 0, sizeof(xclDeviceInfo2)); - info->mMagic = 0X586C0C6C; - info->mHALMajorVersion = XCLHAL_MAJOR_VER; - info->mHALMajorVersion = XCLHAL_MINOR_VER; - info->mMinTransferSize = DDR_BUFFER_ALIGNMENT; - info->mDMAThreads = mDataMover->channelCount(); + int AwsXcl::xclGetDeviceInfo2(xclDeviceInfo2 *info) + { + std::memset(info, 0, sizeof(xclDeviceInfo2)); + info->mMagic = 0X586C0C6C; + info->mHALMajorVersion = XCLHAL_MAJOR_VER; + info->mHALMajorVersion = XCLHAL_MINOR_VER; + info->mMinTransferSize = DDR_BUFFER_ALIGNMENT; + info->mDMAThreads = 4;//AWS has four threads. Others have only two threads #ifdef INTERNAL_TESTING - xdma_ioc_info obj = {{0X586C0C6C, XDMA_IOCINFO}}; - /* Calling the underlying DMA driver to extract - * DMA specific configuration - * A non-zero value reprent at error - */ - int ret = ioctl(mUserHandle, XDMA_IOCINFO, &obj); - // Log the return value for further debug - if (ret) - return ret; - - awsmgmt_ioc_info mgmt_info_obj; - ret = ioctl(mMgtHandle, AWSMGMT_IOCINFO, &mgmt_info_obj); - if (ret) - return ret; - - for (int i = 0; i < 4 ; ++i) { - info->mOCLFrequency[i] = mgmt_info_obj.ocl_frequency[i]; - } - info->mVendorId = obj.vendor; - info->mDeviceId = obj.device; - info->mSubsystemId = obj.subsystem_device; - info->mSubsystemVendorId = obj.subsystem_vendor; - info->mDeviceVersion = obj.subsystem_device & 0x00ff; - info->mPCIeLinkWidth = mgmt_info_obj.pcie_link_width; - info->mPCIeLinkSpeed = mgmt_info_obj.pcie_link_speed; + /* Sarab disabling xdma ioctl + xdma_ioc_info obj = {{0X586C0C6C, XDMA_IOCINFO}}; + /--* Calling the underlying DMA driver to extract + * DMA specific configuration + * A non-zero value reprent at error + *--/ + int ret = ioctl(mUserHandle, XDMA_IOCINFO, &obj); + // Log the return value for further debug + if (ret) + return ret; + info->mVendorId = obj.vendor; + info->mDeviceId = obj.device; + info->mSubsystemId = obj.subsystem_device; + info->mSubsystemVendorId = obj.subsystem_vendor; + info->mDeviceVersion = obj.subsystem_device & 0x00ff; + */ + awsmgmt_ioc_info mgmt_info_obj; + int ret = ioctl(mMgtHandle, AWSMGMT_IOCINFO, &mgmt_info_obj); + if (ret) + return ret; + + info->mVendorId = mgmt_info_obj.vendor; + info->mDeviceId = mgmt_info_obj.device; + info->mSubsystemId = mgmt_info_obj.subsystem_device; + info->mSubsystemVendorId = mgmt_info_obj.subsystem_vendor; + info->mDeviceVersion = mgmt_info_obj.subsystem_device & 0x00ff; + info->mPCIeLinkWidth = mgmt_info_obj.pcie_link_width; + info->mPCIeLinkSpeed = mgmt_info_obj.pcie_link_speed; + for (int i = 0; i < AWSMGMT_NUM_SUPPORTED_CLOCKS; ++i) { + info->mOCLFrequency[i] = mgmt_info_obj.ocl_frequency[i]; + } + info->mMigCalib = true; + for (int i = 0; i < 4; i++) { + info->mMigCalib = info->mMigCalib && mgmt_info_obj.mig_calibration[i]; + } #else - struct fpga_slot_spec slot_info; - fpga_pci_get_slot_spec(mBoardNumber, &slot_info); - info->mVendorId = slot_info.map[FPGA_APP_PF].vendor_id; - info->mDeviceId = slot_info.map[FPGA_APP_PF].device_id; -// FIXME - update next 3 variables -// info->mSubsystemId = 0; - info->mSubsystemVendorId = 0; - info->mDeviceVersion = 0; - - for (int i = 0; i < 4 ; ++i) { - info->mOCLFrequency[i] = 0; - } - info->mPCIeLinkWidth = 16;// PCIe Gen3 x16 bus - info->mPCIeLinkSpeed = 8; // 8Gbps Gen3 in AWS F1 + struct fpga_slot_spec slot_info; + //fpga_pci_get_slot_spec(mBoardNumber,FPGA_APP_PF, &slot_info); + fpga_pci_get_slot_spec(mBoardNumber, &slot_info); + info->mVendorId = slot_info.map[0].vendor_id; + info->mDeviceId = slot_info.map[0].device_id; + // FIXME - update next 3 variables + info->mSubsystemId = slot_info.map[0].subsystem_device_id; + info->mSubsystemVendorId = slot_info.map[0].subsystem_vendor_id; + info->mDeviceVersion = 0; + info->mPCIeLinkWidth = 16; + info->mPCIeLinkSpeed = 8000; + fpga_mgmt_image_info imageInfo; + fpga_mgmt_describe_local_image( mBoardNumber, &imageInfo, 0 ); + for (int i = 0; i < AWSMGMT_NUM_SUPPORTED_CLOCKS; ++i) { + info->mOCLFrequency[i] = imageInfo.metrics.clocks[i].frequency[0] / 1000000; + } + info->mMigCalib = true; #endif - - // F1 has 16 GiB per channel - info->mDDRSize = 0x400000000 * 4; - info->mDataAlignment = DDR_BUFFER_ALIGNMENT; - info->mNumClocks = 4; - // Number of available channels - // TODO: add support for other FPGA configurations with less - // than 4 DRAM channels - info->mDDRBankCount = 4; - - for (auto i : mDDRMemoryManager) { - info->mDDRFreeSize += i->freeSize(); - } - - const std::string deviceName = getDSAName(info->mDeviceId, info->mSubsystemId); - if (mLogStream.is_open()) + // F1 has 16 GiB per channel + info->mDDRSize = 0x400000000 * 4; + info->mDataAlignment = DDR_BUFFER_ALIGNMENT; + info->mNumClocks = AWSMGMT_NUM_ACTUAL_CLOCKS; + // Number of available channels + // TODO: add support for other FPGA configurations with less + // than 4 DRAM channels + info->mDDRBankCount = 4; + + const std::string deviceName = getDSAName(info->mDeviceId, info->mSubsystemId); + if (mLogStream.is_open()) mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << deviceName << std::endl; - std::size_t length = deviceName.copy(info->mName, deviceName.length(),0); - info->mName[length] = '\0'; + std::size_t length = deviceName.copy(info->mName, deviceName.length(),0); + info->mName[length] = '\0'; - if (mLogStream.is_open()) { - mLogStream << __func__ << ": name=" << deviceName << ", version=0x" << std::hex << info->mDeviceVersion - << ", clock freq=" << std::dec << info->mOCLFrequency[0] - << ", clock freq 2=" << std::dec << info->mOCLFrequency[1] << std::endl; - } - - info->mMigCalib = true; - for (int i = 0; i < 4; i++) { -#ifdef INTERNAL_TEST - info->mMigCalib = info->mMigCalib && mgmt_info_obj.mig_calibration[i]; -#else - info->mMigCalib = 1; -#endif - } - //TODO: Umang - info->mOnChipTemp = 25; - info->mFanTemp = 0; - info->mVInt = 0.9; - info->mVAux = 0.9; - info->mVBram = 0.9; - return 0; + if (mLogStream.is_open()) { + mLogStream << __func__ << ": name=" << deviceName << ", version=0x" << std::hex << info->mDeviceVersion + << ", clock freq=" << std::dec << info->mOCLFrequency[0] + << ", clock freq 2=" << std::dec << info->mOCLFrequency[1] << std::endl; } - int AwsXcl::resetDevice(xclResetKind kind) { - for (auto i : mDDRMemoryManager) { - i->reset(); - } + info->mOnChipTemp = 25; + info->mFanTemp = 0; + info->mVInt = 0.9; + info->mVAux = 0.9; + info->mVBram = 0.9; + return 0; + } + + int AwsXcl::resetDevice(xclResetKind kind) { - // Call a new IOCTL to just reset the OCL region - // TODO : umang + // Call a new IOCTL to just reset the OCL region // if (kind == XCL_RESET_FULL) { // xdma_ioc_base obj = {0X586C0C6C, XDMA_IOCHOTRESET}; // return ioctl(mUserHandle, XDMA_IOCHOTRESET, &obj); @@ -948,230 +919,624 @@ namespace awsbwhal { // } // return -EINVAL; - // AWS FIXME - add reset - return 0; - } + // AWS FIXME - add reset + return 0; + } - int AwsXcl::xclReClock2(unsigned short region, const unsigned short *targetFreqMHz) - { -#ifdef INTERNAL_TESTING - awsmgmt_ioc_freqscaling obj = {0, targetFreqMHz[0], targetFreqMHz[1], 0, 0}; + int AwsXcl::xclReClock2(unsigned short region, const unsigned short *targetFreqMHz) + { + #ifdef INTERNAL_TESTING + awsmgmt_ioc_freqscaling obj = {0, targetFreqMHz[0], targetFreqMHz[1], targetFreqMHz[2], 0}; return ioctl(mMgtHandle, AWSMGMT_IOCFREQSCALING, &obj); -#else + #else // # error "INTERNAL_TESTING macro disabled. AMZN code goes here. " // # This API is not supported in AWS, the frequencies are set per AFI - return 0; -#endif - } + return 0; + #endif } - - xclDeviceHandle xclOpen(unsigned index, const char *logfileName, xclVerbosityLevel level) + ssize_t AwsXcl::xclUnmgdPwrite(unsigned flags, const void *buf, size_t count, uint64_t offset) { - if (index >= awsbwhal::deviceList.size()) - return 0; - awsbwhal::AwsXcl *handle = new awsbwhal::AwsXcl(index, logfileName, level); - if (!awsbwhal::AwsXcl::handleCheck(handle)) { - delete handle; - handle = 0; - } - return (xclDeviceHandle *)handle; + if (flags) + return -EINVAL; + drm_xocl_pwrite_unmgd unmgd = {0, 0, offset, count, reinterpret_cast(buf)}; + return ioctl(mUserHandle, DRM_IOCTL_XOCL_PWRITE_UNMGD, &unmgd); } - void xclClose(xclDeviceHandle handle) + ssize_t AwsXcl::xclUnmgdPread(unsigned flags, void *buf, size_t count, uint64_t offset) { - if (awsbwhal::AwsXcl::handleCheck(handle)) { - delete ((awsbwhal::AwsXcl *)handle); - } + if (flags) + return -EINVAL; + drm_xocl_pread_unmgd unmgd = {0, 0, offset, count, reinterpret_cast(buf)}; + return ioctl(mUserHandle, DRM_IOCTL_XOCL_PREAD_UNMGD, &unmgd); } - int xclGetDeviceInfo2(xclDeviceHandle handle, xclDeviceInfo2 *info) + int AwsXcl::xclExportBO(unsigned int boHandle) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclGetDeviceInfo2(info); + drm_prime_handle info = {boHandle, 0, -1}; + int result = ioctl(mUserHandle, DRM_IOCTL_PRIME_HANDLE_TO_FD, &info); + return !result ? info.fd : result; } - int xclLoadXclBin(xclDeviceHandle handle, const xclBin *buffer) + unsigned int AwsXcl::xclImportBO(int fd, unsigned flags) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclLoadXclBin(buffer); + + /*Sarab + drm_xocl_userptr_bo user = {reinterpret_cast(userptr), size, mNullBO, flags}; + int result = ioctl(mUserHandle, DRM_IOCTL_XOCL_USERPTR_BO, &user); + + */ + + + drm_prime_handle info = {mNullBO, flags, fd}; + int result = ioctl(mUserHandle, DRM_IOCTL_PRIME_FD_TO_HANDLE, &info); + if (result) { + std::cout << __func__ << " ERROR: FD to handle IOCTL failed" << std::endl; + } + return !result ? info.handle : mNullBO; } - size_t xclWrite(xclDeviceHandle handle, xclAddressSpace space, uint64_t offset, const void *hostBuf, size_t size) + int AwsXcl::xclGetBOProperties(unsigned int boHandle, xclBOProperties *properties) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclWrite(space, offset, hostBuf, size); + drm_xocl_info_bo info = {boHandle, 0, 0, 0}; + int result = ioctl(mUserHandle, DRM_IOCTL_XOCL_INFO_BO, &info); + properties->handle = info.handle; + properties->flags = info.flags; + properties->size = info.size; + properties->paddr = info.paddr; + properties->domain = XCL_BO_DEVICE_RAM; // currently all BO domains are XCL_BO_DEVICE_RAM + return result ? mNullBO : 0; } - size_t xclRead(xclDeviceHandle handle, xclAddressSpace space, uint64_t offset, void *hostBuf, size_t size) + bool AwsXcl::xclUnlockDevice() { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclRead(space, offset, hostBuf, size); + flock(mUserHandle, LOCK_UN); + mLocked = false; + return true; } - - uint64_t xclAllocDeviceBuffer(xclDeviceHandle handle, size_t size) + // Assume that the memory is always + // created for the device ddr for now. Ignoring the flags as well. + unsigned int AwsXcl::xclAllocBO(size_t size, xclBOKind domain, unsigned flags) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclAllocDeviceBuffer(size); + drm_xocl_create_bo info = {size, mNullBO, flags}; + int result = ioctl(mUserHandle, DRM_IOCTL_XOCL_CREATE_BO, &info); + if (result) { + std::cout << __func__ << " ERROR: AllocBO IOCTL failed" << std::endl; + } + return result ? mNullBO : info.handle; } - - uint64_t xclAllocDeviceBuffer2(xclDeviceHandle handle, size_t size, xclMemoryDomains domain, - unsigned flags) + unsigned int AwsXcl::xclAllocUserPtrBO(void *userptr, size_t size, unsigned flags) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclAllocDeviceBuffer2(size, domain, flags); + drm_xocl_userptr_bo user = {reinterpret_cast(userptr), size, mNullBO, flags}; + int result = ioctl(mUserHandle, DRM_IOCTL_XOCL_USERPTR_BO, &user); + return result ? mNullBO : user.handle; } - - void xclFreeDeviceBuffer(xclDeviceHandle handle, uint64_t buf) + void AwsXcl::xclFreeBO(unsigned int boHandle) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return; - return drv->xclFreeDeviceBuffer(buf); + drm_gem_close closeInfo = {boHandle, 0}; + ioctl(mUserHandle, DRM_IOCTL_GEM_CLOSE, &closeInfo); } - - size_t xclCopyBufferHost2Device(xclDeviceHandle handle, uint64_t dest, const void *src, size_t size, size_t seek) + int AwsXcl::xclWriteBO(unsigned int boHandle, const void *src, size_t size, size_t seek) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclCopyBufferHost2Device(dest, src, size, seek); + drm_xocl_pwrite_bo pwriteInfo = { boHandle, 0, seek, size, reinterpret_cast(src) }; + return ioctl(mUserHandle, DRM_IOCTL_XOCL_PWRITE_BO, &pwriteInfo); } - - size_t xclCopyBufferDevice2Host(xclDeviceHandle handle, void *dest, uint64_t src, size_t size, size_t skip) + int AwsXcl::xclReadBO(unsigned int boHandle, void *dst, size_t size, size_t skip) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclCopyBufferDevice2Host(dest, src, size, skip); + drm_xocl_pread_bo preadInfo = { boHandle, 0, skip, size, reinterpret_cast(dst) }; + return ioctl(mUserHandle, DRM_IOCTL_XOCL_PREAD_BO, &preadInfo); } - -//This will be deprecated. - int xclUpgradeFirmware(xclDeviceHandle handle, const char *fileName) + void *AwsXcl::xclMapBO(unsigned int boHandle, bool write) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return xclUpgradeFirmware2(handle, fileName, 0); + drm_xocl_info_bo info = { boHandle, 0, 0 }; + int result = ioctl(mUserHandle, DRM_IOCTL_XOCL_INFO_BO, &info); + if (result) + return nullptr; + + drm_xocl_map_bo mapInfo = { boHandle, 0, 0 }; + result = ioctl(mUserHandle, DRM_IOCTL_XOCL_MAP_BO, &mapInfo); + if (result) + return nullptr; + + return mmap(0, info.size, (write ? (PROT_READ|PROT_WRITE) : PROT_READ), + MAP_SHARED, mUserHandle, mapInfo.offset); } - int xclUpgradeFirmware2(xclDeviceHandle handle, const char *fileName1, const char* fileName2) + int AwsXcl::xclSyncBO(unsigned int boHandle, xclBOSyncDirection dir, + size_t size, size_t offset) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return -ENOSYS; + drm_xocl_sync_bo_dir drm_dir = (dir == XCL_BO_SYNC_BO_TO_DEVICE) ? + DRM_XOCL_SYNC_BO_TO_DEVICE : + DRM_XOCL_SYNC_BO_FROM_DEVICE; + drm_xocl_sync_bo syncInfo = {boHandle, 0, size, offset, drm_dir}; + return ioctl(mUserHandle, DRM_IOCTL_XOCL_SYNC_BO, &syncInfo); } - int xclBootFPGA(xclDeviceHandle handle) +#ifndef INTERNAL_TESTING + int AwsXcl::loadDefaultAfiIfCleared( void ) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return -ENOSYS; + int array_len = 16; + fpga_slot_spec spec_array[ array_len ]; + std::memset( spec_array, mBoardNumber, sizeof(fpga_slot_spec) * array_len ); + fpga_pci_get_all_slot_specs( spec_array, array_len ); + if( spec_array[mBoardNumber].map[FPGA_APP_PF].device_id == AWS_UserPF_DEVICE_ID ) { + std::string agfi = DEFAULT_GLOBAL_AFI; + fpga_mgmt_load_local_image( mBoardNumber, const_cast(agfi.c_str()) ); + if( sleepUntilLoaded( agfi ) ) { + std::cout << "ERROR: Sleep until load failed." << std::endl; + return -1; + } + fpga_pci_rescan_slot_app_pfs( mBoardNumber ); + } + return 0; } - unsigned xclProbe() + int AwsXcl::sleepUntilLoaded( const std::string afi ) { - std::lock_guard lock(awsbwhal::deviceListMutex); - if (awsbwhal::deviceList.size()) - return awsbwhal::deviceList.size(); + fpga_mgmt_image_info info; + int max_retries = 20; + int seconds_to_wait = 5; - unsigned i = 0; -#ifndef INTERNAL_TESTING - if (fpga_mgmt_init() || fpga_pci_init() ) { - std::cout << "xclProbe failed to initialized fpga libraries" << std::endl; - return 0; - } - fpga_slot_spec spec_array[16]; - std::memset(spec_array, 0, sizeof(fpga_slot_spec) * 16); - if (fpga_pci_get_all_slot_specs(spec_array, 16)) - return 0; + for( int i = 0; i < max_retries; i++ ) { + // Wait for 10 seconds before checking status + std::this_thread::sleep_for( std::chrono::seconds( seconds_to_wait ) ); + + std::memset( &info, 0, sizeof(struct fpga_mgmt_image_info) ); - unsigned short domain = 0; - unsigned char bus = 0, dev = 0, func = 0; - for (i = 0; i < 16; i++) { - if (spec_array[i].map[FPGA_APP_PF].vendor_id == 0) + // Get describe result in the info object + int result = fpga_mgmt_describe_local_image( mBoardNumber, &info, 0 ); + if( result ) { + std::cout << "ERROR: Load image failed." << std::endl; + return 1; + } + if( (info.status == FPGA_STATUS_LOADED) && !std::strcmp(info.ids.afi_id, const_cast(afi.c_str())) ) { break; + } - domain = spec_array[i].map[FPGA_APP_PF].domain; - bus = spec_array[i].map[FPGA_APP_PF].bus; - dev = spec_array[i].map[FPGA_APP_PF].dev; - func = spec_array[i].map[FPGA_APP_PF].func; + // Increment wait time + seconds_to_wait++; + } - int dmaIndex = awsbwhal::findDMADevice(domain, bus, dev, func); - if (dmaIndex < 0) - break; - awsbwhal::deviceList.push_back(dmaIndex); + // If after the timeout we check once more if our status is LOADED + if( info.status != FPGA_STATUS_LOADED ) { + std::cout << "ERROR: Load image failed after waiting till timeout." << std::endl; + return 1; + } - std::cout << "Device/Slot[" << i << "] (/dev/xdma" << dmaIndex << ", " << std::hex << domain << ":" << (unsigned)bus << ":" << (unsigned)dev << "." << (unsigned)func << std::dec << ')' << std::endl; + // After the AFI is loaded, we check again if the AFI ID is the correct one + if( std::strcmp(info.ids.afi_id, const_cast(afi.c_str())) ) { + std::cout << "ERROR: AFI loaded is not the one we are waiting on." << std::endl; + return 1; } -#else - char file_name_buf[128]; - for (i = 0; i < 16; i++) { - std::sprintf((char *)&file_name_buf, "/dev/awsmgmt%d", i); - int fd = open(file_name_buf, O_RDWR); - if (fd < 0) - break; - awsmgmt_ioc_info info; - if (ioctl(fd, AWSMGMT_IOCINFO, &info)) - break; - close(fd); - int dmaIndex = awsbwhal::findDMADevice(info.domain, info.bus, info.dev, 0); - if (dmaIndex < 0) - break; - awsbwhal::deviceList.push_back(dmaIndex); - std::cout << "Device[" << i << "] (/dev/xdma" << dmaIndex << ", " << std::hex << info.domain << ":" << (unsigned)info.bus << ":" << (unsigned)info.dev << ".0" << std::dec << ')' << std::endl; + + // If we have reached here, things look good + return 0; + } + + int AwsXcl::checkAndSkipReload( char *afi_id, fpga_mgmt_image_info *orig_info ) + { + if( (orig_info->status == FPGA_STATUS_LOADED) && !std::strcmp(orig_info->ids.afi_id, afi_id) ) { + std::cout << "This AFI already loaded. Skip reload!" << std::endl; + int result = 0; + //existing afi matched. + uint16_t status = 0; + result = fpga_mgmt_get_vDIP_status(mBoardNumber, &status); + if(result) { + printf("Error: can not get virtual DIP Switch state\n"); + return result; + } + //Set bit 0 to 1 + status |= (1 << 0); + result = fpga_mgmt_set_vDIP(mBoardNumber, status); + if(result) { + printf("Error trying to set virtual DIP Switch \n"); + return result; + } + std::this_thread::sleep_for(std::chrono::microseconds(250)); + //pulse the changes in. + result = fpga_mgmt_get_vDIP_status(mBoardNumber, &status); + if(result) { + printf("Error: can not get virtual DIP Switch state\n"); + return result; + } + //Set bit 0 to 0 + status &= ~(1 << 0); + result = fpga_mgmt_set_vDIP(mBoardNumber, status); + if(result) { + printf("Error trying to set virtual DIP Switch \n"); + return result; + } + std::this_thread::sleep_for(std::chrono::microseconds(250)); + + printf("Successfully skipped reloading of local image.\n"); + return result; + } else { + std::cout << "AFI not yet loaded, proceed to download." << std::endl; + return 1; } + } #endif +} /* end namespace awsbmhal */ + +xclDeviceHandle xclOpen(unsigned deviceIndex, const char *logFileName, xclVerbosityLevel level) +{ + if(xcldev::pci_device_scanner::device_list.size() <= deviceIndex) { + printf("Cannot find index %d \n", deviceIndex); + return nullptr; + } + + awsbwhal::AwsXcl *handle = new awsbwhal::AwsXcl(deviceIndex, logFileName, level); + if (!awsbwhal::AwsXcl::handleCheck(handle)) { + printf("WARNING: xclOpen Handle check failed\n"); + delete handle; + handle = nullptr; #ifndef INTERNAL_TESTING - std::cout << "xclProbe found " << i << " FPGA slots with XDMA driver running" << std::endl; -#else - std::cout << "xclProbe found " << i << " FPGA slots with baremetal driver running" << std::endl; + /* workaround necessary to load a default afi and program with xclbin when device is in a cleared state */ + xcldev::pci_device_scanner rescan; + rescan.clear_device_list(); + rescan.scan( true ); + for (unsigned int i=0; i(handle); +} + +void xclClose(xclDeviceHandle handle) { + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (drv) + delete drv; +} - int xclResetDevice(xclDeviceHandle handle, xclResetKind kind) +int xclGetDeviceInfo2(xclDeviceHandle handle, xclDeviceInfo2 *info) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return drv->xclGetDeviceInfo2(info); +} + +int xclLoadBitstream(xclDeviceHandle handle, const char *xclBinFileName) +{ + return -ENOSYS; +} + +int xclLoadXclBin(xclDeviceHandle handle, const xclBin *buffer) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return drv->xclLoadXclBin(buffer); +} + +size_t xclWrite(xclDeviceHandle handle, xclAddressSpace space, uint64_t offset, const void *hostBuf, size_t size) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return drv->xclWrite(space, offset, hostBuf, size); +} + +size_t xclRead(xclDeviceHandle handle, xclAddressSpace space, uint64_t offset, void *hostBuf, size_t size) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return drv->xclRead(space, offset, hostBuf, size); +} + + +uint64_t xclAllocDeviceBuffer(xclDeviceHandle handle, size_t size) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return drv->xclAllocDeviceBuffer(size); +} + + +uint64_t xclAllocDeviceBuffer2(xclDeviceHandle handle, size_t size, xclMemoryDomains domain, + unsigned flags) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return drv->xclAllocDeviceBuffer2(size, domain, flags); +} + + +void xclFreeDeviceBuffer(xclDeviceHandle handle, uint64_t buf) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return; + return drv->xclFreeDeviceBuffer(buf); +} + + +size_t xclCopyBufferHost2Device(xclDeviceHandle handle, uint64_t dest, const void *src, size_t size, size_t seek) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return drv->xclCopyBufferHost2Device(dest, src, size, seek); +} + + +size_t xclCopyBufferDevice2Host(xclDeviceHandle handle, void *dest, uint64_t src, size_t size, size_t skip) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return drv->xclCopyBufferDevice2Host(dest, src, size, skip); +} + + +//This will be deprecated. +int xclUpgradeFirmware(xclDeviceHandle handle, const char *fileName) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return xclUpgradeFirmware2(handle, fileName, 0); +} + +int xclUpgradeFirmware2(xclDeviceHandle handle, const char *fileName1, const char* fileName2) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return -ENOSYS; +} + +/* + * xclBootFPGA + * + * Sequence: + * 1) call boot ioctl + * 2) close the device, unload the driver + * 3) remove and scan + * 4) rescan pci devices + * 5) reload the driver (done by the calling function xcldev::boot()) + * + * Return 0 on success, -1 on failure. + */ +int xclBootFPGA(xclDeviceHandle handle) +{ +// awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); +// if (!drv) +// return -1; +// return -ENOSYS; + int retVal = -1; + + //awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); +// retVal = drv->xclBootFPGA(); // boot ioctl + retVal = 0; // skip boot ioctl since this may not be possible for AWS + + if( retVal == 0 ) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return -ENOSYS; + xclClose(handle); // close the device, unload the driver + retVal = xclRemoveAndScanFPGA(); // remove and scan } - int xclReClock2(xclDeviceHandle handle, unsigned short region, const unsigned short *targetFreqMHz) + if( retVal == 0 ) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclReClock2(region, targetFreqMHz); + xcldev::pci_device_scanner devScanner; + devScanner.scan( true ); // rescan pci devices } + return retVal; +} + +int xclRemoveAndScanFPGA( void ) +{ + const std::string devPath = "/devices/"; + const std::string removePath = "/remove"; + const std::string pciPath = "/sys/bus/pci"; + const std::string rescanPath = "/rescan"; + const char *input = "1\n"; - int xclLockDevice(xclDeviceHandle handle) + // remove devices "echo 1 > /sys/bus/pci/devices//remove" + for (unsigned int i = 0; i < xcldev::pci_device_scanner::device_list.size(); i++) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclLockDevice() ? 0 : -1; + std::string dev_name_pf_user = pciPath + devPath + xcldev::pci_device_scanner::device_list[i].user_name + removePath; + std::string dev_name_pf_mgmt = pciPath + devPath + xcldev::pci_device_scanner::device_list[i].mgmt_name + removePath; + + std::ofstream userFile( dev_name_pf_user ); + if( !userFile.is_open() ) { + perror( dev_name_pf_user.c_str() ); + return errno; + } + userFile << input; + + std::ofstream mgmtFile( dev_name_pf_mgmt ); + if( !mgmtFile.is_open() ) { + perror( dev_name_pf_mgmt.c_str() ); + return errno; + } + mgmtFile << input; + } + + std::this_thread::sleep_for(std::chrono::seconds(1)); + // initiate rescan "echo 1 > /sys/bus/pci/rescan" + std::ofstream rescanFile( pciPath + rescanPath ); + if( !rescanFile.is_open() ) { + perror( std::string( pciPath + rescanPath ).c_str() ); + return errno; } + rescanFile << input; + + return 0; +} + +unsigned xclProbe() +{ + return awsbwhal::AwsXcl::xclProbe(); +} + +int xclResetDevice(xclDeviceHandle handle, xclResetKind kind) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return -ENOSYS; +} + +int xclReClock2(xclDeviceHandle handle, unsigned short region, const unsigned short *targetFreqMHz) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return drv->xclReClock2(region, targetFreqMHz); +} + + +int xclLockDevice(xclDeviceHandle handle) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return drv->xclLockDevice() ? 0 : -1; +} + +//Sarab: Added for HAL2 support with XOCL GEM Driver + +int xclExportBO(xclDeviceHandle handle, unsigned int boHandle) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + return drv ? drv->xclExportBO(boHandle) : -ENODEV; +} + + +unsigned int xclImportBO(xclDeviceHandle handle, int fd, unsigned flags) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) { + std::cout << __func__ << ", " << std::this_thread::get_id() << ", handle & XOCL Device are bad" << std::endl; + } + return drv ? drv->xclImportBO(fd, flags) : -ENODEV; +} + +ssize_t xclUnmgdPwrite(xclDeviceHandle handle, unsigned flags, const void *buf, + size_t count, uint64_t offset) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + return drv ? drv->xclUnmgdPwrite(flags, buf, count, offset) : -ENODEV; +} + +int xclGetBOProperties(xclDeviceHandle handle, unsigned int boHandle, xclBOProperties *properties) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + return drv ? drv->xclGetBOProperties(boHandle, properties) : -ENODEV; +} + +ssize_t xclUnmgdPread(xclDeviceHandle handle, unsigned flags, void *buf, + size_t count, uint64_t offset) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + return drv ? drv->xclUnmgdPread(flags, buf, count, offset) : -ENODEV; +} + +int xclUpgradeFirmwareXSpi(xclDeviceHandle handle, const char *fileName, int index) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return -ENOSYS; + //return drv->xclUpgradeFirmwareXSpi(fileName, index); Not supported by AWS +} + +int xclUnlockDevice(xclDeviceHandle handle) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) { + std::cout << "xclUnlockDevice returning -ENODEV\n"; + return -ENODEV; + } else { + return drv->xclUnlockDevice() ? 0 : 1; + } +} + +unsigned int xclAllocBO(xclDeviceHandle handle, size_t size, xclBOKind domain, unsigned flags) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + return drv ? drv->xclAllocBO(size, domain, flags) : -ENODEV; +} + +unsigned int xclAllocUserPtrBO(xclDeviceHandle handle, void *userptr, size_t size, unsigned flags) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + return drv ? drv->xclAllocUserPtrBO(userptr, size, flags) : -ENODEV; +} + +void xclFreeBO(xclDeviceHandle handle, unsigned int boHandle) { + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return; + drv->xclFreeBO(boHandle); +} + +size_t xclWriteBO(xclDeviceHandle handle, unsigned int boHandle, const void *src, size_t size, + size_t seek) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + return drv ? drv->xclWriteBO(boHandle, src, size, seek) : -ENODEV; +} + +size_t xclReadBO(xclDeviceHandle handle, unsigned int boHandle, void *dst, size_t size, + size_t skip) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + return drv ? drv->xclReadBO(boHandle, dst, size, skip) : -ENODEV; +} + +void *xclMapBO(xclDeviceHandle handle, unsigned int boHandle, bool write) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + return drv ? drv->xclMapBO(boHandle, write) : nullptr; +} + + +int xclSyncBO(xclDeviceHandle handle, unsigned int boHandle, xclBOSyncDirection dir, + size_t size, size_t offset) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + return drv ? drv->xclSyncBO(boHandle, dir, size, offset) : -ENODEV; +} + +unsigned int xclVersion () { + return 2; +} + +int xclGetErrorStatus(xclDeviceHandle handle, xclErrorStatus *info) +{ + awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); + if (!drv) + return -1; + return -ENOSYS; + //return drv->xclGetErrorStatus(info); Not supported for AWS +} + +int xclXbsak(int argc, char *argv[]) +{ + return xcldev::xclXbsak(argc, argv); +} + diff --git a/SDAccel/userspace/src/shim.h b/SDAccel/userspace/src/shim.h index b52d548a..039909a3 100644 --- a/SDAccel/userspace/src/shim.h +++ b/SDAccel/userspace/src/shim.h @@ -17,20 +17,23 @@ * License for the specific language governing permissions and limitations * under the License. */ - #ifndef _XDMA_SHIM_H_ #define _XDMA_SHIM_H_ #include "xclhal.h" #include "xclperf.h" +#include "drm.h" #include #include +#include #include #include #include +#include #ifndef INTERNAL_TESTING #include "fpga_pci.h" +#include "fpga_mgmt.h" #endif // Work around GCC 4.8 + XDMA BAR implementation bugs @@ -43,6 +46,81 @@ #endif namespace awsbwhal { + + +struct AddresRange; + +std::ostream& operator<< (std::ostream &strm, const AddresRange &rng); + +/** + * Simple tuple struct to store non overlapping address ranges: address and size + */ +struct AddresRange : public std::pair { + // size will be zero when we are looking up an address that was passed by the user + AddresRange(uint64_t addr, size_t size = 0) : std::pair(std::make_pair(addr, size)) { + //std::cout << "CTOR(" << addr << ',' << size << ")\n"; + } + AddresRange(AddresRange && rhs) : std::pair(std::move(rhs)) { + //std::cout << "MOVE CTOR(" << rhs.first << ',' << rhs.second << ")\n"; + } + + AddresRange(const AddresRange &rhs) = delete; + AddresRange& operator=(const AddresRange &rhs) = delete; + + // Comparison operator is useful when using AddressRange as a key in std::map + // Note one operand in the comparator may have only the address without the size + // However both operands in the comparator will not have zero size + bool operator < (const AddresRange& other) const { + //std::cout << *this << " < " << other << "\n"; + if ((this->second != 0) && (other.second != 0)) + // regular ranges + return (this->first < other.first); + if (other.second == 0) + // second range just has an address + // (1000, 100) < (1200, 0) + // (1000, 100) < (1100, 0) first range ends at 1099 + return ((this->first + this->second) <= other.first); + assert(this->second == 0); + // this range just has an address + // (1100, 0) < (1200, 100) + return (this->first < other.first); + } +}; + +/** + * Simple map of address range to its bo handle and mapped virtual address + */ +static const std::pair mNullValue = std::make_pair(0xffffffff, nullptr); +class RangeTable { + std::map> mTable; + mutable std::mutex mMutex; +public: + void insert(uint64_t addr, size_t size, std::pair bo) { + // assert(find(addr) == 0xffffffff); + std::lock_guard lock(mMutex); + mTable[AddresRange(addr, size)] = bo; + } + + std::pair erase(uint64_t addr) { + std::lock_guard lock(mMutex); + std::map>::const_iterator i = mTable.find(AddresRange(addr)); + if (i == mTable.end()) + return mNullValue; + std::pair result = i->second; + mTable.erase(i); + return result; + } + + std::pair find(uint64_t addr) const { + std::lock_guard lock(mMutex); + std::map>::const_iterator i = mTable.find(AddresRange(addr)); + if (i == mTable.end()) + return mNullValue; + return i->second; + } +}; + + // Memory alignment for DDR and AXI-MM trace access template class AlignedAllocator { void *mBuffer; @@ -67,8 +145,9 @@ namespace awsbwhal { } }; - class MemoryManager; - class DataMover; + const uint64_t mNullAddr = 0xffffffffffffffffull; + const uint64_t mNullBO = 0xffffffff; + // XDMA Shim class AwsXcl{ @@ -87,14 +166,38 @@ namespace awsbwhal { typedef std::list > PairList; public: + //Sarab: Added for HAL2 XOCL Driver support + //int xclGetErrorStatus(xclErrorStatus *info); Not supported for AWS + bool xclUnlockDevice(); + unsigned int xclAllocBO(size_t size, xclBOKind domain, unsigned flags); + unsigned int xclAllocUserPtrBO(void *userptr, size_t size, unsigned flags); + void xclFreeBO(unsigned int boHandle); + int xclWriteBO(unsigned int boHandle, + const void *src, size_t size, size_t seek); + int xclReadBO(unsigned int boHandle, + void *dst, size_t size, size_t skip); + void *xclMapBO(unsigned int boHandle, bool write); + int xclSyncBO(unsigned int boHandle, xclBOSyncDirection dir, + size_t size, size_t offset); + int xclExportBO(unsigned int boHandle); + unsigned int xclImportBO(int fd, unsigned flags); + int xclGetBOProperties(unsigned int boHandle, xclBOProperties *properties); + ssize_t xclUnmgdPread(unsigned flags, void *buf, + size_t count, uint64_t offset); + ssize_t xclUnmgdPwrite(unsigned flags, const void *buf, + size_t count, uint64_t offset); + // Bitstreams + int xclGetXclBinIdFromSysfs(uint64_t &xclbinid); int xclLoadXclBin(const xclBin *buffer); + int xclLoadAxlf(const axlf *buffer); int xclUpgradeFirmware(const char *fileName); int xclUpgradeFirmware2(const char *file1, const char* file2); - int xclUpgradeFirmwareXSpi(const char *fileName, int device_index=0); + //int xclUpgradeFirmwareXSpi(const char *fileName, int device_index=0); Not supported by AWS int xclTestXSpi(int device_index); int xclBootFPGA(); + int xclRemoveAndScanFPGA(); int resetDevice(xclResetKind kind); int xclReClock2(unsigned short region, const unsigned short *targetFreqMHz); @@ -114,18 +217,19 @@ namespace awsbwhal { double xclGetDeviceClockFreqMHz(); double xclGetReadMaxBandwidthMBps(); double xclGetWriteMaxBandwidthMBps(); - void xclSetOclRegionProfilingNumberSlots(uint32_t numSlots); + //void xclSetOclRegionProfilingNumberSlots(uint32_t numSlots); + void xclSetProfilingNumberSlots(xclPerfMonType type, uint32_t numSlots); size_t xclPerfMonClockTraining(xclPerfMonType type); // Counters size_t xclPerfMonStartCounters(xclPerfMonType type); size_t xclPerfMonStopCounters(xclPerfMonType type); size_t xclPerfMonReadCounters(xclPerfMonType type, xclCounterResults& counterResults); - //debug related - uint64_t getProtocolCheckerBaseAddress(int type); uint32_t getCheckerNumberSlots(int type); + uint32_t getIPCountAddrNames(int type, uint64_t *baseAddress, std::string * portNames); size_t xclDebugReadCounters(xclDebugCountersResults* debugResult); size_t xclDebugReadCheckers(xclDebugCheckersResults* checkerResult); + void readDebugIpLayout(); // Trace size_t xclPerfMonStartTrace(xclPerfMonType type, uint32_t startTrigger); @@ -142,18 +246,18 @@ namespace awsbwhal { return mTag; } bool isGood() const; - bool is4DDR() {return m4DDR;}; ~AwsXcl(); AwsXcl(unsigned index, const char *logfileName, xclVerbosityLevel verbosity); private: - int xclLoadAxlf(const axlf *buffer); + size_t xclReadModifyWrite(uint64_t offset, const void *hostBuf, size_t size); + size_t xclReadSkipCopy(uint64_t offset, void *hostBuf, size_t size); bool zeroOutDDR(); bool isXPR() const { - return true; + return ((mDeviceInfo.mSubsystemId >> 12) == 4); } bool isMultipleOCLClockSupported() { @@ -165,14 +269,10 @@ namespace awsbwhal { bool isUltraScale() const { return (mDeviceInfo.mDeviceId & 0x8000); } - void initMemoryManager(); // Core DMA code - // Upper two bytes denote PF, lower two bytes denote BAR - // USERPF == 0x0 - // MGTPF == 0x10000 - SHIM_O2 int pcieBarRead(unsigned int pf_bar, unsigned long long offset, void* buffer, unsigned long long length); - SHIM_O2 int pcieBarWrite(unsigned int pf_bar, unsigned long long offset, const void* buffer, unsigned long long length); + SHIM_O2 int pcieBarRead(int bar_num, unsigned long long offset, void* buffer, unsigned long long length); + SHIM_O2 int pcieBarWrite(int bar_num, unsigned long long offset, const void* buffer, unsigned long long length); int freezeAXIGate(); int freeAXIGate(); @@ -193,7 +293,6 @@ namespace awsbwhal { bool bulkErase(); bool sectorErase(unsigned Addr); bool writeEnable(); - int setDDRCount(const axlf* buffer); #if 0 bool dataTransfer(bool read); #endif @@ -214,7 +313,7 @@ namespace awsbwhal { bool isDSAVersion(unsigned majorVersion, unsigned minorVersion, bool onlyThisVersion); unsigned getBankCount(); uint64_t getHostTraceTimeNsec(); - uint64_t getPerfMonBaseAddress(xclPerfMonType type); + uint64_t getPerfMonBaseAddress(xclPerfMonType type, uint32_t slotNum); uint64_t getPerfMonFifoBaseAddress(xclPerfMonType type, uint32_t fifonum); uint64_t getPerfMonFifoReadBaseAddress(xclPerfMonType type, uint32_t fifonum); uint32_t getPerfMonNumberSlots(xclPerfMonType type); @@ -230,37 +329,49 @@ namespace awsbwhal { uint32_t bin2dec(const char * str, int start, int number); std::string dec2bin(uint32_t n); std::string dec2bin(uint32_t n, unsigned bits); - static const std::string getDSAName(unsigned short deviceId, unsigned short subsystemId); + static std::string getDSAName(unsigned short deviceId, unsigned short subsystemId); private: // This is a hidden signature of this class and helps in preventing // user errors when incorrect pointers are passed in as handles. const unsigned mTag; const int mBoardNumber; - const int mDMADeviceNodeNumber; const size_t maxDMASize; bool mLocked; const uint64_t mOffsets[XCL_ADDR_SPACE_MAX]; - DataMover *mDataMover; -#ifdef INTERNAL_TESTING int mUserHandle; +#ifdef INTERNAL_TESTING int mMgtHandle; #else - pci_bar_handle_t ocl_kernel_bar; // AppPF BAR0 for OpenCL kernels - pci_bar_handle_t sda_mgmt_bar;; // MgmtPF BAR4, for SDAccel Perf mon etc - pci_bar_handle_t ocl_global_mem_bar; // AppPF BAR4 + pci_bar_handle_t ocl_kernel_bar; // AppPF BAR0 for OpenCL kernels + pci_bar_handle_t sda_mgmt_bar; // MgmtPF BAR4, for SDAccel Perf mon etc + pci_bar_handle_t ocl_global_mem_bar; // AppPF BAR4 #endif + uint32_t mMemoryProfilingNumberSlots; uint32_t mOclRegionProfilingNumberSlots; + std::string mDevUserName; + + // Information extracted from platform linker + bool mIsDebugIpLayoutRead = false; + bool mIsDeviceProfiling = false; + uint64_t mPerfMonFifoCtrlBaseAddress; + uint64_t mPerfMonFifoReadBaseAddress; + uint64_t mPerfMonBaseAddress[XSPM_MAX_NUMBER_SLOTS]; + std::string mPerfMonSlotName[XSPM_MAX_NUMBER_SLOTS]; char *mUserMap; std::ofstream mLogStream; xclVerbosityLevel mVerbosity; std::string mBinfile; ELARecordList mRecordList; - std::vector mDDRMemoryManager; xclDeviceInfo2 mDeviceInfo; - bool m4DDR; + RangeTable mLegacyAddressTable; +#ifndef INTERNAL_TESTING + int sleepUntilLoaded( std::string afi ); + int checkAndSkipReload( char *afi_id, fpga_mgmt_image_info *info ); + int loadDefaultAfiIfCleared( void ); +#endif public: static const unsigned TAG; }; diff --git a/SDAccel/userspace/src/test b/SDAccel/userspace/src/test deleted file mode 100644 index 3bf09b28..00000000 --- a/SDAccel/userspace/src/test +++ /dev/null @@ -1,1862 +0,0 @@ -diff --git a/sdk/userspace/fpga_image_tools/src/Makefile b/sdk/userspace/fpga_image_tools/src/Makefile -index 522c4a5..ab475a8 100644 ---- a/sdk/userspace/fpga_image_tools/src/Makefile -+++ b/sdk/userspace/fpga_image_tools/src/Makefile -@@ -21,7 +21,7 @@ LIB_PATH = $(TOP)/lib - INCLUDES = -I$(FPGAHALINC_PATH) -I$(TOP)/include -I../. -I. - - #OPT=-O2 --CFLAGS=$(OPT) -g -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) -+CFLAGS=$(OPT) -g -Wall -Werror -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) - - LDFLAGS = -L$(LIB_PATH)/so - LDLIBS = -lfpga_mgmt -diff --git a/sdk/userspace/fpga_image_tools/src/fpga_local_cmd.c b/sdk/userspace/fpga_image_tools/src/fpga_local_cmd.c -index aa3a3b1..7ab30fd 100644 ---- a/sdk/userspace/fpga_image_tools/src/fpga_local_cmd.c -+++ b/sdk/userspace/fpga_image_tools/src/fpga_local_cmd.c -@@ -91,7 +91,7 @@ cli_show_slot_app_pfs(int slot_id, struct fpga_slot_spec *spec) - - return 0; - err: -- return -1; -+ return FPGA_ERR_FAIL; - } - - /** -@@ -120,7 +120,7 @@ cli_attach(void) - out: - return 0; - err: -- return -1; -+ return FPGA_ERR_FAIL; - } - - /** -@@ -236,17 +236,17 @@ static int - command_metrics(void) - { - int ret; -- uint32_t i; -+ uint32_t i, flags; - struct fpga_mgmt_image_info info; -+ struct fpga_slot_spec slot_spec; - - memset(&info, 0, sizeof(struct fpga_mgmt_image_info)); - -- // todo: -- // req->fpga_cmd_flags |= (f1.get_hw_metrics) ? FPGA_CMD_GET_HW_METRICS : 0; -- // req->fpga_cmd_flags |= (f1.clear_hw_metrics) ? -- // FPGA_CMD_CLEAR_HW_METRICS : 0; -+ flags = 0; -+ flags |= (f1.get_hw_metrics) ? FPGA_CMD_GET_HW_METRICS : 0; -+ flags |= (f1.clear_hw_metrics) ? FPGA_CMD_CLEAR_HW_METRICS : 0; - -- ret = fpga_mgmt_describe_local_image(f1.afi_slot, &info); -+ ret = fpga_mgmt_describe_local_image(f1.afi_slot, &info, flags); - fail_on(ret, err, "Unable to describe local image"); - - if (f1.show_headers) { -@@ -261,13 +261,15 @@ command_metrics(void) - - if (f1.rescan) { - /** Rescan the application PFs for this slot */ -- ret = fpga_pci_rescan_slot_app_pfs(f1.afi_slot); // todo: implement this in the library -+ ret = fpga_pci_rescan_slot_app_pfs(); - fail_on_quiet(ret != 0, err, "cli_rescan_slot_app_pfs failed"); - } - - /** Display the application PFs for this slot */ -- // ret = cli_show_slot_app_pfs(f1.afi_slot); // todo -- //fail_on_quiet(ret != 0, err, "cli_show_slot_app_pfs failed"); -+ ret = fpga_pci_get_slot_spec(f1.afi_slot, &slot_spec); -+ fail_on_quiet(ret != 0, err, "fpga_pci_get_slot_spec failed"); -+ ret = cli_show_slot_app_pfs(f1.afi_slot, &slot_spec); -+ fail_on_quiet(ret != 0, err, "cli_show_slot_app_pfs failed"); - - if (f1.get_hw_metrics) { - if (f1.show_headers) { -@@ -375,7 +377,7 @@ command_metrics(void) - - return 0; - err: -- return -1; -+ return FPGA_ERR_FAIL; - } - - /** -@@ -400,7 +402,7 @@ command_describe_slots(void) - - ret = fpga_pci_get_all_slot_specs(spec_array, sizeof_array(spec_array)); - -- for (i = 0; i < sizeof_array(spec_array); ++i) { -+ for (i = 0; i < (int) sizeof_array(spec_array); ++i) { - if (spec_array[i].map[FPGA_APP_PF].vendor_id == 0) - continue; - -@@ -411,7 +413,7 @@ command_describe_slots(void) - } - return 0; - err: -- return -1; -+ return FPGA_ERR_FAIL; - } - - typedef int (*command_func_t)(void); -@@ -443,7 +445,7 @@ cli_main(void) - - return command_table[f1.opcode](); - err: -- return -1; -+ return FPGA_ERR_FAIL; - } - - /** -@@ -525,6 +527,9 @@ main(int argc, char *argv[]) - ret = cli_main(); - fail_on_quiet(ret != 0, err, "cli_main failed"); - err: -+ if (ret) { -+ printf("Error: (%d) %s\n", ret, fpga_mgmt_strerror(ret)); -+ } - cli_detach(); - cli_destroy(); - return ret; -diff --git a/sdk/userspace/fpga_image_tools/src/fpga_local_cmd.h b/sdk/userspace/fpga_image_tools/src/fpga_local_cmd.h -index df222c6..bf2e06d 100644 ---- a/sdk/userspace/fpga_image_tools/src/fpga_local_cmd.h -+++ b/sdk/userspace/fpga_image_tools/src/fpga_local_cmd.h -@@ -44,30 +44,16 @@ enum { - AFI_EXT_END - }; - --/** F1 Mailbox PF defines */ -+/** F1 Mailbox Device defines */ - #define F1_MBOX_VENDOR_ID 0x1d0f - #define F1_MBOX_DEVICE_ID 0x1041 - #define F1_MBOX_RESOURCE_NUM 0 - --/** F1 Application PF defines */ --#define F1_APP_PF_START 0 --#define F1_APP_PF_END 15 -- --/** -- * Generally, we allow a sanitized first level error to be displayed -- * for the user. We do not want low-level mailbox related errors -- * to be displayed (since we are abstracting the mailbox interface). -- * The fail_on_quiet define allows the multi-level trace debug info -- * to still be displayed for development if needed, by re-defining -- * fail_on_quiet as fail_on. -- */ --#define fail_on_quiet fail_on_user --// #define fail_on_quiet(CONDITION, LABEL, ...) \ --// do { \ --// if (CONDITION) { \ --// goto LABEL; \ --// } \ --// } while (0) -+/** F1 Application Device defines */ -+#define F1_MBOX_DEV2APP_DEV(dev) ((dev) - 1) -+#define F1_APP_PF 0 -+#define F1_REMOVE_APP_DEV_DELAY_MSEC 1000 -+#define F1_REMOVE_APP_DEV_MAX_RETRIES 3 - - /** - * This should be used for the sanitized first level errors to be -@@ -115,13 +101,11 @@ enum { - */ - struct ec2_fpga_cmd { - uint32_t slot_dev_index; -- struct fpga_slot_spec mbox_slot_devs[FPGA_SLOT_MAX]; /* todo: do we need this still? */ - uint32_t opcode; - uint32_t afi_slot; - char afi_id[AFI_ID_STR_MAX]; - uint32_t mbox_timeout; - uint32_t mbox_delay_msec; -- bool plat_attached; - bool show_headers; - bool get_hw_metrics; - bool clear_hw_metrics; -@@ -141,54 +125,3 @@ extern struct ec2_fpga_cmd f1; - */ - int - parse_args(int argc, char *argv[]); -- --/** -- * Initialize the AFI slot devices from the PCI/sysfs layer. -- * -- * @returns -- * 0 on success -- * -1 on failure -- */ --int cli_pci_init(void); -- --/** -- * De-initialize the PCI/sysfs layer. -- */ --void cli_pci_free(void); -- --/** -- * Retrieve the application PF map for the given mbox slot. -- * -- * @param[in] slot the fpga slot -- * @param[in] app_pf_num the application PF number to check -- * @param[out] map the application PF resource map to return -- * -- * @returns -- * 0 on success -- * -1 on failure -- */ --int cli_get_app_pf_map(uint32_t slot, uint32_t app_pf_num, -- struct fpga_pci_resource_map *map); -- --/** -- * Remove the application PF for the given mbox slot. -- * -- * @param[in] slot the fpga slot -- * @param[in] app_pf_num the application PF number to check -- * -- * @returns -- * 0 on success -- * -1 on failure -- */ --int --cli_remove_app_pf(uint32_t slot, uint32_t app_pf_num); -- --/** -- * PCI rescan. -- * -- * @returns -- * 0 on success -- * -1 on failure -- */ --int --cli_pci_rescan(void); -diff --git a/sdk/userspace/fpga_image_tools/src/fpga_local_cmd_parse.c b/sdk/userspace/fpga_image_tools/src/fpga_local_cmd_parse.c -index ab4f371..d07630a 100644 ---- a/sdk/userspace/fpga_image_tools/src/fpga_local_cmd_parse.c -+++ b/sdk/userspace/fpga_image_tools/src/fpga_local_cmd_parse.c -@@ -328,7 +328,7 @@ config_request_timeout(uint32_t timeout) - timeout, f1.mbox_timeout, f1.mbox_delay_msec); - return 0; - err: -- return -1; -+ return -EINVAL; - } - - /** -@@ -400,7 +400,7 @@ parse_args_load_afi(int argc, char *argv[]) - err: - print_usage(argv[0], load_afi_usage, sizeof_array(load_afi_usage)); - out_ver: -- return -1; -+ return -EINVAL; - } - - /** -@@ -462,7 +462,7 @@ parse_args_clear_afi(int argc, char *argv[]) - err: - print_usage(argv[0], clear_afi_usage, sizeof_array(clear_afi_usage)); - out_ver: -- return -1; -+ return -EINVAL; - } - - /** -@@ -538,7 +538,7 @@ parse_args_describe_afi(int argc, char *argv[]) - err: - print_usage(argv[0], describe_afi_usage, sizeof_array(describe_afi_usage)); - out_ver: -- return -1; -+ return -EINVAL; - } - - -@@ -596,7 +596,7 @@ err: - print_usage(argv[0], describe_afi_slots_usage, - sizeof_array(describe_afi_slots_usage)); - out_ver: -- return -1; -+ return -EINVAL; - } - - -@@ -669,7 +669,7 @@ parse_args_start_virtual_jtag(int argc, char *argv[]) - err: - print_usage(argv[0], start_virtual_jtag_usage, sizeof_array(start_virtual_jtag_usage)); - out_ver: -- return -1; -+ return -EINVAL; - } - - /** -@@ -724,7 +724,7 @@ parse_args_get_virtual_led(int argc, char *argv[]) - err: - print_usage(argv[0], get_virtual_led_usage, sizeof_array(get_virtual_led_usage)); - out_ver: -- return -1; -+ return -EINVAL; - } - - /** -@@ -780,7 +780,7 @@ parse_args_get_virtual_dip(int argc, char *argv[]) - err: - print_usage(argv[0], get_virtual_dip_usage, sizeof_array(get_virtual_dip_usage)); - out_ver: -- return -1; -+ return -EINVAL; - } - - /** -@@ -863,7 +863,7 @@ parse_args_set_virtual_dip(int argc, char *argv[]) - err: - print_usage(argv[0], set_virtual_dip_usage, sizeof_array(set_virtual_dip_usage)); - out_ver: -- return -1; -+ return -EINVAL; - } - - typedef int (*parse_args_func_t)(int argc, char *argv[]); -@@ -901,7 +901,7 @@ parse_args(int argc, char *argv[]) - - char *opcode_str = argv[1]; - size_t i; -- int ret = -1; -+ int ret = -EINVAL; - for (i = 0; i < sizeof_array(str2func); i++) { - struct parse_args_str2func *entry = &str2func[i]; - -@@ -919,5 +919,5 @@ parse_args(int argc, char *argv[]) - return ret; - err: - print_usage(argv[0], opcode_str_usage, sizeof_array(opcode_str_usage)); -- return -1; -+ return -EINVAL; - } -diff --git a/sdk/userspace/fpga_image_tools/src/virtual_jtag_pcie.c b/sdk/userspace/fpga_image_tools/src/virtual_jtag_pcie.c -index 260ec6c..b6f1689 100644 ---- a/sdk/userspace/fpga_image_tools/src/virtual_jtag_pcie.c -+++ b/sdk/userspace/fpga_image_tools/src/virtual_jtag_pcie.c -@@ -40,7 +40,7 @@ int open_port(uint32_t slot_id, pci_bar_handle_t* jtag_pci_bar) { - - void close_port(pci_bar_handle_t jtag_pci_bar) { - if (jtag_pci_bar >=0) -- fpga_pci_detatch(jtag_pci_bar); -+ fpga_pci_detach(jtag_pci_bar); - - } - -diff --git a/sdk/userspace/fpga_image_tools/src/virtual_jtag_server.c b/sdk/userspace/fpga_image_tools/src/virtual_jtag_server.c -index 4a1d4f6..684a2b8 100644 ---- a/sdk/userspace/fpga_image_tools/src/virtual_jtag_server.c -+++ b/sdk/userspace/fpga_image_tools/src/virtual_jtag_server.c -@@ -67,7 +67,7 @@ static int open_server(const char* tcp_port) { - if (err) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err)); - errno = EINVAL; -- return -1; -+ return FPGA_ERR_FAIL; - } - - for (res = reslist; res != NULL; res = res->ai_next) { -diff --git a/sdk/userspace/fpga_libs/fpga_mgmt/Makefile b/sdk/userspace/fpga_libs/fpga_mgmt/Makefile -index e4c697b..69483c8 100644 ---- a/sdk/userspace/fpga_libs/fpga_mgmt/Makefile -+++ b/sdk/userspace/fpga_libs/fpga_mgmt/Makefile -@@ -22,7 +22,7 @@ LIB_SO_PATH = $(LIB_PATH)/so - INCLUDES = -I$(TOPINC_PATH) -I/usr/include - - #OPT=-O2 --CFLAGS=$(OPT) -g -std=gnu99 -fPIC -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) -+CFLAGS=$(OPT) -g -std=gnu99 -fPIC -Wall -Werror -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) - - SRC = $(wildcard *.c) - OBJ = $(SRC:.c=.o) -diff --git a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c -index e3c128c..e9d51b3 100644 ---- a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c -+++ b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c -@@ -54,7 +54,7 @@ void fpag_mgmt_set_cmd_delay_msec(uint32_t value) - } - - int fpga_mgmt_describe_local_image(int slot_id, -- struct fpga_mgmt_image_info *info) -+ struct fpga_mgmt_image_info *info, uint32_t flags) - { - int ret; - uint32_t len; -@@ -71,9 +71,7 @@ int fpga_mgmt_describe_local_image(int slot_id, - memset(&rsp, 0, sizeof(union afi_cmd)); - - /* initialize the command structure */ -- fpga_mgmt_cmd_init_metrics(&cmd, &len, -- /*bool get_hw_metrics*/ false, -- /*bool clear_hw_metrics*/ false); -+ fpga_mgmt_cmd_init_metrics(&cmd, &len, flags); - - /* send the command and wait for the response */ - ret = fpga_mgmt_process_cmd(slot_id, &cmd, &rsp, &len); -@@ -107,14 +105,6 @@ out: - return ret; - } - --/** -- * Gets the status of an FPGA. Status values are definted in enum fpga_status. -- * If you need the AFI id at the same time, use fpga_mgmt_describe_local_image. -- * -- * @param[in] slot_id the logical slot index -- * @param[out] status populated with status value -- * @returns 0 on success, non-zero on error -- */ - int fpga_mgmt_get_status(int slot_id, int *status) - { - int ret; -@@ -128,7 +118,7 @@ int fpga_mgmt_get_status(int slot_id, int *status) - - memset(&info, 0, sizeof(struct fpga_mgmt_image_info)); - -- ret = fpga_mgmt_describe_local_image(slot_id, &info); -+ ret = fpga_mgmt_describe_local_image(slot_id, &info, 0); - fail_on(ret, out, "fpga_mgmt_describe_local_image failed"); - - *status = info.status; -@@ -136,10 +126,18 @@ out: - return ret; - } - --const char *fpga_mgmt_get_status_name(int status) { -+const char *fpga_mgmt_get_status_name(int status) -+{ - return FPGA_STATUS2STR(status); - } - -+const char *fpga_mgmt_strerror(int err) { -+ if (err < 0) { -+ return strerror(-err); -+ } -+ return FPGA_ERR2STR(err); -+} -+ - int fpga_mgmt_clear_local_image(int slot_id) { - int ret; - uint32_t len; -@@ -193,14 +191,14 @@ int fpga_mgmt_get_vLED_status(int slot_id, uint16_t *status) { - - ret=fpga_pci_attach(slot_id, FPGA_MGMT_PF, MGMT_PF_BAR0, 0, &led_pci_bar); - if (ret) -- return -1; -+ return FPGA_ERR_FAIL; - - ret = fpga_pci_peek(led_pci_bar,F1_VIRTUAL_LED_REG_OFFSET,&read_data); - /* All this code assumes little endian, it would need rework for supporting non x86/arm platforms */ - *(status) = (uint16_t)( read_data & 0x0000FFFF); - - -- fpga_pci_detatch(led_pci_bar); -+ fpga_pci_detach(led_pci_bar); - return ret; - } - -@@ -211,7 +209,7 @@ int fpga_mgmt_set_vDIP(int slot_id, uint16_t value) { - - ret=fpga_pci_attach(slot_id, FPGA_MGMT_PF, MGMT_PF_BAR0, 0, &dip_pci_bar); - if (ret) -- return -1; -+ return FPGA_ERR_FAIL; - - - write_data = (uint32_t) value; -@@ -219,7 +217,7 @@ int fpga_mgmt_set_vDIP(int slot_id, uint16_t value) { - ret = fpga_pci_poke(dip_pci_bar,F1_VIRTUAL_DIP_REG_OFFSET,write_data); - - -- fpga_pci_detatch(dip_pci_bar); -+ fpga_pci_detach(dip_pci_bar); - return ret; - } - -@@ -231,13 +229,13 @@ int fpga_mgmt_get_vDIP_status(int slot_id, uint16_t *value) { - - ret=fpga_pci_attach(slot_id, FPGA_MGMT_PF, MGMT_PF_BAR0, 0, &dip_pci_bar); - if (ret) -- return -1; -+ return FPGA_ERR_FAIL; - - ret = fpga_pci_peek(dip_pci_bar,F1_VIRTUAL_DIP_REG_OFFSET,&read_data); - /* All this code assumes little endian, it would need rework for supporting non x86/arm platforms */ - *(value) = (uint16_t)read_data; - -- fpga_pci_detatch(dip_pci_bar); -+ fpga_pci_detach(dip_pci_bar); - return ret; - - } -diff --git a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c -index 78bd0d6..ecbb8cc 100644 ---- a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c -+++ b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c -@@ -25,14 +25,10 @@ - #include - #include - #include -+#include - - #include "fpga_mgmt_internal.h" - --#include // todo: get rid of this? --#define fail_on_quiet fail_on --#define fail_on_internal fail_on --#define fail_on_user fail_on -- - /** - * AFI command get payload length utility. - * -@@ -76,7 +72,7 @@ afi_cmd_hdr_set_len(union afi_cmd *cmd, size_t len) - { - /* Null pointer or overflow? */ - if (!cmd || (len & ~AFI_CMD_HDR_LEN_MASK)) { -- return -1; -+ return FPGA_ERR_FAIL; - } - - cmd->hdr.len_flags &= ~AFI_CMD_HDR_LEN_MASK; -@@ -99,7 +95,7 @@ afi_cmd_hdr_set_flags(union afi_cmd *cmd, unsigned int flags) - { - /* Null pointer or overflow? */ - if (!cmd || (flags & ~AFI_CMD_HDR_ALL_FLAGS)) { -- return -1; -+ return FPGA_ERR_FAIL; - } - - cmd->hdr.len_flags &= AFI_CMD_HDR_LEN_MASK; -@@ -164,8 +160,7 @@ fpga_mgmt_cmd_init_load(union afi_cmd *cmd, uint32_t *len, const char *afi_id) - * @param[in,out] len cmd len - */ - void --fpga_mgmt_cmd_init_metrics(union afi_cmd *cmd, uint32_t *len, -- bool get_hw_metrics, bool clear_hw_metrics) -+fpga_mgmt_cmd_init_metrics(union afi_cmd *cmd, uint32_t *len, uint32_t flags) - { - assert(cmd); - assert(len); -@@ -180,10 +175,9 @@ fpga_mgmt_cmd_init_metrics(union afi_cmd *cmd, uint32_t *len, - afi_cmd_hdr_set_len(cmd, payload_len); - afi_cmd_hdr_set_flags(cmd, 0); - -- /** Fill in cmd body */ -- req->fpga_cmd_flags = 0; -- req->fpga_cmd_flags |= (get_hw_metrics) ? FPGA_CMD_GET_HW_METRICS : 0; -- req->fpga_cmd_flags |= (clear_hw_metrics) ? FPGA_CMD_CLEAR_HW_METRICS : 0; -+ /** Fill in cmd body; only allow specific flags to be set */ -+ req->fpga_cmd_flags = flags & -+ (FPGA_CMD_GET_HW_METRICS | FPGA_CMD_CLEAR_HW_METRICS); - - *len = sizeof(struct afi_cmd_hdr) + payload_len; - } -@@ -243,7 +237,7 @@ fpga_mgmt_cmd_handle_metrics(const union afi_cmd *rsp, uint32_t len, - - return 0; - err: -- return -1; -+ return FPGA_ERR_FAIL; - } - - -@@ -270,14 +264,14 @@ fpga_mgmt_mbox_attach(int slot_id) - }; - - ret = fpga_hal_mbox_init(&mbox); -- fail_on_internal(ret != 0, err, CLI_INTERNAL_ERR_STR); -+ fail_on(ret != 0, err, CLI_INTERNAL_ERR_STR); - - ret = fpga_hal_mbox_attach(true); /**< clear_state=true */ -- fail_on_internal(ret != 0, err, CLI_INTERNAL_ERR_STR); -+ fail_on(ret != 0, err, CLI_INTERNAL_ERR_STR); - - return 0; - err: -- return -1; -+ return FPGA_ERR_FAIL; - } - - static int -@@ -290,7 +284,7 @@ fpga_mgmt_mbox_detach(int slot_id) - /** Continue with plat detach */ - } - -- ret = fpga_pci_detatch(fpga_mgmt_state.slots[slot_id].handle); -+ ret = fpga_pci_detach(fpga_mgmt_state.slots[slot_id].handle); - if (ret != 0) { - log_error("%s (line %u)", CLI_INTERNAL_ERR_STR, __LINE__); - /* Continue with detach */ -@@ -311,18 +305,54 @@ int fpga_mgmt_detach_all(void) - } - - /** -+ * Handle AFI error response -+ * -+ * @param[in] rsp the response that was received. -+ * @param[in] len the expected response payload len. -+ * -+ * @returns -+ * zero on success, non-zero on failure -+ */ -+static int -+fpga_mgmt_handle_afi_cmd_error_rsp(const union afi_cmd *rsp, uint32_t len) -+{ -+ struct afi_cmd_err_rsp *err_rsp = (void *)rsp->body; -+ -+ uint32_t tmp_len = -+ sizeof(struct afi_cmd_hdr) + sizeof(struct afi_cmd_err_rsp); -+ -+ fail_on_quiet(len < tmp_len, err, "total_rsp_len(%u) < calculated_len(%u)", -+ len, tmp_len); -+ -+ /** Handle invalid API version error */ -+ if (err_rsp->error == FPGA_ERR_AFI_CMD_API_VERSION_INVALID) { -+ union afi_err_info *err_info = (void *)err_rsp->error_info; -+ -+ tmp_len += sizeof(err_info->afi_cmd_version); -+ fail_on_quiet(len < tmp_len, err, "total_rsp_len(%u) < calculated_len(%u)", -+ len, tmp_len); -+ -+ log_error("Error: Please upgrade from aws-fpga github to AFI CMD API Version: v%u\n", -+ err_info->afi_cmd_version); -+ } -+ -+ return err_rsp->error; -+err: -+ return FPGA_ERR_FAIL; -+} -+ -+/** - * Validate the AFI response header, using the command header. - * -- * @param[in] cmd the command that was sent. -- * @param[in] rsp the response that was received. -- * @param[in] len the expected response payload len. -+ * @param[in] cmd the command that was sent. -+ * @param[in] rsp the response that was received. -+ * @param[in] len the expected response payload len. - * - * @returns -- * 0 on success -- * -1 on failure -+ * zero on success, non-zero on failure - */ --static int --fpga_mgmt_afi_validate_header(const union afi_cmd *cmd, -+static int -+fpga_mgmt_afi_validate_header(const union afi_cmd *cmd, - const union afi_cmd *rsp, uint32_t len) - { - uint32_t stored_flags = afi_cmd_hdr_get_flags(rsp); -@@ -333,8 +363,8 @@ fpga_mgmt_afi_validate_header(const union afi_cmd *cmd, - fail_on_quiet(!rsp, err, "rsp == NULL"); - - /** Version */ -- fail_on_quiet(cmd->hdr.version != rsp->hdr.version, err, -- "cmd_ver(%u) != rsp_ver(%u)", -+ fail_on_quiet(cmd->hdr.version != rsp->hdr.version, err, -+ "cmd_ver(%u) != rsp_ver(%u)", - cmd->hdr.version, rsp->hdr.version); - - /** Opcode */ -@@ -346,11 +376,11 @@ fpga_mgmt_afi_validate_header(const union afi_cmd *cmd, - cmd->hdr.id, rsp->hdr.id); - - /** Received len too small */ -- fail_on_quiet(len < sizeof(struct afi_cmd_hdr), err, -+ fail_on_quiet(len < sizeof(struct afi_cmd_hdr), err, - "Received length %u too small", len); - - /** Payload len too big */ -- fail_on_quiet(payload_len + sizeof(struct afi_cmd_hdr) > AFI_CMD_DATA_LEN, -+ fail_on_quiet(payload_len + sizeof(struct afi_cmd_hdr) > AFI_CMD_DATA_LEN, - err, "Payload length %u too big", payload_len); - - /** Not a response */ -@@ -361,10 +391,10 @@ id_err: - return -EAGAIN; - op_err: - if (rsp->hdr.op == AFI_CMD_ERROR) { -- //return (cmd, rsp, len); // TODO -+ return fpga_mgmt_handle_afi_cmd_error_rsp(rsp, len); - } - err: -- return -1; -+ return FPGA_ERR_FAIL; - } - - static int -@@ -375,30 +405,33 @@ fpga_mgmt_send_cmd( - - /** Write the AFI cmd to the mailbox */ - ret = fpga_hal_mbox_write((void *)cmd, *len); -- fail_on_internal(ret != 0, err, CLI_INTERNAL_ERR_STR); -+ fail_on(ret != 0, err, CLI_INTERNAL_ERR_STR); - -- /** -+ /** - * Read the AFI rsp from the mailbox. -- * -also make a minimal attempt to drain stale responses -+ * -also make a minimal attempt to drain stale responses - * (if any). - */ - uint32_t id_retries = 0; - ret = -EAGAIN; - while (ret == -EAGAIN) { - ret = fpga_hal_mbox_read((void *)rsp, len); -- fail_on_user(ret != 0, err, "Error: operation timed out"); -+ fail_on(ret = (ret) ? ETIMEDOUT : 0, err_code, "Error: operation timed out"); - - ret = fpga_mgmt_afi_validate_header(cmd, rsp, *len); -+ fail_on(ret, err_code, CLI_INTERNAL_ERR_STR); - -- fail_on_internal(id_retries >= AFI_MAX_ID_RETRIES, err, -+ fail_on(id_retries >= AFI_MAX_ID_RETRIES, err, - CLI_INTERNAL_ERR_STR); - id_retries++; - } -- fail_on_internal(ret != 0, err, CLI_INTERNAL_ERR_STR); -- -+ fail_on(ret != 0, err, CLI_INTERNAL_ERR_STR); -+ - return 0; - err: -- return -1; -+ return FPGA_ERR_FAIL; -+err_code: -+ return ret; - } - - int -diff --git a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_internal.h b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_internal.h -index c06f6cd..bb6ddb1 100644 ---- a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_internal.h -+++ b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_internal.h -@@ -52,7 +52,7 @@ extern struct fgpa_mgmt_state_s { - int fpga_mgmt_process_cmd(int slot_id, - const union afi_cmd *cmd, union afi_cmd *rsp, uint32_t *len); - void fpga_mgmt_cmd_init_metrics(union afi_cmd *cmd, uint32_t *len, -- bool get_hw_metrics, bool clear_hw_metrics); -+ uint32_t flags); - void fpga_mgmt_cmd_init_load(union afi_cmd *cmd, uint32_t *len, - const char *afi_id); - void fpga_mgmt_cmd_init_clear(union afi_cmd *cmd, uint32_t *len); -diff --git a/sdk/userspace/fpga_libs/fpga_pci/Makefile b/sdk/userspace/fpga_libs/fpga_pci/Makefile -index 2a90df5..7e81c26 100644 ---- a/sdk/userspace/fpga_libs/fpga_pci/Makefile -+++ b/sdk/userspace/fpga_libs/fpga_pci/Makefile -@@ -21,7 +21,7 @@ LIB_PATH = $(TOP)/lib - INCLUDES = -I$(TOPINC_PATH) -I/usr/include - - #OPT=-O2 --CFLAGS=$(OPT) -g -std=gnu99 -fPIC -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) -+CFLAGS=$(OPT) -g -std=gnu99 -fPIC -Wall -Werror -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) - - SRC = $(wildcard *.c) - OBJ = $(SRC:.c=.o) -diff --git a/sdk/userspace/fpga_libs/fpga_pci/fpga_pci.c b/sdk/userspace/fpga_libs/fpga_pci/fpga_pci.c -index 0289f97..fd03c35 100644 ---- a/sdk/userspace/fpga_libs/fpga_pci/fpga_pci.c -+++ b/sdk/userspace/fpga_libs/fpga_pci/fpga_pci.c -@@ -13,7 +13,7 @@ - * permissions and limitations under the License. - */ - --#include "fpga_pci_interal.h" -+#include "fpga_pci_internal.h" - - #include - -@@ -23,11 +23,17 @@ fpga_pci_init() { - } - - int --fpga_pci_attach(int slot_id, int pf_id, int bar_id, uint32_t flags, pci_bar_handle_t *handle) { -+fpga_pci_attach(int slot_id, int pf_id, int bar_id, uint32_t flags, -+ pci_bar_handle_t *handle) -+{ - int rc; -+ bool write_combining; - struct fpga_slot_spec spec; -+ -+ (void) flags; - -- if (!handle || pf_id < 0 || pf_id >= FPGA_MAX_PF) { -+ if (!handle || pf_id < 0 || pf_id >= FPGA_MAX_PF || -+ bar_id < 0 || bar_id >= FPGA_BAR_PER_PF_MAX) { - return -EINVAL; - } - -@@ -36,13 +42,21 @@ fpga_pci_attach(int slot_id, int pf_id, int bar_id, uint32_t flags, pci_bar_hand - rc = fpga_pci_get_slot_spec(slot_id, &spec); - fail_on(rc, out, "Unable to prefill the slot spec\n"); - -- return fpga_plat_dev_attach(&spec, pf_id, bar_id, handle); -+ write_combining = false; -+ if (flags & BURST_CAPABLE) { -+ rc = (spec.map[pf_id].resource_burstable[bar_id]) ? 0 : FPGA_ERR_FAIL; -+ fail_on(rc, out, "bar is not BURST_CAPABLE (does not support write " -+ "combining.)"); -+ write_combining = true; -+ } -+ -+ return fpga_plat_dev_attach(&spec, pf_id, bar_id, write_combining, handle); - out: -- return 1; -+ return rc; - } - - int --fpga_pci_detatch(pci_bar_handle_t handle) { -+fpga_pci_detach(pci_bar_handle_t handle) { - return fpga_plat_dev_detach(handle); - } - -@@ -53,11 +67,7 @@ fpga_pci_poke(pci_bar_handle_t handle, uint64_t offset, uint32_t value) { - - int - fpga_pci_poke64(pci_bar_handle_t handle, uint64_t offset, uint64_t value) { -- (void) handle; -- (void) offset; -- (void) value; -- /* not implemened */ -- return 1; -+ return fpga_hal_dev_reg_write64(handle, offset, value); - } - - int -@@ -67,18 +77,10 @@ fpga_pci_peek(pci_bar_handle_t handle, uint64_t offset, uint32_t *value) { - - int - fpga_pci_peek64(pci_bar_handle_t handle, uint64_t offset, uint64_t *value) { -- (void) handle; -- (void) offset; -- (void) value; -- /* not implemented */ -- return 1; -+ return fpga_hal_dev_reg_read64(handle, offset, value); - } - - int fpga_pci_write_burst(pci_bar_handle_t handle, uint64_t offset, uint32_t* datap, uint32_t dword_len) { -- (void) handle; -- (void) offset; -- (void) datap; -- (void) dword_len; -- /* not implemented */ -- return 1; -+ int ret = fpga_plat_dev_reg_write_burst(handle, offset, datap, dword_len); -+ return ret ? FPGA_ERR_FAIL : 0; - } -diff --git a/sdk/userspace/fpga_libs/fpga_pci/fpga_pci_sysfs.c b/sdk/userspace/fpga_libs/fpga_pci/fpga_pci_sysfs.c -index 4233896..b0abfa6 100644 ---- a/sdk/userspace/fpga_libs/fpga_pci/fpga_pci_sysfs.c -+++ b/sdk/userspace/fpga_libs/fpga_pci/fpga_pci_sysfs.c -@@ -13,7 +13,7 @@ - * permissions and limitations under the License. - */ - --#include "fpga_pci_interal.h" -+#include "fpga_pci_internal.h" - - #include - #include -@@ -31,18 +31,18 @@ - /** - * Return the ID from the given sysfs file (e.g. Vendor ID, Device ID). - * -- * @param[in] path the sysfs file path -+ * @param[in] path the sysfs file path - * @param[in,out] id the returned id - * - * @returns -- * 0 on success -+ * 0 on success - * -1 on failure - */ - static int - fpga_pci_get_id(char *path, uint16_t *id) - { -- fail_on_internal(!path, err, CLI_INTERNAL_ERR_STR); -- fail_on_internal(!id, err, CLI_INTERNAL_ERR_STR); -+ fail_on(!path, err, CLI_INTERNAL_ERR_STR); -+ fail_on(!id, err, CLI_INTERNAL_ERR_STR); - - int ret = 0; - FILE *fp = fopen(path, "r"); -@@ -61,32 +61,59 @@ err_close: - fclose(fp); - err: - errno = 0; -- return -1; -+ return FPGA_ERR_FAIL; - } - - /** -- * Fill in the DBDF within the PCI resource map using the given PCI device -+ * Write a '1' to the given sysfs file. -+ * -+ * @param[in] path the sysfs file path -+ * -+ * @returns -+ * 0 on success -+ * -1 on failure -+ */ -+static int -+fpga_pci_write_one2file(char *path) -+{ -+ int ret = -1; -+ -+ int fd = open(path, O_WRONLY); -+ fail_on_quiet(fd == -1, err, "opening %s", path); -+ -+ char buf[] = { '1', 0 }; -+ ret = -!!write_loop(fd, buf, sizeof(buf)); -+ fail_on_quiet(ret != 0, err_close, "error writing %s", path); -+ -+err_close: -+ close(fd); -+err: -+ return ret; -+} -+ -+/** -+ * Fill in the DBDF within the PCI resource map using the given PCI device - * directory name. - * -- * @param[in] dir_name the PCI device directory name -- * @param[in,out] map the PCI resource map to fill in -+ * @param[in] dir_name the PCI device directory name -+ * @param[in,out] map the PCI resource map to fill in - * - * @returns -- * 0 on success -+ * 0 on success - * -1 on failure - */ - static int - fpga_pci_get_dbdf(char *dir_name, struct fpga_pci_resource_map *map) - { -- fail_on_internal(!dir_name, err, CLI_INTERNAL_ERR_STR); -- fail_on_internal(!map, err, CLI_INTERNAL_ERR_STR); -+ fail_on(!dir_name, err, CLI_INTERNAL_ERR_STR); -+ fail_on(!map, err, CLI_INTERNAL_ERR_STR); - - uint32_t domain; - uint32_t bus; - uint32_t dev; - int func; - int ret = sscanf(dir_name, PCI_DEV_FMT, &domain, &bus, &dev, &func); -- fail_on_internal(ret != 4, err, CLI_INTERNAL_ERR_STR); -+ fail_on(ret != 4, err, CLI_INTERNAL_ERR_STR); - - map->domain = domain; - map->bus = bus; -@@ -94,19 +121,19 @@ fpga_pci_get_dbdf(char *dir_name, struct fpga_pci_resource_map *map) - map->func = func; - return 0; - err: -- return -1; -+ return FPGA_ERR_FAIL; - } - - /** -- * Return the PCI resource size using the PCI directory name and resource -+ * Return the PCI resource size using the PCI directory name and resource - * number. - * -- * @param[in] dir_name the PCI device directory name -- * @param[in] resource_num the resource number -+ * @param[in] dir_name the PCI device directory name -+ * @param[in] resource_num the resource number - * @param[in,out] resource_size the returned resource size - * - * @returns -- * 0 on success -+ * 0 on success - * -1 on failure - */ - static int -@@ -115,17 +142,17 @@ fpga_pci_get_pci_resource_info(char *dir_name, - { - int ret; - -- fail_on_internal(!dir_name, err, CLI_INTERNAL_ERR_STR); -- fail_on_internal(!resource_size, err, CLI_INTERNAL_ERR_STR); -+ fail_on(!dir_name, err, CLI_INTERNAL_ERR_STR); -+ fail_on(!resource_size, err, CLI_INTERNAL_ERR_STR); - - char sysfs_name[NAME_MAX + 1]; -- ret = snprintf(sysfs_name, sizeof(sysfs_name), -- "/sys/bus/pci/devices/%s/resource%u", dir_name, -+ ret = snprintf(sysfs_name, sizeof(sysfs_name), -+ "/sys/bus/pci/devices/%s/resource%u", dir_name, - resource_num); - - fail_on_quiet(ret < 0, err, "Error building the sysfs path for resource%u", - resource_num); -- fail_on_quiet((size_t) ret >= sizeof(sysfs_name), err, -+ fail_on_quiet((size_t) ret >= sizeof(sysfs_name), err, - "sysfs path too long for resource%u", resource_num); - - /** Check for file existence, obtain the file size */ -@@ -135,13 +162,13 @@ fpga_pci_get_pci_resource_info(char *dir_name, - - *resource_size = file_stat.st_size; - -- ret = snprintf(sysfs_name, sizeof(sysfs_name), -- "/sys/bus/pci/devices/%s/resource%u_wc", dir_name, -+ ret = snprintf(sysfs_name, sizeof(sysfs_name), -+ "/sys/bus/pci/devices/%s/resource%u_wc", dir_name, - resource_num); - - fail_on_quiet(ret < 0, err, "Error building the sysfs path for resource%u", - resource_num); -- fail_on_quiet((size_t) ret >= sizeof(sysfs_name), err, -+ fail_on_quiet((size_t) ret >= sizeof(sysfs_name), err, - "sysfs path too long for resource%u", resource_num); - - memset(&file_stat, 0, sizeof(struct stat)); -@@ -150,7 +177,7 @@ fpga_pci_get_pci_resource_info(char *dir_name, - - return 0; - err: -- return -1; -+ return FPGA_ERR_FAIL; - } - - static int -@@ -176,20 +203,18 @@ fpga_pci_handle_resources(char *dir_name, struct fpga_pci_resource_map *map) - map->resource_burstable[resource_num] = burstable; - } - return 0; --err: -- return -1; - } - - - /** -- * Handle one PCI device directory with the given directory name, and see if -- * it is an AFI mbox slot. If so, initialize a slot device structure for it -+ * Handle one PCI device directory with the given directory name, and see if -+ * it is an AFI mbox slot. If so, initialize a slot device structure for it - * and its associated slot device (if any). - * -- * @param[in] dir_name the PCI device directory name -+ * @param[in] dir_name the PCI device directory name - * - * @returns -- * 0 on success -+ * 0 on success - * -1 on failure - */ - static int -@@ -199,12 +224,10 @@ fpga_pci_handle_pci_dir_name(char *dir_name, struct fpga_pci_resource_map *map) - uint16_t device_id = 0; - - fail_on_quiet(!dir_name, err, CLI_INTERNAL_ERR_STR); -- // fail_on_quiet(f1.slot_dev_index >= FPGA_SLOT_MAX, err, -- // CLI_INTERNAL_ERR_STR); - - /** Setup and read the PCI Vendor ID */ - char sysfs_name[NAME_MAX + 1]; -- int ret = snprintf(sysfs_name, sizeof(sysfs_name), -+ int ret = snprintf(sysfs_name, sizeof(sysfs_name), - "/sys/bus/pci/devices/%s/vendor", dir_name); - - fail_on_quiet(ret < 0, err, "Error building the sysfs path for vendor"); -@@ -214,7 +237,7 @@ fpga_pci_handle_pci_dir_name(char *dir_name, struct fpga_pci_resource_map *map) - fail_on_quiet(ret != 0, err, "Error retrieving vendor_id"); - - /** Setup and read the PCI Device ID */ -- ret = snprintf(sysfs_name, sizeof(sysfs_name), -+ ret = snprintf(sysfs_name, sizeof(sysfs_name), - "/sys/bus/pci/devices/%s/device", dir_name); - - fail_on_quiet(ret < 0, err, "Error building the sysfs path for device"); -@@ -223,27 +246,17 @@ fpga_pci_handle_pci_dir_name(char *dir_name, struct fpga_pci_resource_map *map) - ret = fpga_pci_get_id(sysfs_name, &device_id); - fail_on_quiet(ret != 0, err, "Error retrieving device_id"); - -- // /** Check for a match to the FPGA Mbox Vendor ID and Device ID */ -- // if ((vendor_id != F1_MBOX_VENDOR_ID) || (device_id != F1_MBOX_DEVICE_ID)) { -- // /* the device did not match */ -- // return 1; -- // } -- - /** Fill in the DBDF */ - ret = fpga_pci_get_dbdf(dir_name, map); - fail_on_quiet(ret != 0, err, "Error retrieving DBDF from dir_name=%s", - dir_name); - -- /** Retrieve the PCI resource size for plat attach */ -- ret = fpga_pci_handle_resources(dir_name, map); -- fail_on_quiet(ret != 0, err, "Error retrieving resource information"); -- - map->vendor_id = vendor_id; - map->device_id = device_id; - - return 0; - err: -- return -1; -+ return FPGA_ERR_FAIL; - } - - int -@@ -252,59 +265,70 @@ fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) - bool found_afi_slot = false; - char *path = "/sys/bus/pci/devices"; - DIR *dirp = opendir(path); -- fail_on_internal(!dirp, err, CLI_INTERNAL_ERR_STR); -+ fail_on(!dirp, err, CLI_INTERNAL_ERR_STR); -+ -+ struct dirent entry_a, entry_b, *entry, *previous_entry, *result; - int slot_dev_index = 0; - struct fpga_slot_spec search_spec; -- struct fpga_pci_resource_map search_map, previous_map; -+ struct fpga_pci_resource_map a, b, *search_map, *previous_map; - - memset(&search_spec, 0, sizeof(struct fpga_slot_spec)); -- memset(&previous_map, 0, sizeof(struct fpga_pci_resource_map)); -+ memset(&a, 0, sizeof(struct fpga_pci_resource_map)); -+ memset(&b, 0, sizeof(struct fpga_pci_resource_map)); -+ search_map = &a; -+ previous_map = &b; - -- /** Loop through the sysfs device directories */ -- for (;;) { -- struct dirent entry; -- struct dirent *result; -- memset(&entry, 0, sizeof(entry)); -+ entry = &entry_a; -+ previous_entry = &entry_b; - -- readdir_r(dirp, &entry, &result); -+ /** Loop through the sysfs device directories */ -+ while (true) { -+ memset(entry, 0, sizeof(entry)); -+ readdir_r(dirp, entry, &result); - if (result == NULL) { - /** No more directories */ - break; - } - - /** Handle the current directory entry */ -- memset(&search_map, 0, sizeof(struct fpga_pci_resource_map)); -- int ret = fpga_pci_handle_pci_dir_name(entry.d_name, &search_map); -+ memset(search_map, 0, sizeof(struct fpga_pci_resource_map)); -+ int ret = fpga_pci_handle_pci_dir_name(entry->d_name, search_map); - if (ret != 0) { -+ previous_map->device_id = 0; - continue; - } -- found_afi_slot = true; -- if (search_map.domain != previous_map.domain || -- search_map.bus != previous_map.bus || -- search_map.dev != previous_map.dev) { -- -- -- /* domain, bus, device do not match: this is the next slot */ -- if (search_spec.map[FPGA_MGMT_PF].vendor_id == F1_MBOX_VENDOR_ID && -- search_spec.map[FPGA_MGMT_PF].device_id == F1_MBOX_DEVICE_ID) { - -- spec_array[slot_dev_index] = search_spec; -- ++slot_dev_index; -- if (slot_dev_index >= size) { -- break; -- } -+ if (search_map->vendor_id == F1_MBOX_VENDOR_ID && -+ search_map->device_id == F1_MBOX_DEVICE_ID && -+ previous_map->device_id != 0) { -+ -+ /* Retrieve the PCI resource size for plat attach after confirming -+ * these devices are FPGAs. */ -+ /* mbox resources */ -+ ret = fpga_pci_handle_resources(entry->d_name, search_map); -+ fail_on_quiet(ret != 0, err, "Error retrieving resource information"); -+ /* app resources */ -+ ret = fpga_pci_handle_resources(previous_entry->d_name, previous_map); -+ fail_on_quiet(ret != 0, err, "Error retrieving resource information"); -+ -+ /* copy the results into the spec_array */ -+ spec_array[slot_dev_index].map[FPGA_APP_PF] = *previous_map; -+ spec_array[slot_dev_index].map[FPGA_MGMT_PF] = *search_map; -+ -+ found_afi_slot = true; -+ slot_dev_index += 1; -+ if (slot_dev_index >= size) { -+ break; - } -- } -- if (search_map.func >= FPGA_MAX_PF) { -- /* unexpected pf */ -+ -+ /* invalidate the previous_map and do not swap */ -+ previous_map->device_id = 0; - continue; - } -- /* copy the map into the spec array */ -- search_spec.map[search_map.func] = search_map; -- previous_map = search_map; -+ -+ swap(previous_map, search_map); -+ swap(previous_entry, entry); - } -- /* TODO: this has a bug in it: if there are no PCI devices after the last -- * FPGA, it will fail to find that FPGA. */ - - closedir(dirp); - -@@ -312,13 +336,14 @@ fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) - - return 0; - err: -- return -1; -+ return FPGA_ERR_FAIL; - } - - int - fpga_pci_get_slot_spec(int slot_id, struct fpga_slot_spec *spec) - { - int ret; -+ unsigned int size; - struct fpga_slot_spec spec_array[FPGA_SLOT_MAX]; - - if (slot_id < 0 || slot_id >= FPGA_SLOT_MAX || !spec) { -@@ -327,7 +352,9 @@ fpga_pci_get_slot_spec(int slot_id, struct fpga_slot_spec *spec) - - memset(spec_array, 0, sizeof(spec_array)); - -- ret = fpga_pci_get_all_slot_specs(spec_array, sizeof_array(spec_array)); -+ /* tell fpga_pci_get_all_slot_specs not to search past the slot number */ -+ size = min(sizeof_array(spec_array), (unsigned) slot_id); -+ ret = fpga_pci_get_all_slot_specs(spec_array, size); - fail_on_quiet(ret, err, "Unable to read PCI device information."); - - if (spec_array[slot_id].map[FPGA_APP_PF].vendor_id == 0) { -@@ -338,21 +365,49 @@ fpga_pci_get_slot_spec(int slot_id, struct fpga_slot_spec *spec) - *spec = spec_array[slot_id]; - return 0; - err: -- return -1; -+ return FPGA_ERR_FAIL; - } - - int --fpga_pci_get_resource_map(int slot_id, int pf_id, struct fpga_pci_resource_map *map) -+fpga_pci_get_resource_map(int slot_id, int pf_id, -+ struct fpga_pci_resource_map *map) - { -- (void) slot_id; -- (void) pf_id; -- (void) map; -- return -ENOSYS; -+ int ret; -+ -+ if (slot_id < 0 || slot_id >= FPGA_SLOT_MAX || -+ pf_id < 0 || pf_id >= FPGA_MAX_PF || -+ !map) { -+ return -EINVAL; -+ } -+ -+ struct fpga_slot_spec slot_spec; -+ memset(&slot_spec, 0, sizeof(struct fpga_slot_spec)); -+ -+ ret = fpga_pci_get_slot_spec(slot_id, &slot_spec); -+ fail_on_quiet(ret, out, "fpga_pci_get_slot_spec failed"); -+ -+ *map = slot_spec.map[pf_id]; -+out: -+ return ret; - } - - int --fpga_pci_rescan_slot_app_pfs(int slot_id) -+fpga_pci_rescan_slot_app_pfs(void) - { -- (void) slot_id; -- return -ENOSYS; -+ /** Setup and write '1' to the PCI rescan file */ -+ char sysfs_name[NAME_MAX + 1]; -+ int ret = snprintf(sysfs_name, sizeof(sysfs_name), "/sys/bus/pci/rescan"); -+ -+ fail_on_quiet(ret < 0, err, -+ "Error building the sysfs path for PCI rescan file"); -+ fail_on_quiet((size_t) ret >= sizeof(sysfs_name), err, -+ "sysfs path too long for PCI rescan file"); -+ -+ /** Write a "1" to the PCI rescan file */ -+ ret = fpga_pci_write_one2file(sysfs_name); -+ fail_on_quiet(ret != 0, err, "fpga_pci_write_one2file failed"); -+ -+ return 0; -+err: -+ return FPGA_ERR_FAIL; - } -diff --git a/sdk/userspace/hal/src/api/mbox/hw/Makefile b/sdk/userspace/hal/src/api/mbox/hw/Makefile -index d7e68e5..edb667a 100644 ---- a/sdk/userspace/hal/src/api/mbox/hw/Makefile -+++ b/sdk/userspace/hal/src/api/mbox/hw/Makefile -@@ -24,7 +24,7 @@ HALLIB_PATH = $(TOP)/lib - INCLUDES = -I. -I$(HALINC_PATH) -I$(TOPINC_PATH) -I$(FPGADINC_PATH) -I$(UTILINC_PATH) -I/usr/include - - #OPT=-O2 --CFLAGS=$(OPT) -g -fPIC -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) -+CFLAGS=$(OPT) -g -fPIC -Wall -Werror -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) - - SRC = fpga_hal_mbox.c - OBJ = $(SRC:.c=.o) -diff --git a/sdk/userspace/hal/src/api/reg/Makefile b/sdk/userspace/hal/src/api/reg/Makefile -index ead0ee4..52c9afe 100644 ---- a/sdk/userspace/hal/src/api/reg/Makefile -+++ b/sdk/userspace/hal/src/api/reg/Makefile -@@ -24,7 +24,7 @@ HALLIB_PATH = $(TOP)/lib - INCLUDES = -I. -I$(HALINC_PATH) -I$(TOPINC_PATH) -I$(FPGADINC_PATH) -I$(UTILINC_PATH) -I/usr/include - - #OPT=-O2 --CFLAGS=$(OPT) -g -fPIC -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) -+CFLAGS=$(OPT) -g -fPIC -Wall -Werror -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) - - SRC = $(wildcard *.c) - OBJ = $(SRC:.c=.o) -diff --git a/sdk/userspace/hal/src/api/reg/fpga_hal_reg.c b/sdk/userspace/hal/src/api/reg/fpga_hal_reg.c -index 44b61b5..83e4997 100644 ---- a/sdk/userspace/hal/src/api/reg/fpga_hal_reg.c -+++ b/sdk/userspace/hal/src/api/reg/fpga_hal_reg.c -@@ -41,6 +41,20 @@ fpga_hal_dev_reg_write(int dev_index, uint64_t offset, uint32_t value) - return fpga_plat_dev_reg_write(dev_index, offset, value); - } - -+int -+fpga_hal_dev_reg_read64(int dev_index, uint64_t offset, uint64_t *value) -+{ -+ log_debug("enter"); -+ return fpga_plat_dev_reg_read64(dev_index, offset, value); -+} -+ -+int -+fpga_hal_dev_reg_write64(int dev_index, uint64_t offset, uint64_t value) -+{ -+ log_debug("enter"); -+ return fpga_plat_dev_reg_write64(dev_index, offset, value); -+} -+ - /************************************************************************ - * Single device attachment and use. - * e.g. for applications that only attach to one FPGA at a time, -diff --git a/sdk/userspace/hal/src/platform/hw/Makefile b/sdk/userspace/hal/src/platform/hw/Makefile -index 7d6f203..05a20cf 100644 ---- a/sdk/userspace/hal/src/platform/hw/Makefile -+++ b/sdk/userspace/hal/src/platform/hw/Makefile -@@ -24,7 +24,7 @@ HALLIB_PATH = $(TOP)/lib - INCLUDES = -I. -I$(HALINC_PATH) -I$(TOPINC_PATH) -I$(FPGADINC_PATH) -I$(UTILINC_PATH) -I/usr/include - - #OPT=-O2 --CFLAGS=$(OPT) -g -fPIC -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) -+CFLAGS=$(OPT) -g -fPIC -Wall -Werror -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) - - SRC = $(wildcard *.c) - OBJ = $(SRC:.c=.o) -diff --git a/sdk/userspace/hal/src/platform/hw/fpga_hal_plat.c b/sdk/userspace/hal/src/platform/hw/fpga_hal_plat.c -index 0dbe576..bc17b82 100644 ---- a/sdk/userspace/hal/src/platform/hw/fpga_hal_plat.c -+++ b/sdk/userspace/hal/src/platform/hw/fpga_hal_plat.c -@@ -198,7 +198,8 @@ err: - ************************************************************************/ - - int --fpga_plat_dev_attach(struct fpga_slot_spec *spec, int pf_id, int bar_id, int *dev_index) -+fpga_plat_dev_attach(struct fpga_slot_spec *spec, int pf_id, int bar_id, -+ bool write_combining, int *dev_index) - { - log_debug("enter"); - -@@ -247,7 +248,7 @@ fpga_plat_dev_attach(struct fpga_slot_spec *spec, int pf_id, int bar_id, int *de - sysfs_name, map->device_id); - - char wc_suffix[3] = "\0"; -- if (map->resource_burstable[bar_id]) { -+ if (map->resource_burstable[bar_id] && write_combining) { - strncpy(wc_suffix, "_wc", sizeof(wc_suffix)); - } - -@@ -353,6 +354,84 @@ err: - return -1; - } - -+int -+fpga_plat_dev_reg_read64(int dev_index, uint64_t offset, uint64_t *value) -+{ -+ log_debug("dev_index=%d", dev_index); -+ fail_on(!value, err, "value is NULL"); -+ -+ int ret = fpga_plat_dev_check_mem_offset(dev_index, offset); -+ fail_on(ret != 0, err, "Invalid offset 0x%" PRIx64 ", or not attached", offset); -+ -+ uint64_t *reg_ptr = (uint64_t *)fpga_plat_dev_get_mem_at_offset(dev_index, -+ offset); -+ fail_on(!reg_ptr, err, "fpga_plat_get_mem_at_offset failed"); -+ -+ *value = *reg_ptr; -+ -+ log_debug("offset=0x%" PRIx64 ", value=0x%" PRIx64, offset, *value); -+ return 0; -+err: -+ return -1; -+} -+ -+int -+fpga_plat_dev_reg_write64(int dev_index, uint64_t offset, uint64_t value) -+{ -+ log_debug("dev_index=%d", dev_index); -+ -+ int ret = fpga_plat_dev_check_mem_offset(dev_index, offset); -+ fail_on(ret != 0, err, "Invalid offset=0x%" PRIx64 ", or not attached", -+ offset); -+ -+ log_debug("offset=0x%" PRIx64 ", value=0x%" PRIx64, offset, value); -+ uint64_t *reg_ptr = (uint64_t *)fpga_plat_dev_get_mem_at_offset(dev_index, -+ offset); -+ fail_on(!reg_ptr, err, "fpga_plat_get_mem_at_offset failed"); -+ -+ *reg_ptr = value; -+ -+ return 0; -+err: -+ return -1; -+} -+ -+int -+fpga_plat_dev_reg_write_burst(int dev_index, uint64_t offset, uint32_t* datap, -+ uint32_t dword_len) -+{ -+ int ret; -+ uint32_t i; -+ static const uint32_t dword_mult = 4; -+ log_debug("dev_index=%d", dev_index); -+ -+ /* validate the beginning of the data range */ -+ ret = fpga_plat_dev_check_mem_offset(dev_index, offset); -+ fail_on(ret != 0, err, "Invalid offset=0x%" PRIx64 ", or not attached", -+ offset); -+ -+ /* validate the end of the data range */ -+ ret = fpga_plat_dev_check_mem_offset(dev_index, -+ offset + dword_len * dword_mult - 1); -+ fail_on(ret != 0, err, "Invalid offset=0x%" PRIx64 " (out of range)", -+ offset); -+ -+ /* get the pointer to the beginning of the range */ -+ log_debug("offset=0x%" PRIx64, offset); -+ uint32_t *reg_ptr = (uint32_t *)fpga_plat_dev_get_mem_at_offset(dev_index, -+ offset); -+ fail_on(!reg_ptr, err, "fpga_plat_get_mem_at_offset failed"); -+ -+ /* memcpy */ -+ for (i = 0; i < dword_len; ++i) { -+ reg_ptr[i] = datap[i]; -+ } -+ -+ return 0; -+err: -+ return -1; -+} -+ - /************************************************************************ - * Single device attachment and use. - * e.g. for applications that only attach to one FPGA at a time, -@@ -366,7 +445,7 @@ fpga_plat_attach(struct fpga_slot_spec *spec, int pf_id, int bar_id) - log_debug("enter"); - - int dev_index = -1; -- int ret = fpga_plat_dev_attach(spec, pf_id, bar_id, &dev_index); -+ int ret = fpga_plat_dev_attach(spec, pf_id, bar_id, false, &dev_index); - fail_on(ret != 0, err, "fpga_plat_dev_attach failed"); - - if (dev_index != 0) { -diff --git a/sdk/userspace/include/fpga_common.h b/sdk/userspace/include/fpga_common.h -index 8921fb6..46786a7 100644 ---- a/sdk/userspace/include/fpga_common.h -+++ b/sdk/userspace/include/fpga_common.h -@@ -79,10 +79,8 @@ enum { - FPGA_ERR_CL_ID_MISMATCH = 12, - /** CL DDR calibration failed */ - FPGA_ERR_CL_DDR_CALIB_FAILED = 13, -- /** fpga_clk_recipe is invalid */ -- FPGA_ERR_CLK_RECIPE_INVALID = 14, -- /** fpga_clk_recipe programming failed */ -- FPGA_ERR_CLK_RECIPE_FAILED = 15, -+ /** generic/unspecified error */ -+ FPGA_ERR_FAIL = 14, - - FPGA_ERR_END - }; -@@ -95,8 +93,7 @@ enum { - ((error) == FPGA_ERR_AFI_CMD_API_VERSION_INVALID) ? "invalid-afi-cmd-api-version" : \ - ((error) == FPGA_ERR_CL_ID_MISMATCH) ? "cl-id-mismatch" : \ - ((error) == FPGA_ERR_CL_DDR_CALIB_FAILED) ? "cl-ddr-calib-failed" : \ -- ((error) == FPGA_ERR_CLK_RECIPE_INVALID) ? "invalid-clk-recipe" : \ -- ((error) == FPGA_ERR_CLK_RECIPE_FAILED) ? "clk-recipe-failed" : \ -+ ((error) == FPGA_ERR_FAIL) ? "unspecified-error" : \ - "internal-error" - - -diff --git a/sdk/userspace/include/fpga_mgmt.h b/sdk/userspace/include/fpga_mgmt.h -index 047010c..221508e 100644 ---- a/sdk/userspace/include/fpga_mgmt.h -+++ b/sdk/userspace/include/fpga_mgmt.h -@@ -22,28 +22,42 @@ - /** - * Initialize the fpga_mgmt library. - * Calls fpga_pci_init. -- * @returns -- * 0 on success -- * -1 on failure -+ * -+ * @returns 0 on success, non-zero on error - */ - int fpga_mgmt_init(void); - -+/** -+ * Closes the fpga_mgmt library and its dependencies and releases any acquired -+ * resources. -+ * -+ * @returns 0 on success, non-zero on error -+ */ - int fpga_mgmt_close(void); - - /** -+ * Get an error code string. -+ * -+ * @param[in] err The error code to decode -+ * @returns a string corresponding to the provided error code. -+ */ -+const char *fpga_mgmt_strerror(int err); -+ -+/** - * Sets the command timeout value in multiples of the delay_msec value. - * -- * @param[in] value timeout, n * delay_msec -+ * @param[in] value timeout, n * delay_msec - */ - void fpag_mgmt_set_cmd_timeout(uint32_t value); - - /** -+ * Sets the value of the delay_msec. The value is used as the basic unit of time -+ * used to calculate timeouts for communicating with the mailbox pf. - * -+ * @param[in] value number of ms used as base time unit - */ - void fpag_mgmt_set_cmd_delay_msec(uint32_t value); - --/* fpga-describe-local-image */ -- - /** - * This structure provides all of the information for - * fpga_mgmt_describe_local_image. -@@ -63,12 +77,14 @@ struct fpga_mgmt_image_info { - * - * @param[in] slot_id the logical slot index - * @param[out] info struct to populate with the slot description -+ * @param[in] flags set flags for for metrics retrieval options - * @returns 0 on success, non-zero on error - */ --int fpga_mgmt_describe_local_image(int slot_id, struct fpga_mgmt_image_info *info); -+int fpga_mgmt_describe_local_image(int slot_id, -+ struct fpga_mgmt_image_info *info, uint32_t flags); - - /** -- * Gets the status of an FPGA. Status values are definted in enum fpga_status. -+ * Gets the status of an FPGA. Status values are defined in enum fpga_status. - * If you need the AFI id at the same time, use fpga_mgmt_describe_local_image. - * - * @param[in] slot_id the logical slot index -@@ -86,7 +102,6 @@ int fpga_mgmt_get_status(int slot_id, int *status); - */ - const char *fpga_mgmt_get_status_name(int status); - --/* fpga-clear-local-image */ - /** - * Clears the specified FPGA image slot, including FPGA internal and external - * memories that are used by the slot. -@@ -96,7 +111,6 @@ const char *fpga_mgmt_get_status_name(int status); - */ - int fpga_mgmt_clear_local_image(int slot_id); - --/* fpga-load-local-image */ - /** - * Loads the specified FPGA image to the specified slot number. - * -@@ -107,17 +121,32 @@ int fpga_mgmt_clear_local_image(int slot_id); - int fpga_mgmt_load_local_image(int slot_id, char *afi_id); - - /** -- * getting the status of the 16 virtual LED -+ * Gets the status of the 16 virtual LEDs. Their statuses are returned as a -+ * 16-bit value with each bit corresponding to the on/off state of the LEDs. -+ * -+ * @param[in] slot_id the logical slot index -+ * @param[out] status 16 bits describing the LED states -+ * @returns 0 on success, non-zero on error - */ - int fpga_mgmt_get_vLED_status(int slot_id, uint16_t *status); - - /** -- * set the value for the 16 virtual DIP switchs -+ * Sets the status of the 16 virtual dip switches. Their statuses are set as a -+ * 16-bit value with each bit corresponding to the on/off state of the switches. -+ * -+ * @param[in] slot_id the logical slot index -+ * @param[in] value 16 bits describing the switch states -+ * @returns 0 on success, non-zero on error - */ - int fpga_mgmt_set_vDIP(int slot_id, uint16_t value); - - /** -- * get the value for the 16 virtual DIP switchs -+ * Gets the status of the 16 virtual dip switches. Their statuses are returned -+ * as a 16-bit value with each bit corresponding to the on/off state of the -+ * switches. -+ * -+ * @param[in] slot_id the logical slot index -+ * @param[out] value 16 bits describing the switch states -+ * @returns 0 on success, non-zero on error - */ --int fpga_mgmt_get_vDIP_status(int slot_id, uint16_t *); -- -+int fpga_mgmt_get_vDIP_status(int slot_id, uint16_t *value); -diff --git a/sdk/userspace/include/fpga_pci.h b/sdk/userspace/include/fpga_pci.h -index dda8865..20f219a 100644 ---- a/sdk/userspace/include/fpga_pci.h -+++ b/sdk/userspace/include/fpga_pci.h -@@ -33,15 +33,16 @@ enum { - MGMT_PF_BAR_MAX - }; - -+/** -+ * Type definition for a descriptor/handle used to specify a BAR. Initialize -+ * with PCI_BAR_HANDLE_INIT. -+ */ - typedef int pci_bar_handle_t; - #define PCI_BAR_HANDLE_INIT (-1) - - /** - * Initialize the pci library. -- * Calls fpga_hal_plat_init. -- * @returns -- * 0 on success -- * -1 on failure -+ * @returns 0 on success, non-zero on error - */ - int fpga_pci_init(void); - -@@ -57,11 +58,8 @@ int fpga_pci_init(void); - * - * @returns 0 on success, non-zero on error - */ --int fpga_pci_attach(int slot_id, int pf_id, int bar_id, uint32_t flags, pci_bar_handle_t *handle); -- --/** -- */ --int fpga_pci_attach_2(struct fpga_pci_resource_map *map, int bar_id, uint32_t flags, pci_bar_handle_t *handle); -+int fpga_pci_attach(int slot_id, int pf_id, int bar_id, uint32_t flags, -+ pci_bar_handle_t *handle); - - /** - * Flags used to specify options for fpga_pci_attach. -@@ -72,13 +70,13 @@ enum { - }; - - /** -- * Detatch from an FPGA memory space. -+ * Detach from an FPGA memory space. - * - * @param[in] handle the value provided by fpga_pci_attach corresponding to - * the memory space to detach - * @returns 0 on success, non-zero on error - */ --int fpga_pci_detatch(pci_bar_handle_t handle); -+int fpga_pci_detach(pci_bar_handle_t handle); - - /** - * Write a value to a register. -@@ -110,7 +108,8 @@ int fpga_pci_poke64(pci_bar_handle_t handle, uint64_t offset, uint64_t value); - * - * @returns 0 on success, non-zero on error - */ --int fpga_pci_write_burst(pci_bar_handle_t handle, uint64_t offset, uint32_t* datap, uint32_t dword_len); -+int fpga_pci_write_burst(pci_bar_handle_t handle, uint64_t offset, -+ uint32_t* datap, uint32_t dword_len); - - /** - * Read a value from a register. -@@ -144,13 +143,30 @@ int fpga_pci_peek64(pci_bar_handle_t handle, uint64_t offset, uint64_t *value); - int fpga_pci_get_slot_spec(int slot_id, struct fpga_slot_spec *spec); - - /** -+ * Populate slot specs for all FPGAs on the system. It is recommended to use -+ * FPGA_SLOT_MAX as the size of the spec_array; -+ * -+ * @param[out] spec_array array to populate -+ * @param[in] size allocated size of the provided array - */ - int fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size); - - /** -+ * Get resource map information for a single slot and physical function. This -+ * information is provided in the slot_spec, but occasionally only the resource -+ * map is needed. -+ * -+ * @param[in] slot_id The logical slot id of the FPGA of interest -+ * @param[in] pf_id physical function id (e.g. FPGA_APP_PF) -+ * @param[out] map resource map to populate -+ * @returns 0 on success, non-zero on error - */ --int fpga_pci_get_resource_map(int slot_id, int pf_id, struct fpga_pci_resource_map *map); -+int fpga_pci_get_resource_map(int slot_id, int pf_id, -+ struct fpga_pci_resource_map *map); - - /** -+ * PCI rescan. -+ * -+ * @returns 0 on success, non-zero on error - */ --int fpga_pci_rescan_slot_app_pfs(int slot_id); -+int fpga_pci_rescan_slot_app_pfs(void); -diff --git a/sdk/userspace/include/hal/fpga_hal_plat.h b/sdk/userspace/include/hal/fpga_hal_plat.h -index a7e8088..15afbfc 100644 ---- a/sdk/userspace/include/hal/fpga_hal_plat.h -+++ b/sdk/userspace/include/hal/fpga_hal_plat.h -@@ -75,7 +75,8 @@ int fpga_plat_init(void); - * 0 on success - * -1 on failure - */ --int fpga_plat_dev_attach(struct fpga_slot_spec *spec, int pf_id, int bar_id, int *dev_index); -+int fpga_plat_dev_attach(struct fpga_slot_spec *spec, int pf_id, int bar_id, -+ bool write_combining, int *dev_index); - - /** - * Platform layer detach using the given slot specification. -@@ -114,6 +115,33 @@ int fpga_plat_dev_reg_read(int dev_index, uint64_t offset, uint32_t *value); - */ - int fpga_plat_dev_reg_write(int dev_index, uint64_t offset, uint32_t value); - -+ -+/** -+ * Platform layer register read. -+ * -+ * @param[in] dev_index the attached fpga device index. -+ * @param[in] offset the register offset -+ * @param[in,out] value the register value to return -+ * -+ * @returns -+ * 0 on success -+ * -1 on failure -+ */ -+int fpga_plat_dev_reg_read64(int dev_index, uint64_t offset, uint64_t *value); -+ -+/** -+ * Platform layer register write. -+ * -+ * @param[in] dev_index the attached fpga device index. -+ * @param[in] offset the register offset -+ * @param[in] value the register value to write -+ * -+ * @returns -+ * 0 on success -+ * -1 on failure -+ */ -+int fpga_plat_dev_reg_write64(int dev_index, uint64_t offset, uint64_t value); -+ - /** - * Platform layer get mem base. - * -@@ -125,6 +153,17 @@ int fpga_plat_dev_reg_write(int dev_index, uint64_t offset, uint32_t value); - */ - void *fpga_plat_dev_get_mem_base(int dev_index); - -+/** -+ * Platform layer write burst. -+ * -+ * @param[in] dev_index the attached fpga device index. -+ * @param[in] offset the register offset -+ * @param[in] datap source pointer -+ * @param[in] dword_len number of 4 byte words to copy -+ */ -+int fpga_plat_dev_reg_write_burst(int dev_index, uint64_t offset, -+ uint32_t* datap, uint32_t dword_len); -+ - /************************************************************************ - * Single device attachment and use. - * e.g. for applications that only attach to one FPGA at a time, -diff --git a/sdk/userspace/include/hal/fpga_hal_reg.h b/sdk/userspace/include/hal/fpga_hal_reg.h -index fa7bcad..e63cb31 100644 ---- a/sdk/userspace/include/hal/fpga_hal_reg.h -+++ b/sdk/userspace/include/hal/fpga_hal_reg.h -@@ -51,6 +51,32 @@ int fpga_hal_dev_reg_read(int dev_index, uint64_t offset, uint32_t *value); - */ - int fpga_hal_dev_reg_write(int dev_index, uint64_t offset, uint32_t value); - -+/** -+ * FPGA HAL layer register read. -+ * -+ * @param[in] dev_index the attached fpga device index. -+ * @param[in] offset the register offset -+ * @param[in,out] value the register value to return -+ * -+ * @returns -+ * 0 on success -+ * -1 on failure -+ */ -+int fpga_hal_dev_reg_read64(int dev_index, uint64_t offset, uint64_t *value); -+ -+/** -+ * FPGA HAL layer register write. -+ * -+ * @param[in] dev_index the attached fpga device index. -+ * @param[in] offset the register offset -+ * @param[in] value the register value to write -+ * -+ * @returns -+ * 0 on success -+ * -1 on failure -+ */ -+int fpga_hal_dev_reg_write64(int dev_index, uint64_t offset, uint64_t value); -+ - /************************************************************************ - * Single device attachment and use. - * e.g. for applications that only attach to one FPGA at a time, -diff --git a/sdk/userspace/include/utils/log.h b/sdk/userspace/include/utils/log.h -index d3cd7b4..60cec19 100644 ---- a/sdk/userspace/include/utils/log.h -+++ b/sdk/userspace/include/utils/log.h -@@ -163,6 +163,14 @@ static inline __printf(1, 2) void log_dummy(const char *fmt, ...) - } \ - } while (0) - -+#define fail_on_quiet(CONDITION, LABEL, ...) \ -+ do { \ -+ if (CONDITION) { \ -+ log_debug(__VA_ARGS__); \ -+ goto LABEL; \ -+ } \ -+ } while (0) -+ - extern const struct logger logger_stdout; - extern const struct logger logger_kmsg; - extern const struct logger *logger_default; -diff --git a/sdk/userspace/utils/Makefile b/sdk/userspace/utils/Makefile -index 90b7306..af10ad3 100644 ---- a/sdk/userspace/utils/Makefile -+++ b/sdk/userspace/utils/Makefile -@@ -18,7 +18,7 @@ INCLUDES = -I. -I../include -I/usr/include - LIB_PATH = $(TOP)/lib - - #OPT=-O2 --CFLAGS=$(OPT) -g -std=gnu99 -fPIC -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) -+CFLAGS=$(OPT) -g -std=gnu99 -fPIC -Wall -Werror -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes $(INCLUDES) - - UTILLIB = $(LIB_PATH)/libutils.a - diff --git a/SDAccel/userspace/src/xclbin.cpp b/SDAccel/userspace/src/xclbin.cpp index 18bb8475..7ce369e5 100644 --- a/SDAccel/userspace/src/xclbin.cpp +++ b/SDAccel/userspace/src/xclbin.cpp @@ -17,6 +17,7 @@ * License for the specific language governing permissions and limitations * under the License. */ +//#define INTERNAL_TESTING 1 #include diff --git a/SDAccel/userspace/src2/LICENSE-2.0.txt b/SDAccel/userspace/src2/LICENSE-2.0.txt deleted file mode 100644 index d6456956..00000000 --- a/SDAccel/userspace/src2/LICENSE-2.0.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/SDAccel/userspace/src2/Makefile b/SDAccel/userspace/src2/Makefile deleted file mode 100755 index f95abfd6..00000000 --- a/SDAccel/userspace/src2/Makefile +++ /dev/null @@ -1,82 +0,0 @@ -# Amazon FPGA Hardware Development Kit -# -# Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Amazon Software License (the "License"). You may not use -# this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/asl/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or -# implied. See the License for the specific language governing permissions and -# limitations under the License. - - -# AWS Bare-metal HAL Driver Makefile -# set ec2=1 to compile for F1 instance - -CXX := g++ -CXX_EXT := cpp -AR := ar -ARFLAGS := rcv - -ifeq ($(ec2),1) - CXXFLAGS := -Werror -std=c++11 - STLIB = libxrt-aws.a - SHLIB = libxrt-aws.so -else -# For bare metal testing, i.e. in non EC2 environment - CXXFLAGS := -Werror -std=c++11 -DINTERNAL_TESTING - STLIB = libxrtbm-aws.a - SHLIB = libxrtbm-aws.so -endif - -LIBS := $(STLIB) $(SHLIB) - -XCLHAL_VER = -DXCLHAL_MAJOR_VER=2 -DXCLHAL_MINOR_VER=1 - -# Include XCLHAL includes, AWS fpga_pci/mgmt and AWS kernel drivers -SHIM_INC := -I../include -I$(SDK_DIR)/userspace/include -I$(SDK_DIR)/linux_kernel_drivers - -CXXFLAGS += $(CXXFLAGS) $(XCLHAL_VER) $(SHIM_INC) -fpic -fvisibility=hidden -lrt -Wall - -ifeq ($(debug),1) - CXXFLAGS += -g -DDEBUG -else - CXXFLAGS += -O2 -DNDEBUG -endif - -SRCS := $(wildcard *.$(CXX_EXT)) -OBJS := $(patsubst %.$(CXX_EXT), %.o, $(SRCS)) - --include $(OBJS:.o=.d) - -# the name that will be included as libXXXXX.so -AWS_FPGA_MGMTLIB := fpga_mgmt -AWS_FPGA_MGMTLIB_DIR := $(SDK_DIR)/userspace/lib - -ifeq ($(ec2),1) -LDFLAGS += -L$(AWS_FPGA_MGMTLIB_DIR) -LDLIBS += -l$(AWS_FPGA_MGMTLIB) -endif - -all: $(LIBS) - -clean: - rm -rf *.o *.d lib*drv.* - -%.o: %.$(CXX_EXT) - $(CXX) $(CXXFLAGS) $(MYCFLAGS) $(MYCXXFLAGS) -c $< -o $@ - $(CXX) $(CXXFLAGS) $(MYCFLAGS) $(MYCXXFLAGS) -c -MM $< -o $(patsubst %.o, %.d, $@) - -$(STLIB) : $(OBJS) - $(AR) $(ARFLAGS) -o $@ $(OBJS) - -$(SHLIB) : $(OBJS) - $(CXX) -shared -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS) - -.PHONY: all clean - -.DEFAULT_GOAL := all diff --git a/SDAccel/userspace/src2/debug.cpp b/SDAccel/userspace/src2/debug.cpp deleted file mode 100644 index 7cbee184..00000000 --- a/SDAccel/userspace/src2/debug.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2017-2018 Xilinx, Inc - * Debug functionality to AWS hal driver - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - - -#include "shim.h" -#include "perfmon_parameters.h" -#include "xclbin2.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef _WINDOWS -// TODO: Windows build support -// unistd.h is linux only header file -// it is included for read, write, close, lseek64 -#include -#endif - -#ifdef _WINDOWS -#define __func__ __FUNCTION__ -#endif - -namespace awsbwhal { - // **************** - // Helper functions - // **************** - - void AwsXcl::readDebugIpLayout() - { - if (mIsDebugIpLayoutRead) - return; - - // - // Profiling - addresses and names - // Parsed from debug_ip_layout.rtd contained in xclbin - if (mLogStream.is_open()) { - mLogStream << "debug_ip_layout: reading profile addresses and names..." << std::endl; - } - mMemoryProfilingNumberSlots = getIPCountAddrNames(AXI_MM_MONITOR, mPerfMonBaseAddress, mPerfMonSlotName); - mIsDeviceProfiling = (mMemoryProfilingNumberSlots > 0); - - std::string fifoName; - uint64_t fifoCtrlBaseAddr = mOffsets[XCL_ADDR_SPACE_DEVICE_PERFMON]; - getIPCountAddrNames(AXI_MONITOR_FIFO_LITE, &fifoCtrlBaseAddr, &fifoName); - mPerfMonFifoCtrlBaseAddress = fifoCtrlBaseAddr; - - uint64_t fifoReadBaseAddr = XPAR_AXI_PERF_MON_0_TRACE_OFFSET_AXI_FULL2; - getIPCountAddrNames(AXI_MONITOR_FIFO_FULL, &fifoReadBaseAddr, &fifoName); - mPerfMonFifoReadBaseAddress = fifoReadBaseAddr; - - if (mLogStream.is_open()) { - for (unsigned int i = 0; i < mMemoryProfilingNumberSlots; ++i) { - mLogStream << "debug_ip_layout: AXI_MM_MONITOR slot " << i << ": " - << "base address = 0x" << std::hex << mPerfMonBaseAddress[i] - << ", name = " << mPerfMonSlotName[i] << std::endl; - } - mLogStream << "debug_ip_layout: AXI_MONITOR_FIFO_LITE: " - << "base address = 0x" << std::hex << fifoCtrlBaseAddr << std::endl; - mLogStream << "debug_ip_layout: AXI_MONITOR_FIFO_FULL: " - << "base address = 0x" << std::hex << fifoReadBaseAddr << std::endl; - } - - // Only need to read it once - mIsDebugIpLayoutRead = true; - } - - // Gets the information about the specified IP from the sysfs debug_ip_table. - // The IP types are defined in xclbin.h - uint32_t AwsXcl::getIPCountAddrNames(int type, uint64_t *baseAddress, std::string * portNames) { - debug_ip_layout *map; - std::string path = "/sys/bus/pci/devices/" + mDevUserName + "/debug_ip_layout"; - std::ifstream ifs(path.c_str(), std::ifstream::binary); - uint32_t count = 0; - char buffer[4096]; - if( ifs ) { - //sysfs max file size is 4096 - ifs.read(buffer, 4096); - if (ifs.gcount() > 0) { - map = (debug_ip_layout*)(buffer); - for( unsigned int i = 0; i < map->m_count; i++ ) { - if (map->m_debug_ip_data[i].m_type == type) { - if(baseAddress)baseAddress[count] = map->m_debug_ip_data[i].m_base_address; - if(portNames) portNames[count] = (char*)map->m_debug_ip_data[i].m_name; - ++count; - } - } - } - ifs.close(); - } - return count; - } - - // Read APM performance counters - size_t AwsXcl::xclDebugReadCheckers(xclDebugCheckersResults* aCheckerResults) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() - << ", " << aCheckerResults - << ", Read protocl checker status..." << std::endl; - } - - size_t size = 0; - - uint64_t statusRegisters[] = { - LAPC_OVERALL_STATUS_OFFSET, - - LAPC_CUMULATIVE_STATUS_0_OFFSET, LAPC_CUMULATIVE_STATUS_1_OFFSET, - LAPC_CUMULATIVE_STATUS_2_OFFSET, LAPC_CUMULATIVE_STATUS_3_OFFSET, - - LAPC_SNAPSHOT_STATUS_0_OFFSET, LAPC_SNAPSHOT_STATUS_1_OFFSET, - LAPC_SNAPSHOT_STATUS_2_OFFSET, LAPC_SNAPSHOT_STATUS_3_OFFSET - }; - - uint64_t baseAddress[XLAPC_MAX_NUMBER_SLOTS]; - uint32_t numSlots = getIPCountAddrNames(LAPC, baseAddress, nullptr); - uint32_t temp[XLAPC_STATUS_PER_SLOT]; - aCheckerResults->NumSlots = numSlots; - snprintf(aCheckerResults->DevUserName, 256, "%s", mDevUserName.c_str()); - for (uint32_t s = 0; s < numSlots; ++s) { - for (int c=0; c < XLAPC_STATUS_PER_SLOT; c++) - size += xclRead(XCL_ADDR_SPACE_DEVICE_CHECKER, baseAddress[s]+statusRegisters[c], &temp[c], 4); - - aCheckerResults->OverallStatus[s] = temp[XLAPC_OVERALL_STATUS]; - std::copy(temp+XLAPC_CUMULATIVE_STATUS_0, temp+XLAPC_SNAPSHOT_STATUS_0, aCheckerResults->CumulativeStatus[s]); - std::copy(temp+XLAPC_SNAPSHOT_STATUS_0, temp+XLAPC_STATUS_PER_SLOT, aCheckerResults->SnapshotStatus[s]); - } - - return size; - } - - // Read APM performance counters - - size_t AwsXcl::xclDebugReadCounters(xclDebugCountersResults* aCounterResults) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() - << ", " << XCL_PERF_MON_MEMORY << ", " << aCounterResults - << ", Read device counters..." << std::endl; - } - - size_t size = 0; - - uint64_t spm_offsets[] = { - XSPM_SAMPLE_WRITE_BYTES_OFFSET, - XSPM_SAMPLE_WRITE_TRANX_OFFSET, - XSPM_SAMPLE_READ_BYTES_OFFSET, - XSPM_SAMPLE_READ_TRANX_OFFSET, - XSPM_SAMPLE_OUTSTANDING_COUNTS_OFFSET, - XSPM_SAMPLE_LAST_WRITE_ADDRESS_OFFSET, - XSPM_SAMPLE_LAST_WRITE_DATA_OFFSET, - XSPM_SAMPLE_LAST_READ_ADDRESS_OFFSET, - XSPM_SAMPLE_LAST_READ_DATA_OFFSET - }; - - // Read all metric counters - uint64_t baseAddress[XSPM_MAX_NUMBER_SLOTS]; - uint32_t numSlots = getIPCountAddrNames(AXI_MM_MONITOR, baseAddress, nullptr); - - uint32_t temp[XSPM_DEBUG_SAMPLE_COUNTERS_PER_SLOT]; - - aCounterResults->NumSlots = numSlots; - snprintf(aCounterResults->DevUserName, 256, "%s", mDevUserName.c_str()); - for (uint32_t s=0; s < numSlots; s++) { - uint32_t sampleInterval; - // Read sample interval register to latch the sampled metric counters - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, - baseAddress[s] + XSPM_SAMPLE_OFFSET, - &sampleInterval, 4); - - for (int c=0; c < XSPM_DEBUG_SAMPLE_COUNTERS_PER_SLOT; c++) - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress[s]+spm_offsets[c], &temp[c], 4); - - aCounterResults->WriteBytes[s] = temp[0]; - aCounterResults->WriteTranx[s] = temp[1]; - - aCounterResults->ReadBytes[s] = temp[2]; - aCounterResults->ReadTranx[s] = temp[3]; - aCounterResults->OutStandCnts[s] = temp[4]; - aCounterResults->LastWriteAddr[s] = temp[5]; - aCounterResults->LastWriteData[s] = temp[6]; - aCounterResults->LastReadAddr[s] = temp[7]; - aCounterResults->LastReadData[s] = temp[8]; - } - return size; - } -} // namespace awsbwhal - -size_t xclDebugReadIPStatus(xclDeviceHandle handle, xclDebugReadType type, void* debugResults) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - switch (type) { - case XCL_DEBUG_READ_TYPE_LAPC : - return drv->xclDebugReadCheckers(reinterpret_cast(debugResults)); - case XCL_DEBUG_READ_TYPE_SPM : - return drv->xclDebugReadCounters(reinterpret_cast(debugResults)); - default : - break; - }; - return -1; -} diff --git a/SDAccel/userspace/src2/perf.cpp b/SDAccel/userspace/src2/perf.cpp deleted file mode 100755 index 74a0d994..00000000 --- a/SDAccel/userspace/src2/perf.cpp +++ /dev/null @@ -1,766 +0,0 @@ -/* - * Copyright (C) 2017-2018 Xilinx, Inc - * Performance Monitoring using PCIe for AWS HAL Driver - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -#include "shim.h" -#include "perfmon_parameters.h" -#include "xocl/xocl_ioctl.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WINDOWS -#define __func__ __FUNCTION__ -#endif - -namespace awsbwhal { - - static int unmgdPread(int fd, void *buffer, size_t size, uint64_t addr) - { - drm_xocl_pread_unmgd unmgd = { 0, 0, addr, size, reinterpret_cast(buffer) }; - return ioctl(fd, DRM_IOCTL_XOCL_PREAD_UNMGD, &unmgd); - } - - // **************** - // Helper functions - // **************** - - unsigned AwsXcl::getBankCount() { - return mDeviceInfo.mDDRBankCount; - } - - void AwsXcl::xclSetProfilingNumberSlots(xclPerfMonType type, uint32_t numSlots) { - if (type == XCL_PERF_MON_OCL_REGION) - mOclRegionProfilingNumberSlots = numSlots; - } - - // Get host timestamp to write to APM - // IMPORTANT NOTE: this *must* be compatible with the method of generating - // timestamps as defined in RTProfile::getTraceTime() - uint64_t AwsXcl::getHostTraceTimeNsec() { - struct timespec now; - int err; - if ((err = clock_gettime(CLOCK_MONOTONIC, &now)) < 0) - return 0; - - return (uint64_t) now.tv_sec * 1000000000UL + (uint64_t) now.tv_nsec; - } - - uint64_t AwsXcl::getPerfMonBaseAddress(xclPerfMonType type, uint32_t slotNum) { - if (type == XCL_PERF_MON_MEMORY) return mPerfMonBaseAddress[slotNum]; - return 0; - } - - uint64_t AwsXcl::getPerfMonFifoBaseAddress(xclPerfMonType type, uint32_t fifonum) { - if (type == XCL_PERF_MON_MEMORY) return mPerfMonFifoCtrlBaseAddress; - return 0; - } - - uint64_t AwsXcl::getPerfMonFifoReadBaseAddress(xclPerfMonType type, uint32_t fifonum) { - if (type == XCL_PERF_MON_MEMORY) return mPerfMonFifoReadBaseAddress; - return 0; - } - - uint32_t AwsXcl::getPerfMonNumberFifos(xclPerfMonType type) { - if (type == XCL_PERF_MON_MEMORY) - return XPAR_AXI_PERF_MON_0_TRACE_NUMBER_FIFO; - if (type == XCL_PERF_MON_HOST_INTERFACE) - return XPAR_AXI_PERF_MON_1_TRACE_NUMBER_FIFO; - if (type == XCL_PERF_MON_OCL_REGION) { - if (mOclRegionProfilingNumberSlots > 4) - return 3; - else - return 2; - } - return 0; - } - - uint32_t AwsXcl::getPerfMonNumberSlots(xclPerfMonType type) { - if (type == XCL_PERF_MON_MEMORY) { - return (getBankCount() + 1); - } - if (type == XCL_PERF_MON_HOST_INTERFACE) { - return XPAR_AXI_PERF_MON_1_NUMBER_SLOTS; - } - if (type == XCL_PERF_MON_OCL_REGION) { - return mOclRegionProfilingNumberSlots; - } - return 1; - } - - uint32_t AwsXcl::getPerfMonNumberSamples(xclPerfMonType type) { - if (type == XCL_PERF_MON_MEMORY) return XPAR_AXI_PERF_MON_0_TRACE_NUMBER_SAMPLES; - if (type == XCL_PERF_MON_HOST_INTERFACE) return XPAR_AXI_PERF_MON_1_TRACE_NUMBER_SAMPLES; - if (type == XCL_PERF_MON_OCL_REGION) return XPAR_AXI_PERF_MON_2_TRACE_NUMBER_SAMPLES; - return 0; - } - - uint32_t AwsXcl::getPerfMonByteScaleFactor(xclPerfMonType type) { - return 1; - } - - uint8_t AwsXcl::getPerfMonShowIDS(xclPerfMonType type) { - if (type == XCL_PERF_MON_MEMORY) { - if (getBankCount() > 1) - return XPAR_AXI_PERF_MON_0_SHOW_AXI_IDS_2DDR; - return XPAR_AXI_PERF_MON_0_SHOW_AXI_IDS; - } - if (type == XCL_PERF_MON_HOST_INTERFACE) { - return XPAR_AXI_PERF_MON_1_SHOW_AXI_IDS; - } - if (type == XCL_PERF_MON_OCL_REGION) { - return XPAR_AXI_PERF_MON_2_SHOW_AXI_IDS; - } - return 0; - } - - uint8_t AwsXcl::getPerfMonShowLEN(xclPerfMonType type) { - if (type == XCL_PERF_MON_MEMORY) { - if (getBankCount() > 1) - return XPAR_AXI_PERF_MON_0_SHOW_AXI_LEN_2DDR; - return XPAR_AXI_PERF_MON_0_SHOW_AXI_LEN; - } - if (type == XCL_PERF_MON_HOST_INTERFACE) { - return XPAR_AXI_PERF_MON_1_SHOW_AXI_LEN; - } - if (type == XCL_PERF_MON_OCL_REGION) { - return XPAR_AXI_PERF_MON_2_SHOW_AXI_LEN; - } - return 0; - } - - uint32_t AwsXcl::getPerfMonSlotStartBit(xclPerfMonType type, uint32_t slotnum) { - // NOTE: ID widths also set to 5 in HEAD/data/sdaccel/board_support/alpha_data/common/xclplat/xclplat_ip.tcl - uint32_t bitsPerID = 5; - uint8_t showIDs = getPerfMonShowIDS(type); - uint8_t showLen = getPerfMonShowLEN(type); - uint32_t bitsPerSlot = 10 + (bitsPerID * 4 * showIDs) + (16 * showLen); - return (18 + (bitsPerSlot * slotnum)); - } - - uint32_t AwsXcl::getPerfMonSlotDataWidth(xclPerfMonType type, uint32_t slotnum) { - if (slotnum == 0) return XPAR_AXI_PERF_MON_0_SLOT0_DATA_WIDTH; - if (slotnum == 1) return XPAR_AXI_PERF_MON_0_SLOT1_DATA_WIDTH; - if (slotnum == 2) return XPAR_AXI_PERF_MON_0_SLOT2_DATA_WIDTH; - if (slotnum == 3) return XPAR_AXI_PERF_MON_0_SLOT3_DATA_WIDTH; - if (slotnum == 4) return XPAR_AXI_PERF_MON_0_SLOT4_DATA_WIDTH; - if (slotnum == 5) return XPAR_AXI_PERF_MON_0_SLOT5_DATA_WIDTH; - if (slotnum == 6) return XPAR_AXI_PERF_MON_0_SLOT6_DATA_WIDTH; - if (slotnum == 7) return XPAR_AXI_PERF_MON_0_SLOT7_DATA_WIDTH; - return XPAR_AXI_PERF_MON_0_SLOT0_DATA_WIDTH; - } - - // Get the device clock frequency (in MHz) - double AwsXcl::xclGetDeviceClockFreqMHz() { - unsigned clockFreq = mDeviceInfo.mOCLFrequency[0]; - if (clockFreq == 0) - clockFreq = 200; - - //if (mLogStream.is_open()) - // mLogStream << __func__ << ": clock freq = " << clockFreq << std::endl; - return ((double)clockFreq); - } - - // Get the maximum bandwidth for host reads from the device (in MB/sec) - // NOTE: for now, set to: (256/8 bytes) * 300 MHz = 9600 MBps - double AwsXcl::xclGetReadMaxBandwidthMBps() { - return 9600.0; - } - - // Get the maximum bandwidth for host writes to the device (in MB/sec) - // NOTE: for now, set to: (256/8 bytes) * 300 MHz = 9600 MBps - double AwsXcl::xclGetWriteMaxBandwidthMBps() { - return 9600.0; - } - - // Convert binary string to decimal - uint32_t AwsXcl::bin2dec(std::string str, int start, int number) { - return bin2dec(str.c_str(), start, number); - } - - // Convert binary char * to decimal - uint32_t AwsXcl::bin2dec(const char* ptr, int start, int number) { - const char* temp_ptr = ptr + start; - uint32_t value = 0; - int i = 0; - - do { - if (*temp_ptr != '0' && *temp_ptr!= '1') - return value; - value <<= 1; - if(*temp_ptr=='1') - value += 1; - i++; - temp_ptr++; - } while (i < number); - - return value; - } - - // Convert decimal to binary string - // NOTE: length of string is always sizeof(uint32_t) * 8 - std::string AwsXcl::dec2bin(uint32_t n) { - char result[(sizeof(uint32_t) * 8) + 1]; - unsigned index = sizeof(uint32_t) * 8; - result[index] = '\0'; - - do { - result[ --index ] = '0' + (n & 1); - } while (n >>= 1); - - for (int i=index-1; i >= 0; --i) - result[i] = '0'; - - return std::string( result ); - } - - // Convert decimal to binary string of length bits - std::string AwsXcl::dec2bin(uint32_t n, unsigned bits) { - char result[bits + 1]; - unsigned index = bits; - result[index] = '\0'; - - do result[ --index ] = '0' + (n & 1); - while (n >>= 1); - - for (int i=index-1; i >= 0; --i) - result[i] = '0'; - - return std::string( result ); - } - - // Reset all APM trace AXI stream FIFOs - size_t AwsXcl::resetFifos(xclPerfMonType type) { - uint64_t resetCoreAddress[] = { - getPerfMonFifoBaseAddress(type, 0) + AXI_FIFO_SRR, - getPerfMonFifoBaseAddress(type, 1) + AXI_FIFO_SRR, - getPerfMonFifoBaseAddress(type, 2) + AXI_FIFO_SRR - }; - - uint64_t resetFifoAddress[] = { - getPerfMonFifoBaseAddress(type, 0) + AXI_FIFO_RDFR, - getPerfMonFifoBaseAddress(type, 1) + AXI_FIFO_RDFR, - getPerfMonFifoBaseAddress(type, 2) + AXI_FIFO_RDFR - }; - - size_t size = 0; - uint32_t regValue = AXI_FIFO_RESET_VALUE; - - for (int f=0; f < XPAR_AXI_PERF_MON_0_TRACE_NUMBER_FIFO; f++) { - size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, resetCoreAddress[f], ®Value, 4); - size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, resetFifoAddress[f], ®Value, 4); - } - - return size; - } - - // ******** - // Counters - // ******** - - // Start device counters performance monitoring - size_t AwsXcl::xclPerfMonStartCounters(xclPerfMonType type) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " - << type << ", Start device counters..." << std::endl; - } - - // Update addresses for debug/profile IP - readDebugIpLayout(); - - if (!mIsDeviceProfiling) - return 0; - - size_t size = 0; - uint32_t regValue; - uint64_t baseAddress; - uint32_t numSlots = getPerfMonNumberSlots(type); - - for (uint32_t i = 0; i < numSlots; i++) { - baseAddress = getPerfMonBaseAddress(type, i); - - // 1. Reset AXI - MM monitor metric counters - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_CONTROL_OFFSET, ®Value, 4); - - regValue = regValue | XSPM_CR_COUNTER_RESET_MASK; - size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_CONTROL_OFFSET, ®Value, 4); - - regValue = regValue & ~(XSPM_CR_COUNTER_RESET_MASK); - size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_CONTROL_OFFSET, ®Value, 4); - - // 2. Start AXI-MM monitor metric counters - regValue = regValue | XSPM_CR_COUNTER_ENABLE_MASK; - size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_CONTROL_OFFSET, ®Value, 4); - - // 3. Read from sample register to ensure total time is read again at end - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_SAMPLE_OFFSET, ®Value, 4); - } - return size; - } - - // Stop both profile and trace performance monitoring - size_t AwsXcl::xclPerfMonStopCounters(xclPerfMonType type) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " - << type << ", Stop and reset device counters..." << std::endl; - } - - if (!mIsDeviceProfiling) - return 0; - - size_t size = 0; - uint32_t regValue; - uint64_t baseAddress; - uint32_t numSlots = getPerfMonNumberSlots(type); - - for (uint32_t i = 0; i < numSlots; i++) { - baseAddress = getPerfMonBaseAddress(type, i); - - // 1. Stop SPM metric counters - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_CONTROL_OFFSET, ®Value, 4); - - regValue = regValue & ~(XSPM_CR_COUNTER_ENABLE_MASK); - size += xclWrite(XCL_ADDR_SPACE_DEVICE_PERFMON, baseAddress + XSPM_CONTROL_OFFSET, ®Value, 4); - } - return size; - } - - // Read APM performance counters - size_t AwsXcl::xclPerfMonReadCounters(xclPerfMonType type, xclCounterResults& counterResults) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() - << ", " << type << ", " << &counterResults - << ", Read device counters..." << std::endl; - } - - // Initialize all values in struct to 0 - memset(&counterResults, 0, sizeof(xclCounterResults)); - - if (!mIsDeviceProfiling) - return 0; - - size_t size = 0; - uint64_t baseAddress; - uint32_t sampleInterval; - uint32_t numSlots = getPerfMonNumberSlots(type); - - for (uint32_t s = 0; s < numSlots; s++) { - baseAddress = getPerfMonBaseAddress(type, s); - - // Read sample interval register - // NOTE: this also latches the sampled metric counters - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, - baseAddress + XSPM_SAMPLE_OFFSET, - &sampleInterval, 4); - // Need to do this for every xilmon - if (s == 0) { - counterResults.SampleIntervalUsec = sampleInterval / xclGetDeviceClockFreqMHz(); - } - - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, - baseAddress + XSPM_SAMPLE_WRITE_BYTES_OFFSET, - &counterResults.WriteBytes[s], 4); - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, - baseAddress + XSPM_SAMPLE_WRITE_TRANX_OFFSET, - &counterResults.WriteTranx[s], 4); - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, - baseAddress + XSPM_SAMPLE_WRITE_LATENCY_OFFSET, - &counterResults.WriteLatency[s], 4); - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, - baseAddress + XSPM_SAMPLE_READ_BYTES_OFFSET, - &counterResults.ReadBytes[s], 4); - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, - baseAddress + XSPM_SAMPLE_READ_TRANX_OFFSET, - &counterResults.ReadTranx[s], 4); - size += xclRead(XCL_ADDR_SPACE_DEVICE_PERFMON, - baseAddress + XSPM_SAMPLE_READ_LATENCY_OFFSET, - &counterResults.ReadLatency[s], 4); - - if (mLogStream.is_open()) { - mLogStream << "Reading ...SlotNum : " << s << std::endl; - mLogStream << "Reading ...WriteBytes : " << counterResults.WriteBytes[s] << std::endl; - mLogStream << "Reading ...WriteTranx : " << counterResults.WriteTranx[s] << std::endl; - mLogStream << "Reading ...WriteLatency : " << counterResults.WriteLatency[s] << std::endl; - mLogStream << "Reading ...ReadBytes : " << counterResults.ReadBytes[s] << std::endl; - mLogStream << "Reading ...ReadTranx : " << counterResults.ReadTranx[s] << std::endl; - mLogStream << "Reading ...ReadLatency : " << counterResults.ReadLatency[s] << std::endl; - } - } - return size; - } - - // ***** - // Trace - // ***** - - // Clock training used in converting device trace timestamps to host domain - size_t AwsXcl::xclPerfMonClockTraining(xclPerfMonType type) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " - << type << ", Send clock training..." << std::endl; - } - // We're snapping first event to start of cu. - return 1; - } - - // Start trace performance monitoring - size_t AwsXcl::xclPerfMonStartTrace(xclPerfMonType type, uint32_t startTrigger) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() - << ", " << type << ", " << startTrigger - << ", Start device tracing..." << std::endl; - } - - // Update addresses for debug/profile IP - readDebugIpLayout(); - - if (!mIsDeviceProfiling) - return 0; - - size_t size = 0; - xclPerfMonGetTraceCount(type); - size += resetFifos(type); - xclPerfMonGetTraceCount(type); - return size; - } - - // Stop trace performance monitoring - size_t AwsXcl::xclPerfMonStopTrace(xclPerfMonType type) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " - << type << ", Stop and reset device tracing..." << std::endl; - } - - if (!mIsDeviceProfiling) - return 0; - - size_t size = 0; - xclPerfMonGetTraceCount(type); - size += resetFifos(type); - return size; - } - - // Get trace word count - uint32_t AwsXcl::xclPerfMonGetTraceCount(xclPerfMonType type) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() - << ", " << type << std::endl; - } - - if (!mIsDeviceProfiling) - return 0; - - xclAddressSpace addressSpace = (type == XCL_PERF_MON_OCL_REGION) ? - XCL_ADDR_KERNEL_CTRL : XCL_ADDR_SPACE_DEVICE_PERFMON; - - uint32_t fifoCount = 0; - uint32_t numSamples = 0; - uint32_t numBytes = 0; - xclRead(addressSpace, getPerfMonFifoBaseAddress(type, 0) + AXI_FIFO_RLR, &fifoCount, 4); - // Read bits 22:0 per AXI-Stream FIFO product guide (PG080, 10/1/14) - numBytes = fifoCount & 0x7FFFFF; - numSamples = numBytes / (XPAR_AXI_PERF_MON_0_TRACE_WORD_WIDTH / 8); - - if (mLogStream.is_open()) { - mLogStream << " No. of trace samples = " << std::dec << numSamples - << " (fifoCount = 0x" << std::hex << fifoCount << ")" << std::dec << std::endl; - } - - return numSamples; - } - - // Read all values from APM trace AXI stream FIFOs - size_t AwsXcl::xclPerfMonReadTrace(xclPerfMonType type, xclTraceResultsVector& traceVector) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() - << ", " << type << ", " << &traceVector - << ", Reading device trace stream..." << std::endl; - } - - traceVector.mLength = 0; - if (!mIsDeviceProfiling) - return 0; - - uint32_t numSamples = xclPerfMonGetTraceCount(type); - if (numSamples == 0) - return 0; - - uint64_t fifoReadAddress[] = { 0, 0, 0 }; - if (type == XCL_PERF_MON_MEMORY) { - fifoReadAddress[0] = getPerfMonFifoReadBaseAddress(type, 0) + AXI_FIFO_RDFD_AXI_FULL; - } - else { - for (int i = 0; i < 3; i++) - fifoReadAddress[i] = getPerfMonFifoReadBaseAddress(type, i) + AXI_FIFO_RDFD; - } - - size_t size = 0; - - // Limit to max number of samples so we don't overrun trace buffer on host - uint32_t maxSamples = getPerfMonNumberSamples(type); - numSamples = (numSamples > maxSamples) ? maxSamples : numSamples; - traceVector.mLength = numSamples; - - const uint32_t bytesPerSample = (XPAR_AXI_PERF_MON_0_TRACE_WORD_WIDTH / 8); - const uint32_t wordsPerSample = (XPAR_AXI_PERF_MON_0_TRACE_WORD_WIDTH / 32); - //uint32_t numBytes = numSamples * bytesPerSample; - uint32_t numWords = numSamples * wordsPerSample; - - // Create trace buffer on host (requires alignment) - const int BUFFER_BYTES = MAX_TRACE_NUMBER_SAMPLES * bytesPerSample; - const int BUFFER_WORDS = MAX_TRACE_NUMBER_SAMPLES * wordsPerSample; -#if GCC_VERSION >= 40800 - alignas(AXI_FIFO_RDFD_AXI_FULL)uint32_t hostbuf[BUFFER_WORDS]; -#else - AlignedAllocator alignedBuffer(AXI_FIFO_RDFD_AXI_FULL, BUFFER_WORDS); - uint32_t* hostbuf = alignedBuffer.getBuffer(); -#endif - memset((void *)hostbuf, 0, BUFFER_BYTES); - - // Iterate over chunks - // NOTE: AXI limits this to 4K bytes per transfer - uint32_t chunkSizeWords = 256 * wordsPerSample; - if (chunkSizeWords > 1024) chunkSizeWords = 1024; - uint32_t chunkSizeBytes = 4 * chunkSizeWords; - uint32_t words = 0; - - // Read trace a chunk of bytes at a time - if (numWords > chunkSizeWords) { - for (; words < (numWords - chunkSizeWords); words += chunkSizeWords) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ": reading " << chunkSizeBytes << " bytes from 0x" - << std::hex << fifoReadAddress[0] << " and writing it to 0x" - << (void *)(hostbuf + words) << std::dec << std::endl; - } - - if (awsbwhal::unmgdPread(mUserHandle, (void *)(hostbuf + words), chunkSizeBytes, fifoReadAddress[0]) < 0) - return 0; - - size += chunkSizeBytes; - } - } - - // Read remainder of trace not divisible by chunk size - if (words < numWords) { - chunkSizeBytes = 4 * (numWords - words); - - if (mLogStream.is_open()) { - mLogStream << __func__ << ": reading " << chunkSizeBytes << " bytes from 0x" - << std::hex << fifoReadAddress[0] << " and writing it to 0x" - << (void *)(hostbuf + words) << std::dec << std::endl; - } - - if (awsbwhal::unmgdPread(mUserHandle, (void *)(hostbuf + words), chunkSizeBytes, fifoReadAddress[0]) < 0) - return 0; - - size += chunkSizeBytes; - } - - if (mLogStream.is_open()) { - mLogStream << __func__ << ": done reading " << size << " bytes " << std::endl; - } - - // ****************************** - // Read & process all trace FIFOs - // ****************************** - for (uint32_t wordnum = 0; wordnum < numSamples; wordnum++) { - uint32_t index = wordsPerSample * wordnum; - xclTraceResults results; - uint64_t temp = 0; - - temp = *(hostbuf + index) | (uint64_t)*(hostbuf + index + 1) << 32; - if (!temp) - continue; - - // Initialize result to 0 - memset(&results, 0, sizeof(xclTraceResults)); - // SDSoC Packet Format - results.Timestamp = temp & 0x1FFFFFFFFFFF; - results.EventType = ((temp >> 45) & 0xF) ? XCL_PERF_MON_END_EVENT : - XCL_PERF_MON_START_EVENT; - results.TraceID = (temp >> 49) & 0xFFF; - results.Reserved = (temp >> 61) & 0x1; - results.Overflow = (temp >> 62) & 0x1; - results.Error = (temp >> 63) & 0x1; - results.EventID = XCL_PERF_MON_HW_EVENT; - traceVector.mArray[wordnum] = results; - - if (mLogStream.is_open()) { - mLogStream << " Trace sample " << std::dec << wordnum << ": "; - mLogStream << dec2bin(uint32_t(temp >> 32)) << " " << dec2bin(uint32_t(temp & 0xFFFFFFFF)); - mLogStream << std::endl; - mLogStream << " Timestamp : " << results.Timestamp << " "; - mLogStream << "Event Type : " << results.EventType << " "; - mLogStream << "slotID : " << results.TraceID << " "; - mLogStream << "Start, Stop : " << static_cast(results.Reserved) << " "; - mLogStream << "Overflow : " << static_cast(results.Overflow) << " "; - mLogStream << "Error : " << static_cast(results.Error) << " "; - mLogStream << std::endl; - } - } - - return size; - } // end xclPerfMonReadTrace - -} // namespace awsbwhal - - -size_t xclPerfMonStartCounters(xclDeviceHandle handle, xclPerfMonType type) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclPerfMonStartCounters(type); -} - - -size_t xclPerfMonStopCounters(xclDeviceHandle handle, xclPerfMonType type) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclPerfMonStopCounters(type); -} - - -size_t xclPerfMonReadCounters(xclDeviceHandle handle, xclPerfMonType type, xclCounterResults& counterResults) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclPerfMonReadCounters(type, counterResults); -} - - -size_t xclPerfMonClockTraining(xclDeviceHandle handle, xclPerfMonType type) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclPerfMonClockTraining(type); -} - - -size_t xclPerfMonStartTrace(xclDeviceHandle handle, xclPerfMonType type, uint32_t startTrigger) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclPerfMonStartTrace(type, startTrigger); -} - - -size_t xclPerfMonStopTrace(xclDeviceHandle handle, xclPerfMonType type) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclPerfMonStopTrace(type); -} - - -uint32_t xclPerfMonGetTraceCount(xclDeviceHandle handle, xclPerfMonType type) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclPerfMonGetTraceCount(type); -} - - -size_t xclPerfMonReadTrace(xclDeviceHandle handle, xclPerfMonType type, xclTraceResultsVector& traceVector) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclPerfMonReadTrace(type, traceVector); -} - - -double xclGetDeviceClockFreqMHz(xclDeviceHandle handle) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return 0.0; - return drv->xclGetDeviceClockFreqMHz(); -} - - -double xclGetReadMaxBandwidthMBps(xclDeviceHandle handle) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return 0.0; - return drv->xclGetReadMaxBandwidthMBps(); -} - - -double xclGetWriteMaxBandwidthMBps(xclDeviceHandle handle) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return 0.0; - return drv->xclGetWriteMaxBandwidthMBps(); -} - - -size_t xclGetDeviceTimestamp(xclDeviceHandle handle) -{ - return 0; -} - - -void xclSetProfilingNumberSlots(xclDeviceHandle handle, xclPerfMonType type, uint32_t numSlots) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return; - return drv->xclSetProfilingNumberSlots(type, numSlots); -} - - -uint32_t xclGetProfilingNumberSlots(xclDeviceHandle handle, xclPerfMonType type) -{ - return 2; -} - - -void xclGetProfilingSlotName(xclDeviceHandle handle, xclPerfMonType type, uint32_t slotnum, - char* slotName, uint32_t length) -{ - const char* name = (slotnum == XPAR_SPM0_HOST_SLOT) ? "Host" : "Kernels"; - strncpy(slotName, name, length); -} - - -void xclWriteHostEvent(xclDeviceHandle handle, xclPerfMonEventType type, - xclPerfMonEventID id) -{ - // don't do anything -} - -// 67d7842dbbe25473c3c32b93c0da8047785f30d78e8a024de1b57352245f9689 diff --git a/SDAccel/userspace/src2/perfmon_parameters.h b/SDAccel/userspace/src2/perfmon_parameters.h deleted file mode 100755 index 4a2f417b..00000000 --- a/SDAccel/userspace/src2/perfmon_parameters.h +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright (C) 2018 Xilinx, Inc - * Performance Monitoring Internal Parameters using PCIe for AWS HAL Driver. - * NOTE: partially taken from file xaxipmon_hw.h in v5.0 of APM driver - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -#ifndef _PERFMON_PARAMETERS_H -#define _PERFMON_PARAMETERS_H - -#define PERFMON0_OFFSET 0x100000 -#define PERFMON1_OFFSET 0x120000 -#define PERFMON2_OFFSET 0x010000 - -/************************ AXI Stream FIFOs ************************************/ - -/* Address offsets in core */ -#define AXI_FIFO_RDFR 0x18 -#define AXI_FIFO_RDFO 0x1c -#define AXI_FIFO_RDFD 0x20 -#define AXI_FIFO_RDFD_AXI_FULL 0x1000 -#define AXI_FIFO_TDFD 0x10 -#define AXI_FIFO_RLR 0x24 -#define AXI_FIFO_SRR 0x28 -#define AXI_FIFO_RESET_VALUE 0xA5 - -/************************ SDx Performance Monitor(SPM) ************************/ - -/* Address offsets in core */ -#define XSPM_CONTROL_OFFSET 0x08 -#define XSPM_TRACE_CTRL_OFFSET 0x10 -#define XSPM_EVENT_OFFSET 0x18 -#define XSPM_SAMPLE_OFFSET 0x20 -#define XSPM_FIFO_COUNTS_OFFSET 0x28 -#define XSPM_FIFO_READ_COUNTS_OFFSET 0x30 -#define XSPM_WRITE_BYTES_OFFSET 0x40 -#define XSPM_WRITE_TRANX_OFFSET 0x44 -#define XSPM_WRITE_LATENCY_OFFSET 0x48 -#define XSPM_READ_BYTES_OFFSET 0x4C -#define XSPM_READ_TRANX_OFFSET 0x50 -#define XSPM_READ_LATENCY_OFFSET 0x54 -//#define XSPM_MIN_MAX_WRITE_LATENCY_OFFSET 0x58 -//#define XSPM_MIN_MAX_READ_LATENCY_OFFSET 0x5C -#define XSPM_OUTSTANDING_COUNTS_OFFSET 0x58 -#define XSPM_LAST_WRITE_ADDRESS_OFFSET 0x5C -#define XSPM_LAST_WRITE_DATA_OFFSET 0x60 -#define XSPM_LAST_READ_ADDRESS_OFFSET 0x64 -#define XSPM_LAST_READ_DATA_OFFSET 0x68 -#define XSPM_SAMPLE_WRITE_BYTES_OFFSET 0x80 -#define XSPM_SAMPLE_WRITE_TRANX_OFFSET 0x84 -#define XSPM_SAMPLE_WRITE_LATENCY_OFFSET 0x88 -#define XSPM_SAMPLE_READ_BYTES_OFFSET 0x8C -#define XSPM_SAMPLE_READ_TRANX_OFFSET 0x90 -#define XSPM_SAMPLE_READ_LATENCY_OFFSET 0x94 -//#define XSPM_SAMPLE_MIN_MAX_WRITE_LATENCY_OFFSET 0x98 -//#define XSPM_SAMPLE_MIN_MAX_READ_LATENCY_OFFSET 0x9C -#define XSPM_SAMPLE_OUTSTANDING_COUNTS_OFFSET 0x98 -#define XSPM_SAMPLE_LAST_WRITE_ADDRESS_OFFSET 0x9C -#define XSPM_SAMPLE_LAST_WRITE_DATA_OFFSET 0xA0 -#define XSPM_SAMPLE_LAST_READ_ADDRESS_OFFSET 0xA4 -#define XSPM_SAMPLE_LAST_READ_DATA_OFFSET 0xA8 - -/* SPM Control Register masks */ -#define XSPM_CR_RESET_ON_SAMPLE_MASK 0x00000010 -#define XSPM_CR_FIFO_RESET_MASK 0x00000008 -#define XSPM_CR_TRACE_ENABLE_MASK 0x00000004 -#define XSPM_CR_COUNTER_RESET_MASK 0x00000002 -#define XSPM_CR_COUNTER_ENABLE_MASK 0x00000001 - -/************************ APM Constant Definitions ****************************/ - -/* Register offsets of AXIMONITOR in the Device Config */ - -#define XAPM_GCC_HIGH_OFFSET 0x0000 /**< Global Clock Counter 32 to 63 bits */ -#define XAPM_GCC_LOW_OFFSET 0x0004 /**< Global Clock Counter Lower 0-31 bits */ -#define XAPM_SI_HIGH_OFFSET 0x0020 /**< Sample Interval MSB */ -#define XAPM_SI_LOW_OFFSET 0x0024 /**< Sample Interval LSB */ -#define XAPM_SICR_OFFSET 0x0028 /**< Sample Interval Control Register */ -#define XAPM_SR_OFFSET 0x002C /**< Sample Register */ -#define XAPM_GIE_OFFSET 0x0030 /**< Global Interrupt Enable Register */ -#define XAPM_IE_OFFSET 0x0034 /**< Interrupt Enable Register */ -#define XAPM_IS_OFFSET 0x0038 /**< Interrupt Status Register */ - -#define XAPM_MSR0_OFFSET 0x0044 /**< Metric Selector 0 Register */ -#define XAPM_MSR1_OFFSET 0x0048 /**< Metric Selector 1 Register */ -#define XAPM_MSR2_OFFSET 0x004C /**< Metric Selector 2 Register */ - -#define XAPM_MC0_OFFSET 0x0100 /**< Metric Counter 0 Register */ -#define XAPM_INC0_OFFSET 0x0104 /**< Incrementer 0 Register */ -#define XAPM_RANGE0_OFFSET 0x0108 /**< Range 0 Register */ -#define XAPM_MC0LOGEN_OFFSET 0x010C /**< Metric Counter 0 Log Enable Register */ -#define XAPM_MC1_OFFSET 0x0110 /**< Metric Counter 1 Register */ -#define XAPM_INC1_OFFSET 0x0114 /**< Incrementer 1 Register */ -#define XAPM_RANGE1_OFFSET 0x0118 /**< Range 1 Register */ -#define XAPM_MC1LOGEN_OFFSET 0x011C /**< Metric Counter 1 Log Enable Register */ -#define XAPM_MC2_OFFSET 0x0120 /**< Metric Counter 2 Register */ -#define XAPM_INC2_OFFSET 0x0124 /**< Incrementer 2 Register */ -#define XAPM_RANGE2_OFFSET 0x0128 /**< Range 2 Register */ -#define XAPM_MC2LOGEN_OFFSET 0x012C /**< Metric Counter 2 Log Enable Register */ -#define XAPM_MC3_OFFSET 0x0130 /**< Metric Counter 3 Register */ -#define XAPM_INC3_OFFSET 0x0134 /**< Incrementer 3 Register */ -#define XAPM_RANGE3_OFFSET 0x0138 /**< Range 3 Register */ -#define XAPM_MC3LOGEN_OFFSET 0x013C /**< Metric Counter 3 Log Enable Register */ -#define XAPM_MC4_OFFSET 0x0140 /**< Metric Counter 4 Register */ -#define XAPM_INC4_OFFSET 0x0144 /**< Incrementer 4 Register */ -#define XAPM_RANGE4_OFFSET 0x0148 /**< Range 4 Register */ -#define XAPM_MC4LOGEN_OFFSET 0x014C /**< Metric Counter 4 Log Enable Register */ -#define XAPM_MC5_OFFSET 0x0150 /**< Metric Counter 5 Register */ -#define XAPM_INC5_OFFSET 0x0154 /**< Incrementer 5 Register */ -#define XAPM_RANGE5_OFFSET 0x0158 /**< Range 5 Register */ -#define XAPM_MC5LOGEN_OFFSET 0x015C /**< Metric Counter 5 Log Enable Register */ -#define XAPM_MC6_OFFSET 0x0160 /**< Metric Counter 6 Register */ -#define XAPM_INC6_OFFSET 0x0164 /**< Incrementer 6 Register */ -#define XAPM_RANGE6_OFFSET 0x0168 /**< Range 6 Register */ -#define XAPM_MC6LOGEN_OFFSET 0x016C /**< Metric Counter 6 Log Enable Register */ -#define XAPM_MC7_OFFSET 0x0170 /**< Metric Counter 7 Register */ -#define XAPM_INC7_OFFSET 0x0174 /**< Incrementer 7 Register */ -#define XAPM_RANGE7_OFFSET 0x0178 /**< Range 7 Register */ -#define XAPM_MC7LOGEN_OFFSET 0x017C /**< Metric Counter 7 Log Enable Register */ -#define XAPM_MC8_OFFSET 0x0180 /**< Metric Counter 8 Register */ -#define XAPM_INC8_OFFSET 0x0184 /**< Incrementer 8 Register */ -#define XAPM_RANGE8_OFFSET 0x0188 /**< Range 8 Register */ -#define XAPM_MC8LOGEN_OFFSET 0x018C /**< Metric Counter 8 Log Enable Register */ -#define XAPM_MC9_OFFSET 0x0190 /**< Metric Counter 9 Register */ -#define XAPM_INC9_OFFSET 0x0194 /**< Incrementer 9 Register */ -#define XAPM_RANGE9_OFFSET 0x0198 /**< Range 9 Register */ -#define XAPM_MC9LOGEN_OFFSET 0x019C /**< Metric Counter 9 Log Enable Register */ - -#define XAPM_SMC0_OFFSET 0x0200 /**< Sampled Metric Counter 0 Register */ -#define XAPM_SINC0_OFFSET 0x0204 /**< Sampled Incrementer 0 Register */ -#define XAPM_SMC1_OFFSET 0x0210 /**< Sampled Metric Counter 1 Register */ -#define XAPM_SINC1_OFFSET 0x0214 /**< Sampled Incrementer 1 Register */ -#define XAPM_SMC2_OFFSET 0x0220 /**< Sampled Metric Counter 2 Register */ -#define XAPM_SINC2_OFFSET 0x0224 /**< Sampled Incrementer 2 Register */ -#define XAPM_SMC3_OFFSET 0x0230 /**< Sampled Metric Counter 3 Register */ -#define XAPM_SINC3_OFFSET 0x0234 /**< Sampled Incrementer 3 Register */ -#define XAPM_SMC4_OFFSET 0x0240 /**< Sampled Metric Counter 4 Register */ -#define XAPM_SINC4_OFFSET 0x0244 /**< Sampled Incrementer 4 Register */ -#define XAPM_SMC5_OFFSET 0x0250 /**< Sampled Metric Counter 5 Register */ -#define XAPM_SINC5_OFFSET 0x0254 /**< Sampled Incrementer 5 Register */ -#define XAPM_SMC6_OFFSET 0x0260 /**< Sampled Metric Counter 6 Register */ -#define XAPM_SINC6_OFFSET 0x0264 /**< Sampled Incrementer 6 Register */ -#define XAPM_SMC7_OFFSET 0x0270 /**< Sampled Metric Counter 7 Register */ -#define XAPM_SINC7_OFFSET 0x0274 /**< Sampled Incrementer 7 Register */ -#define XAPM_SMC8_OFFSET 0x0280 /**< Sampled Metric Counter 8 Register */ -#define XAPM_SINC8_OFFSET 0x0284 /**< Sampled Incrementer 8 Register */ -#define XAPM_SMC9_OFFSET 0x0290 /**< Sampled Metric Counter 9 Register */ -#define XAPM_SINC9_OFFSET 0x0294 /**< Sampled Incrementer 9 Register */ - -#define XAPM_MC10_OFFSET 0x01A0 /**< Metric Counter 10 Register */ -#define XAPM_MC11_OFFSET 0x01B0 /**< Metric Counter 11 Register */ -#define XAPM_MC12_OFFSET 0x0500 /**< Metric Counter 12 Register */ -#define XAPM_MC13_OFFSET 0x0510 /**< Metric Counter 13 Register */ -#define XAPM_MC14_OFFSET 0x0520 /**< Metric Counter 14Register */ -#define XAPM_MC15_OFFSET 0x0530 /**< Metric Counter 15 Register */ -#define XAPM_MC16_OFFSET 0x0540 /**< Metric Counter 16 Register */ -#define XAPM_MC17_OFFSET 0x0550 /**< Metric Counter 17 Register */ -#define XAPM_MC18_OFFSET 0x0560 /**< Metric Counter 18 Register */ -#define XAPM_MC19_OFFSET 0x0570 /**< Metric Counter 19 Register */ -#define XAPM_MC20_OFFSET 0x0580 /**< Metric Counter 20 Register */ -#define XAPM_MC21_OFFSET 0x0590 /**< Metric Counter 21 Register */ -#define XAPM_MC22_OFFSET 0x05A0 /**< Metric Counter 22 Register */ -#define XAPM_MC23_OFFSET 0x05B0 /**< Metric Counter 23 Register */ -#define XAPM_MC24_OFFSET 0x0700 /**< Metric Counter 24 Register */ -#define XAPM_MC25_OFFSET 0x0710 /**< Metric Counter 25 Register */ -#define XAPM_MC26_OFFSET 0x0720 /**< Metric Counter 26 Register */ -#define XAPM_MC27_OFFSET 0x0730 /**< Metric Counter 27 Register */ -#define XAPM_MC28_OFFSET 0x0740 /**< Metric Counter 28 Register */ -#define XAPM_MC29_OFFSET 0x0750 /**< Metric Counter 29 Register */ -#define XAPM_MC30_OFFSET 0x0760 /**< Metric Counter 30 Register */ -#define XAPM_MC31_OFFSET 0x0770 /**< Metric Counter 31 Register */ -#define XAPM_MC32_OFFSET 0x0780 /**< Metric Counter 32 Register */ -#define XAPM_MC33_OFFSET 0x0790 /**< Metric Counter 33 Register */ -#define XAPM_MC34_OFFSET 0x07A0 /**< Metric Counter 34 Register */ -#define XAPM_MC35_OFFSET 0x07B0 /**< Metric Counter 35 Register */ -#define XAPM_MC36_OFFSET 0x0900 /**< Metric Counter 36 Register */ -#define XAPM_MC37_OFFSET 0x0910 /**< Metric Counter 37 Register */ -#define XAPM_MC38_OFFSET 0x0920 /**< Metric Counter 38 Register */ -#define XAPM_MC39_OFFSET 0x0930 /**< Metric Counter 39 Register */ -#define XAPM_MC40_OFFSET 0x0940 /**< Metric Counter 40 Register */ -#define XAPM_MC41_OFFSET 0x0950 /**< Metric Counter 41 Register */ -#define XAPM_MC42_OFFSET 0x0960 /**< Metric Counter 42 Register */ -#define XAPM_MC43_OFFSET 0x0970 /**< Metric Counter 43 Register */ -#define XAPM_MC44_OFFSET 0x0980 /**< Metric Counter 44 Register */ -#define XAPM_MC45_OFFSET 0x0990 /**< Metric Counter 45 Register */ -#define XAPM_MC46_OFFSET 0x09A0 /**< Metric Counter 46 Register */ -#define XAPM_MC47_OFFSET 0x09B0 /**< Metric Counter 47 Register */ - -#define XAPM_SMC10_OFFSET 0x02A0 /**< Sampled Metric Counter 10 Register */ -#define XAPM_SMC11_OFFSET 0x02B0 /**< Sampled Metric Counter 11 Register */ -#define XAPM_SMC12_OFFSET 0x0600 /**< Sampled Metric Counter 12 Register */ -#define XAPM_SMC13_OFFSET 0x0610 /**< Sampled Metric Counter 13 Register */ -#define XAPM_SMC14_OFFSET 0x0620 /**< Sampled Metric Counter 14 Register */ -#define XAPM_SMC15_OFFSET 0x0630 /**< Sampled Metric Counter 15 Register */ -#define XAPM_SMC16_OFFSET 0x0640 /**< Sampled Metric Counter 16 Register */ -#define XAPM_SMC17_OFFSET 0x0650 /**< Sampled Metric Counter 17 Register */ -#define XAPM_SMC18_OFFSET 0x0660 /**< Sampled Metric Counter 18 Register */ -#define XAPM_SMC19_OFFSET 0x0670 /**< Sampled Metric Counter 19 Register */ -#define XAPM_SMC20_OFFSET 0x0680 /**< Sampled Metric Counter 20 Register */ -#define XAPM_SMC21_OFFSET 0x0690 /**< Sampled Metric Counter 21 Register */ -#define XAPM_SMC22_OFFSET 0x06A0 /**< Sampled Metric Counter 22 Register */ -#define XAPM_SMC23_OFFSET 0x06B0 /**< Sampled Metric Counter 23 Register */ -#define XAPM_SMC24_OFFSET 0x0800 /**< Sampled Metric Counter 24 Register */ -#define XAPM_SMC25_OFFSET 0x0810 /**< Sampled Metric Counter 25 Register */ -#define XAPM_SMC26_OFFSET 0x0820 /**< Sampled Metric Counter 26 Register */ -#define XAPM_SMC27_OFFSET 0x0830 /**< Sampled Metric Counter 27 Register */ -#define XAPM_SMC28_OFFSET 0x0840 /**< Sampled Metric Counter 28 Register */ -#define XAPM_SMC29_OFFSET 0x0850 /**< Sampled Metric Counter 29 Register */ -#define XAPM_SMC30_OFFSET 0x0860 /**< Sampled Metric Counter 30 Register */ -#define XAPM_SMC31_OFFSET 0x0870 /**< Sampled Metric Counter 31 Register */ -#define XAPM_SMC32_OFFSET 0x0880 /**< Sampled Metric Counter 32 Register */ -#define XAPM_SMC33_OFFSET 0x0890 /**< Sampled Metric Counter 33 Register */ -#define XAPM_SMC34_OFFSET 0x08A0 /**< Sampled Metric Counter 34 Register */ -#define XAPM_SMC35_OFFSET 0x08B0 /**< Sampled Metric Counter 35 Register */ -#define XAPM_SMC36_OFFSET 0x0A00 /**< Sampled Metric Counter 36 Register */ -#define XAPM_SMC37_OFFSET 0x0A10 /**< Sampled Metric Counter 37 Register */ -#define XAPM_SMC38_OFFSET 0x0A20 /**< Sampled Metric Counter 38 Register */ -#define XAPM_SMC39_OFFSET 0x0A30 /**< Sampled Metric Counter 39 Register */ -#define XAPM_SMC40_OFFSET 0x0A40 /**< Sampled Metric Counter 40 Register */ -#define XAPM_SMC41_OFFSET 0x0A50 /**< Sampled Metric Counter 41 Register */ -#define XAPM_SMC42_OFFSET 0x0A60 /**< Sampled Metric Counter 42 Register */ -#define XAPM_SMC43_OFFSET 0x0A70 /**< Sampled Metric Counter 43 Register */ -#define XAPM_SMC44_OFFSET 0x0A80 /**< Sampled Metric Counter 44 Register */ -#define XAPM_SMC45_OFFSET 0x0A90 /**< Sampled Metric Counter 45 Register */ -#define XAPM_SMC46_OFFSET 0x0AA0 /**< Sampled Metric Counter 46 Register */ -#define XAPM_SMC47_OFFSET 0x0AB0 /**< Sampled Metric Counter 47 Register */ -/* Sampled metric counters 48-63: In Profile mode, this are min/max latency registers */ -#define XAPM_SMC48_OFFSET 0x0254 /**< Sampled Metric Counter 48 Register */ -#define XAPM_SMC49_OFFSET 0x0258 /**< Sampled Metric Counter 49 Register */ -#define XAPM_SMC50_OFFSET 0x02B4 /**< Sampled Metric Counter 50 Register */ -#define XAPM_SMC51_OFFSET 0x02B8 /**< Sampled Metric Counter 51 Register */ -#define XAPM_SMC52_OFFSET 0x0654 /**< Sampled Metric Counter 52 Register */ -#define XAPM_SMC53_OFFSET 0x0658 /**< Sampled Metric Counter 53 Register */ -#define XAPM_SMC54_OFFSET 0x06B4 /**< Sampled Metric Counter 54 Register */ -#define XAPM_SMC55_OFFSET 0x06B8 /**< Sampled Metric Counter 55 Register */ -#define XAPM_SMC56_OFFSET 0x0854 /**< Sampled Metric Counter 56 Register */ -#define XAPM_SMC57_OFFSET 0x0858 /**< Sampled Metric Counter 57 Register */ -#define XAPM_SMC58_OFFSET 0x08B4 /**< Sampled Metric Counter 58 Register */ -#define XAPM_SMC59_OFFSET 0x08B8 /**< Sampled Metric Counter 59 Register */ -#define XAPM_SMC60_OFFSET 0x0A54 /**< Sampled Metric Counter 60 Register */ -#define XAPM_SMC61_OFFSET 0x0A58 /**< Sampled Metric Counter 61 Register */ -#define XAPM_SMC62_OFFSET 0x0AB4 /**< Sampled Metric Counter 62 Register */ -#define XAPM_SMC63_OFFSET 0x0AB8 /**< Sampled Metric Counter 63 Register */ - -#define XAPM_CTL_OFFSET 0x0300 /**< Control Register */ -#define XAPM_ID_OFFSET 0x0304 /**< Latency ID Register */ -#define XAPM_IDMASK_OFFSET 0x0308 /**< ID Mask Register */ -#define XAPM_FEC_OFFSET 0x0400 /**< Flag Enable Control Register */ -#define XAPM_SWD_OFFSET 0x0404 /**< Software-written Data Register */ -#define XAPM_ENT_OFFSET 0x0408 /**< Enable Trace Register */ - -/* AXI Monitor Sample Interval Control Register mask(s) */ - -#define XAPM_SICR_MCNTR_RST_MASK 0x00000100 /**< Enable the Metric Counter Reset */ -#define XAPM_SICR_LOAD_MASK 0x00000002 /**< Load the Sample Interval Register Value into the counter */ -#define XAPM_SICR_ENABLE_MASK 0x00000001 /**< Enable the downcounter */ - -/* Interrupt Status/Enable Register Bit Definitions and Masks */ - -#define XAPM_IXR_MC9_OVERFLOW_MASK 0x00001000 /**< Metric Counter 9 Overflow> */ -#define XAPM_IXR_MC8_OVERFLOW_MASK 0x00000800 /**< Metric Counter 8 Overflow> */ -#define XAPM_IXR_MC7_OVERFLOW_MASK 0x00000400 /**< Metric Counter 7 Overflow> */ -#define XAPM_IXR_MC6_OVERFLOW_MASK 0x00000200 /**< Metric Counter 6 Overflow> */ -#define XAPM_IXR_MC5_OVERFLOW_MASK 0x00000100 /**< Metric Counter 5 Overflow> */ -#define XAPM_IXR_MC4_OVERFLOW_MASK 0x00000080 /**< Metric Counter 4 Overflow> */ -#define XAPM_IXR_MC3_OVERFLOW_MASK 0x00000040 /**< Metric Counter 3 Overflow> */ -#define XAPM_IXR_MC2_OVERFLOW_MASK 0x00000020 /**< Metric Counter 2 Overflow> */ -#define XAPM_IXR_MC1_OVERFLOW_MASK 0x00000010 /**< Metric Counter 1 Overflow> */ -#define XAPM_IXR_MC0_OVERFLOW_MASK 0x00000008 /**< Metric Counter 0 Overflow> */ -#define XAPM_IXR_FIFO_FULL_MASK 0x00000004 /**< Event Log FIFO full> */ -#define XAPM_IXR_SIC_OVERFLOW_MASK 0x00000002 /**< Sample Interval Counter Overflow> */ -#define XAPM_IXR_GCC_OVERFLOW_MASK 0x00000001 /**< Global Clock Counter Overflow> */ -#define XAPM_IXR_ALL_MASK (XAPM_IXR_SIC_OVERFLOW_MASK | \ - XAPM_IXR_GCC_OVERFLOW_MASK | \ - XAPM_IXR_FIFO_FULL_MASK | \ - XAPM_IXR_MC0_OVERFLOW_MASK | \ - XAPM_IXR_MC1_OVERFLOW_MASK | \ - XAPM_IXR_MC2_OVERFLOW_MASK | \ - XAPM_IXR_MC3_OVERFLOW_MASK | \ - XAPM_IXR_MC4_OVERFLOW_MASK | \ - XAPM_IXR_MC5_OVERFLOW_MASK | \ - XAPM_IXR_MC6_OVERFLOW_MASK | \ - XAPM_IXR_MC7_OVERFLOW_MASK | \ - XAPM_IXR_MC8_OVERFLOW_MASK | \ - XAPM_IXR_MC9_OVERFLOW_MASK) - -/* AXI Monitor Control Register mask(s) */ - -#define XAPM_CR_FIFO_RESET_MASK 0x02000000 /**< FIFO Reset */ -#define XAPM_CR_GCC_RESET_MASK 0x00020000 /**< Global Clk Counter Reset */ -#define XAPM_CR_GCC_ENABLE_MASK 0x00010000 /**< Global Clk Counter Enable */ -#define XAPM_CR_EVTLOG_EXTTRIGGER_MASK 0x00000200 /**< Enable External trigger to start event Log */ -#define XAPM_CR_EVENTLOG_ENABLE_MASK 0x00000100 /**< Event Log Enable */ -#define XAPM_CR_RDLATENCY_END_MASK 0x00000080 /**< Write Latency End point */ -#define XAPM_CR_RDLATENCY_START_MASK 0x00000040 /**< Read Latency Start point */ -#define XAPM_CR_WRLATENCY_END_MASK 0x00000020 /**< Write Latency End point */ -#define XAPM_CR_WRLATENCY_START_MASK 0x00000010 /**< Write Latency Start point */ -#define XAPM_CR_IDFILTER_ENABLE_MASK 0x00000008 /**< ID Filter Enable */ -#define XAPM_CR_MCNTR_EXTTRIGGER_MASK 0x00000004 /**< Enable External trigger to start Metric Counters */ -#define XAPM_CR_MCNTR_RESET_MASK 0x00000002 /**< Metrics Counter Reset */ -#define XAPM_CR_MCNTR_ENABLE_MASK 0x00000001 /**< Metrics Counter Enable */ - -/* AXI Monitor ID Register mask(s) */ - -#define XAPM_ID_RID_MASK 0xFFFF0000 /**< Read ID */ -#define XAPM_ID_WID_MASK 0x0000FFFF /**< Write ID */ - -/* AXI Monitor ID Mask Register mask(s) */ - -#define XAPM_MASKID_RID_MASK 0xFFFF0000 /**< Read ID Mask */ -#define XAPM_MASKID_WID_MASK 0x0000FFFF /**< Write ID Mask*/ - -/* AXI Monitor Min/Max Register masks and shifts */ - -#define XAPM_MAX_LATENCY_MASK 0xFFFF0000 /**< Max Latency Mask */ -#define XAPM_MIN_LATENCY_MASK 0x0000FFFF /**< Min Latency Mask */ -#define XAPM_MAX_LATENCY_SHIFT 16 /**< Max Latency Shift */ -#define XAPM_MIN_LATENCY_SHIFT 0 /**< Min Latency Shift */ - -/* LAPC Base address */ -#define LAPC0_BASE 0x00120000 //ocl master00 -#define LAPC1_BASE 0x00121000 //ocl master01 -#define LAPC2_BASE 0x00122000 //ocl master02 -#define LAPC3_BASE 0x00123000 //ocl master03 - -//Following status registers are available at each base -#define LAPC_OVERALL_STATUS_OFFSET 0x0 -#define LAPC_CUMULATIVE_STATUS_0_OFFSET 0x100 -#define LAPC_CUMULATIVE_STATUS_1_OFFSET 0x104 -#define LAPC_CUMULATIVE_STATUS_2_OFFSET 0x108 -#define LAPC_CUMULATIVE_STATUS_3_OFFSET 0x10c - -#define LAPC_SNAPSHOT_STATUS_0_OFFSET 0x200 -#define LAPC_SNAPSHOT_STATUS_1_OFFSET 0x204 -#define LAPC_SNAPSHOT_STATUS_2_OFFSET 0x208 -#define LAPC_SNAPSHOT_STATUS_3_OFFSET 0x20c -#endif - diff --git a/SDAccel/userspace/src2/shim.cpp b/SDAccel/userspace/src2/shim.cpp deleted file mode 100755 index 095ce5d0..00000000 --- a/SDAccel/userspace/src2/shim.cpp +++ /dev/null @@ -1,1514 +0,0 @@ -/* - * Copyright (C) 2017-2018 Xilinx, Inc - * Author: Sonal Santan - * AWS HAL Driver for SDAccel/OpenCL runtime evnrionemnt, for AWS EC2 F1 - * - * Code copied from SDAccel XDMA based HAL driver - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -#include "shim.h" -#include -/* - * Define GCC version macro so we can use newer C++11 features - * if possible - */ -#define GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) - -#ifdef INTERNAL_TESTING -#define ACCELERATOR_BAR 0 -#define MMAP_SIZE_USER 0x400000 -#endif - -/* Aligning access to FPGA DRAM space to 4096 Byte */ -#define DDR_BUFFER_ALIGNMENT 0x1000 - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xclbin2.h" -#include "xocl/xocl_ioctl.h" -#include "scan.h" -#include "awssak.h" - -#ifdef INTERNAL_TESTING -#include "driver/aws/kernel/include/mgmt-ioctl.h" -#else -#define AWSMGMT_NUM_SUPPORTED_CLOCKS 4 -#define AWSMGMT_NUM_ACTUAL_CLOCKS 3 -// TODO - define this in a header file -extern char* get_afi_from_xclBin(const xclBin *); -extern char* get_afi_from_axlf(const axlf *); -// define DEFAULT_GLOBAL_AFI "agfi-069ddd533a748059b" // 1.4 shell -#define DEFAULT_GLOBAL_AFI "agfi-0cc0ac6a40aa73ce8" // 1.4 shell 4-ddr data retention enabled -#endif - -namespace awsbwhal { - // This list will get populated in xclProbe - // 0 -> /dev/dri/renderD129 - // 1 -> /dev/dri/renderD130 - static std::mutex deviceListMutex; - // static std::vector> deviceList; - - const unsigned AwsXcl::TAG = 0X586C0C6C; // XL OpenCL X->58(ASCII), L->6C(ASCII), O->0 C->C L->6C(ASCII); - -#ifdef INTERNAL_TESTING - int AwsXcl::xclLoadAxlf(const axlf *buffer) - { - if ( mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << buffer << std::endl; - } - - if ( !mLocked) - return -EPERM; - - std::cout << "Downloading xclbin ...\n" << std::endl; - const unsigned cmd = AWSMGMT_IOCICAPDOWNLOAD_AXLF; - awsmgmt_ioc_bitstream_axlf obj = { const_cast(buffer) }; - int ret = ioctl(mMgtHandle, cmd, &obj); - if ( 0 != ret) - return ret; - - // If it is an XPR DSA, zero out the DDR again as downloading the XCLBIN - // reinitializes the DDR and results in ECC error. - if ( isXPR()) { - if ( mLogStream.is_open()) { - mLogStream << __func__ << "XPR Device found, zeroing out DDR again.." << std::endl; - } - - if ( zeroOutDDR() == false) { - if ( mLogStream.is_open()) { - mLogStream << __func__ << "zeroing out DDR failed" << std::endl; - } - return -EIO; - } - } - - drm_xocl_axlf axlf_obj = {const_cast(buffer)}; - ret = ioctl(mUserHandle, DRM_IOCTL_XOCL_READ_AXLF, &axlf_obj); - return ret; - } -#endif - - int AwsXcl::xclGetXclBinIdFromSysfs(uint64_t &xclbin_id_from_sysfs) - { - const std::string devPath = "/sys/bus/pci/devices/" + xcldev::pci_device_scanner::device_list[ mBoardNumber ].user_name; - std::string binid_path = devPath + "/xclbinid"; - struct stat sb; - if( stat( binid_path.c_str(), &sb ) < 0 ) { - std::cout << "ERROR: failed to stat " << binid_path << std::endl; - return errno; - } - std::ifstream ifs( binid_path.c_str(), std::ifstream::binary ); - if( !ifs.good() ) { - return errno; - } - char* fileReadBuf = new char[sb.st_size]; - memset(fileReadBuf, 0, sb.st_size); - ifs.read( fileReadBuf, sb.st_size ); - if( ifs.gcount() > 0 ) { - std::string tmp_hex_string = fileReadBuf; - xclbin_id_from_sysfs = std::stoi(std::string(fileReadBuf),nullptr,16); - } else { // xclbinid exists, but no data read or reported - std::cout << "WARNING: 'xclbinid' invalid, unable to report xclbinid. Has the bitstream been loaded? See 'xbsak program'.\n"; - } - delete [] fileReadBuf; - ifs.close(); - return 0; - } - - int AwsXcl::xclLoadXclBin(const xclBin *buffer) - { - char *xclbininmemory = reinterpret_cast (const_cast (buffer)); -#ifdef INTERNAL_TESTING - if (!memcmp(xclbininmemory, "xclbin2", 8)) { - return xclLoadAxlf(reinterpret_cast(xclbininmemory)); - } - - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << buffer << std::endl; - } - - if (!mLocked) - return -EPERM; - - const unsigned cmd = AWSMGMT_IOCICAPDOWNLOAD; - awsmgmt_ioc_bitstream obj = {const_cast(buffer)}; - return ioctl(mMgtHandle, cmd, &obj); -#else - if (!memcmp(xclbininmemory, "xclbin2", 8)) { - int retVal = 0; - axlf *axlfbuffer = reinterpret_cast(const_cast (buffer)); - fpga_mgmt_image_info orig_info; - char* afi_id = get_afi_from_axlf(axlfbuffer); - std::memset(&orig_info, 0, sizeof(struct fpga_mgmt_image_info)); - fpga_mgmt_describe_local_image(mBoardNumber, &orig_info, 0); - - uint64_t xclbin_id_from_sysfs; - if( int retVal = xclGetXclBinIdFromSysfs( xclbin_id_from_sysfs ) != 0 ) - return retVal; - - if ( (xclbin_id_from_sysfs == 0) || (axlfbuffer->m_uniqueId != xclbin_id_from_sysfs) || checkAndSkipReload(afi_id, &orig_info) ) { - // force data retention option - union fpga_mgmt_load_local_image_options opt; - fpga_mgmt_init_load_local_image_options(&opt); - opt.flags = FPGA_CMD_DRAM_DATA_RETENTION; - opt.afi_id = afi_id; - opt.slot_id = mBoardNumber; - retVal = fpga_mgmt_load_local_image_with_options(&opt); - if (retVal == FPGA_ERR_DRAM_DATA_RETENTION_NOT_POSSIBLE || - retVal == FPGA_ERR_DRAM_DATA_RETENTION_FAILED || - retVal == FPGA_ERR_DRAM_DATA_RETENTION_SETUP_FAILED) { - std::cout << "INFO: Could not load AFI for data retention, code: " << retVal - << " - Loading in classic mode." << std::endl; - retVal = fpga_mgmt_load_local_image(mBoardNumber, afi_id); - } - // check retVal from image load - if (retVal) { - std::cout << "Failed to load AFI, error: " << retVal << std::endl; - return -retVal; - } - retVal = sleepUntilLoaded( std::string(afi_id) ); - if (!retVal) { - drm_xocl_axlf axlf_obj = { reinterpret_cast(const_cast(buffer)) }; - retVal = ioctl(mUserHandle, DRM_IOCTL_XOCL_READ_AXLF, &axlf_obj); - if (retVal) { - std::cout << "IOCTL DRM_IOCTL_XOCL_READ_AXLF Failed: " << retVal << std::endl; - } else { - std::cout << "AFI load complete." << std::endl; - } - } - } - return retVal; - } else { - char* afi_id = get_afi_from_xclBin(buffer); - return fpga_mgmt_load_local_image(mBoardNumber, afi_id); - } -#endif - } - - /* Accessing F1 FPGA memory space (i.e. OpenCL Global Memory) is mapped through AppPF BAR4 - * all offsets are relative to the base address available in AppPF BAR4 - * SDAcell XCL_ADDR_SPACE_DEVICE_RAM enum maps to AwsXcl::ocl_global_mem_bar, which is the - * handle for AppPF BAR4 - */ - size_t AwsXcl::xclReadModifyWrite(uint64_t offset, const void *hostBuf, size_t size) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " - << offset << ", " << hostBuf << ", " << size << std::endl; - } -#if GCC_VERSION >= 40800 - alignas(DDR_BUFFER_ALIGNMENT) char buffer[DDR_BUFFER_ALIGNMENT]; -#else - AlignedAllocator alignedBuffer(DDR_BUFFER_ALIGNMENT, DDR_BUFFER_ALIGNMENT); - char* buffer = alignedBuffer.getBuffer(); -#endif - - const size_t mod_size = offset % DDR_BUFFER_ALIGNMENT; - // Read back one full aligned block starting from preceding aligned address - const uint64_t mod_offset = offset - mod_size; - if (xclRead(XCL_ADDR_SPACE_DEVICE_RAM, mod_offset, buffer, DDR_BUFFER_ALIGNMENT) != DDR_BUFFER_ALIGNMENT) - return -1; - - // Update the local copy of buffer with user requested data - const size_t copy_size = (size + mod_size > DDR_BUFFER_ALIGNMENT) ? DDR_BUFFER_ALIGNMENT - mod_size : size; - std::memcpy(buffer + mod_size, hostBuf, copy_size); - - // Write back the updated aligned block - if (xclWrite(XCL_ADDR_SPACE_DEVICE_RAM, mod_offset, buffer, DDR_BUFFER_ALIGNMENT) != DDR_BUFFER_ALIGNMENT) - return -1; - - // Write any remaining blocks over DDR_BUFFER_ALIGNMENT size - if (size + mod_size > DDR_BUFFER_ALIGNMENT) { - size_t write_size = xclWrite(XCL_ADDR_SPACE_DEVICE_RAM, mod_offset + DDR_BUFFER_ALIGNMENT, - (const char *)hostBuf + copy_size, size - copy_size); - if (write_size != (size - copy_size)) - return -1; - } - return size; - } - - /* Accessing F1 FPGA memory space mapped through AppPF PCIe BARs - * space = XCL_ADDR_SPACE_DEVICE_RAM maps to AppPF PCIe BAR4, (sh_cl_dma_pcis_ bus), with AwsXcl::ocl_global_mem_bar as handle - * space = XCL_ADDR_KERNEL_CTRL maps to AppPF PCIe BAR0 (sh_cl_ocl bus), with AwsXcl::ocl_kernel_bar as handle - * all offsets are relative to the base address available in AppPF - */ - size_t AwsXcl::xclWrite(xclAddressSpace space, uint64_t offset, const void *hostBuf, size_t size) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << space << ", " - << offset << ", " << hostBuf << ", " << size << std::endl; - } - - if (!mLocked) - return -1; - - switch (space) { - - /* Current release now includes performance monitors */ - case XCL_ADDR_SPACE_DEVICE_PERFMON: - { -#ifdef INTERNAL_TESTING - if (pcieBarWrite(ACCELERATOR_BAR, offset, hostBuf, size) == 0) { - return size; - } -#else - if (pcieBarWrite(APP_PF_BAR0, offset, hostBuf, size) == 0) { - return size; - } -#endif - return -1; - } - case XCL_ADDR_KERNEL_CTRL: - { - if (mLogStream.is_open()) { - const unsigned *reg = static_cast(hostBuf); - size_t regSize = size / 4; - if (regSize > 32) - regSize = 32; - for (unsigned i = 0; i < regSize; i++) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << space << ", 0x" - << std::hex << offset + i << std::dec << ", 0x" << std::hex << reg[i] << std::dec << std::endl; - - } - } -#ifdef INTERNAL_TESTING - if (pcieBarWrite(ACCELERATOR_BAR, offset, hostBuf, size) == 0) { -#else - if (pcieBarWrite(APP_PF_BAR0, offset, hostBuf, size) == 0) { - -#endif - return size; - } - return -1; - } - default: - { - return -1; - } - } - } - - - size_t AwsXcl::xclRead(xclAddressSpace space, uint64_t offset, void *hostBuf, size_t size) { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << space << ", " - << offset << ", " << hostBuf << ", " << size << std::endl; - } - - switch (space) { - case XCL_ADDR_SPACE_DEVICE_PERFMON: - { -#ifdef INTERNAL_TESTING - if (pcieBarRead(ACCELERATOR_BAR, offset, hostBuf, size) == 0) { - return size; - } -#else - if (pcieBarRead(APP_PF_BAR0, offset, hostBuf, size) == 0) { - return size; - } -#endif - return -1; - } - case XCL_ADDR_KERNEL_CTRL: - { -#ifdef INTERNAL_TESTING - int result = pcieBarRead(ACCELERATOR_BAR, offset, hostBuf, size); -#else - int result = pcieBarRead(APP_PF_BAR0, offset, hostBuf, size); -#endif - if (mLogStream.is_open()) { - const unsigned *reg = static_cast(hostBuf); - size_t regSize = size / 4; - if (regSize > 4) - regSize = 4; - for (unsigned i = 0; i < regSize; i++) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << space << ", 0x" - << std::hex << offset + i << std::dec << ", 0x" << std::hex << reg[i] << std::dec << std::endl; - } - } - return !result ? size : 0; - } - default: - { - return -1; - } - } - } - - uint64_t AwsXcl::xclAllocDeviceBuffer(size_t size) - { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << size << std::endl; - } - - uint64_t result = mNullAddr; - unsigned boHandle = xclAllocBO(size, XCL_BO_DEVICE_RAM, 0x0); - if (boHandle == mNullBO) - return result; - - drm_xocl_info_bo boInfo = {boHandle, 0, 0, 0}; - if (ioctl(mUserHandle, DRM_IOCTL_XOCL_INFO_BO, &boInfo)) - return result; - - void *hbuf = xclMapBO(boHandle, true); - if (hbuf == MAP_FAILED) { - xclFreeBO(boHandle); - return mNullAddr; - } - mLegacyAddressTable.insert(boInfo.paddr, size, std::make_pair(boHandle, (char *)hbuf)); - return boInfo.paddr; - } - - uint64_t AwsXcl::xclAllocDeviceBuffer2(size_t size, xclMemoryDomains domain, unsigned flags) - { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << size << ", " - << domain << ", " << flags << std::endl; - } - - uint64_t result = mNullAddr; - if (domain != XCL_MEM_DEVICE_RAM) - return result; - - unsigned ddr = 1; - ddr <<= flags; - unsigned boHandle = xclAllocBO(size, XCL_BO_DEVICE_RAM, ddr); - if (boHandle == mNullBO) - return result; - - drm_xocl_info_bo boInfo = {boHandle, 0, 0, 0}; - if (ioctl(mUserHandle, DRM_IOCTL_XOCL_INFO_BO, &boInfo)) - return result; - - void *hbuf = xclMapBO(boHandle, true); - if (hbuf == MAP_FAILED) { - xclFreeBO(boHandle); - return mNullAddr; - } - mLegacyAddressTable.insert(boInfo.paddr, size, std::make_pair(boHandle, (char *)hbuf)); - return boInfo.paddr; - } - - void AwsXcl::xclFreeDeviceBuffer(uint64_t buf) - { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << buf << std::endl; - } - - std::pair bo = mLegacyAddressTable.erase(buf); - drm_xocl_info_bo boInfo = {bo.first, 0, 0, 0}; - if (!ioctl(mUserHandle, DRM_IOCTL_XOCL_INFO_BO, &boInfo)) { - munmap(bo.second, boInfo.size); - } - xclFreeBO(bo.first); - } - - - size_t AwsXcl::xclCopyBufferHost2Device(uint64_t dest, const void *src, size_t size, size_t seek) - { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << dest << ", " - << src << ", " << size << ", " << seek << std::endl; - } - - std::pair bo = mLegacyAddressTable.find(dest); - std::memcpy(bo.second + seek, src, size); - int result = xclSyncBO(bo.first, XCL_BO_SYNC_BO_TO_DEVICE, size, seek); - if (result) - return result; - return size; - } - - - size_t AwsXcl::xclCopyBufferDevice2Host(void *dest, uint64_t src, size_t size, size_t skip) - { - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << dest << ", " - << src << ", " << size << ", " << skip << std::endl; - } - - std::pair bo = mLegacyAddressTable.find(src); - int result = xclSyncBO(bo.first, XCL_BO_SYNC_BO_FROM_DEVICE, size, skip); - if (result) - return result; - std::memcpy(dest, bo.second + skip, size); - return size; - } - - - AwsXcl *AwsXcl::handleCheck(void *handle) { - // Sanity checks - if (!handle) - return 0; - if (*(unsigned *)handle != TAG) - return 0; - if (!((AwsXcl *)handle)->isGood()) { - return 0; - } - - return (AwsXcl *)handle; - } - - unsigned AwsXcl::xclProbe() { - std::lock_guard lock(awsbwhal::deviceListMutex); - if(xcldev::pci_device_scanner::device_list.size() == 0) { - xcldev::pci_device_scanner devices; - devices.scan(true); - } - - unsigned i = 0; -#ifdef INTERNAL_TESTING - char file_name_buf[128]; - for (i = 0; i < 16; i++) { - std::sprintf((char *)&file_name_buf, "/dev/awsmgmt%d", i); - int fd = open(file_name_buf, O_RDWR); - if (fd < 0) { - return i; - } - close(fd); - } - if (i != xcldev::pci_device_scanner::device_list.size()) { - std::cout << "ERROR xclProbe: Num of FPGA userPF device do not match num of mgmtPF devices" << std::endl; - std::cout << "ERROR xclProbe: Num of userPF, mgmtPF devices = " << std::dec << xcldev::pci_device_scanner::device_list.size() << std::dec << i << std::endl; - return 0; - } -#endif - i = xcldev::pci_device_scanner::device_list.size(); - -#ifndef INTERNAL_TESTING - std::cout << "xclProbe found " << std::dec << i << " FPGA slots with xocl driver running" << std::endl; -#else - std::cout << "xclProbe found " << std::dec << i << " FPGA slots with awsmgmt & xocl driver running" << std::endl; -#endif - return i; - } - - AwsXcl::~AwsXcl() - { -#ifdef INTERNAL_TESTING - if (mUserMap != MAP_FAILED) { - munmap(mUserMap, MMAP_SIZE_USER); - } - if (mUserHandle > 0) { - close(mUserHandle); - } - if (mMgtHandle > 0) - close(mMgtHandle); -#else -//# error "INTERNAL_TESTING macro disabled. AMZN code goes here. " - if (ocl_kernel_bar >=0) - fpga_pci_detach(ocl_kernel_bar); - if (ocl_global_mem_bar>=0) - fpga_pci_detach(ocl_global_mem_bar); - if (sda_mgmt_bar>=0) - fpga_pci_detach(sda_mgmt_bar); - - ocl_kernel_bar = -1; - ocl_global_mem_bar = -1; - sda_mgmt_bar = -1; - -#endif - - if (mLogStream.is_open()) { - mLogStream << __func__ << ", " << std::this_thread::get_id() << std::endl; - mLogStream.close(); - } - } - - AwsXcl::AwsXcl(unsigned index, const char *logfileName, - xclVerbosityLevel verbosity) : mTag(TAG), mBoardNumber(index), - maxDMASize(0xfa0000), - mLocked(false), - mOffsets{0x0, 0x0, 0x0, 0x0}, - mOclRegionProfilingNumberSlots(XPAR_AXI_PERF_MON_2_NUMBER_SLOTS) - { -#ifndef INTERNAL_TESTING - loadDefaultAfiIfCleared(); -#endif - const std::string devName = "/dev/dri/renderD" + std::to_string(xcldev::pci_device_scanner::device_list[mBoardNumber].user_instance); -#ifndef INTERNAL_TESTING - mUserHandle = open(devName.c_str(), O_RDWR); - if(mUserHandle <= 0) { - std::cout << "WARNING: AwsXcl - Cannot open userPF: " << devName << std::endl; - } -#endif - -#ifdef INTERNAL_TESTING - if(mUserHandle > 0) { - mUserMap = (char *)mmap(0, MMAP_SIZE_USER, PROT_READ | PROT_WRITE, MAP_SHARED, mUserHandle, 0); - if (mUserMap == MAP_FAILED) { - std::cout << "Map failed: " << devName << std::endl; - close(mUserHandle); - mUserHandle = -1; - } - } - - char file_name_buf[128]; - std::fill(&file_name_buf[0], &file_name_buf[0] + 128, 0); - std::sprintf((char *)&file_name_buf, "/dev/awsmgmt%d", mBoardNumber); - mMgtHandle = open(file_name_buf, O_RDWR | O_SYNC); - if(mMgtHandle > 0) { - if (xclGetDeviceInfo2(&mDeviceInfo)) { - close(mMgtHandle); - mMgtHandle = -1; - } - } else { - std::cout << "Cannot open mgmtPF: " << devName << std::endl; - } -#else - int slot_id = mBoardNumber; - ocl_kernel_bar = -1; - ocl_global_mem_bar = -1; - sda_mgmt_bar = -1; - - if (xclGetDeviceInfo2(&mDeviceInfo)) { - std::cout << "ERROR AwsXcl: DeviceInfo failed for slot# " << std::dec << slot_id << std::endl; - } else if (fpga_pci_attach(slot_id, FPGA_APP_PF, APP_PF_BAR0, 0, &ocl_kernel_bar) ) { - ocl_kernel_bar = -1; - std::cout << "ERROR AwsXcl: PCI kernel bar attach failed for slot# " << std::dec << slot_id << std::endl; - } else if (fpga_pci_attach(slot_id, FPGA_APP_PF, APP_PF_BAR4, 0, &ocl_global_mem_bar) ) { - fpga_pci_detach(ocl_kernel_bar); - ocl_kernel_bar = -1; - ocl_global_mem_bar = -1; - sda_mgmt_bar = -1; - std::cout << "ERROR AwsXcl: PCI global bar attach failed for slot# " << std::dec << slot_id << std::endl; - } else if (fpga_pci_attach(slot_id, FPGA_MGMT_PF, MGMT_PF_BAR4, 0, &sda_mgmt_bar) ) { - fpga_pci_detach(ocl_kernel_bar); - fpga_pci_detach(ocl_global_mem_bar); - ocl_kernel_bar = -1; - ocl_global_mem_bar = -1; - sda_mgmt_bar = -1; - std::cout << "ERROR AwsXcl: PCI mgmt bar attach failed for slot# " << std::dec << slot_id << std::endl; - } -#endif - - // - // Profiling - defaults - // Class-level defaults: mIsDebugIpLayoutRead = mIsDeviceProfiling = false - mDevUserName = xcldev::pci_device_scanner::device_list[mBoardNumber].user_name; - mMemoryProfilingNumberSlots = 0; - mPerfMonFifoCtrlBaseAddress = 0x00; - mPerfMonFifoReadBaseAddress = 0x00; - // - // Profiling - defaults - // Class-level defaults: mIsDebugIpLayoutRead = mIsDeviceProfiling = false - mDevUserName = xcldev::pci_device_scanner::device_list[mBoardNumber].user_name; - mMemoryProfilingNumberSlots = 0; - mPerfMonFifoCtrlBaseAddress = 0x00; - mPerfMonFifoReadBaseAddress = 0x00; - - // - // Profiling - defaults - // Class-level defaults: mIsDebugIpLayoutRead = mIsDeviceProfiling = false - mDevUserName = xcldev::pci_device_scanner::device_list[mBoardNumber].user_name; - mMemoryProfilingNumberSlots = 0; - mPerfMonFifoCtrlBaseAddress = 0x00; - mPerfMonFifoReadBaseAddress = 0x00; - } - - bool AwsXcl::isGood() const { -#ifdef INTERNAL_TESTING - if (mUserHandle < 0) { - std::cout << "AwsXcl: Bad handle. No userPF Handle" << std::endl; - return false; - } - if (mMgtHandle < 0) { - std::cout << "AwsXcl: Bad handle. No mgmtPF Handle" << std::endl; - return false; - } -#else - if (ocl_kernel_bar < 0) { - std::cout << "WARNING: AwsXcl isGood: kernel, global & mgmt bar are: " << std::hex << ocl_kernel_bar << ", " << std::hex << ocl_global_mem_bar << ", " << sda_mgmt_bar << std::endl; - return false; - } - if (ocl_global_mem_bar < 0) { - std::cout << "WARNING: AwsXcl isGood: kernel, global & mgmt bar are: " << std::hex << ocl_kernel_bar << ", " << std::hex << ocl_global_mem_bar << ", " << sda_mgmt_bar << std::endl; - return false; - } - if (sda_mgmt_bar < 0) { - std::cout << "WARNING: AwsXcl isGood: kernel, global & mgmt bar are: " << std::hex << ocl_kernel_bar << ", " << std::hex << ocl_global_mem_bar << ", " << sda_mgmt_bar << std::endl; - return false; - } - if (mUserHandle <= 0) { - std::cout << "WARNING: AwsXcl isGood: invalid user handle." << std::endl; - return false; - } -#endif - return true; - } - - - int AwsXcl::pcieBarRead(int bar_num, unsigned long long offset, void* buffer, unsigned long long length) { - char *qBuf = (char *)buffer; - switch (bar_num) { -#ifdef INTERNAL_TESTING - const char *mem = 0; - case 0: - { - if ((length + offset) > MMAP_SIZE_USER) { - return -1; - } - mem = mUserMap; -#else - case APP_PF_BAR0: - { -#endif - break; - } - default: - { - return -1; - } - } - - while (length >= 4) { -#ifdef INTERNAL_TESTING - *(unsigned *)qBuf = *(unsigned *)(mem + offset); -#else - fpga_pci_peek(ocl_kernel_bar, (uint64_t)offset,(uint32_t*)qBuf); -#endif - offset += 4; - qBuf += 4; - length -= 4; - } - while (length) { -#ifdef INTERNAL_TESTING - *qBuf = *(mem + offset); -#else - - // TODO - add support for sub 4-byte read in AWS platform -#endif - offset++; - qBuf++; - length--; - } - -// std::memcpy(buffer, mem + offset, length); - return 0; - } - - int AwsXcl::pcieBarWrite(int bar_num, unsigned long long offset, const void* buffer, unsigned long long length) { - char *qBuf = (char *)buffer; - switch (bar_num) { -#ifdef INTERNAL_TESTING - char *mem = 0; - case 0: - { - if ((length + offset) > MMAP_SIZE_USER) { - return -1; - } - mem = mUserMap; -#else - case APP_PF_BAR0: - { -#endif - break; - } - default: - { - return -1; - } - } - - while (length >= 4) { -#ifdef INTERNAL_TESTING - *(unsigned *)(mem + offset) = *(unsigned *)qBuf; -#else - fpga_pci_poke(ocl_kernel_bar, uint64_t (offset), *((uint32_t*) qBuf)); -#endif - offset += 4; - qBuf += 4; - length -= 4; - } - while (length) { -#ifdef INTERNEL_TESTING - *(mem + offset) = *qBuf; -#else - std::cout << "xclWrite - unsupported write with length not multiple of 4-bytes" << std::endl; - -#endif - offset++; - qBuf++; - length--; - } - -// std::memcpy(mem + offset, buffer, length); - return 0; - } - - bool AwsXcl::zeroOutDDR() - { - // Zero out the FPGA external DRAM Content so memory controller - // will not complain about ECC error from memory regions not - // initialized before - // In AWS F1 FPGA, the DRAM is clear before loading new AFI - // hence this API is redundant and will return false to - // make sure developers dont assume it works - - // static const unsigned long long BLOCK_SIZE = 0x4000000; -// void *buf = 0; -// if (posix_memalign(&buf, DDR_BUFFER_ALIGNMENT, BLOCK_SIZE)) -// return false; -// memset(buf, 0, BLOCK_SIZE); -// mDataMover->pset64(buf, BLOCK_SIZE, 0, mDeviceInfo.mDDRSize/BLOCK_SIZE); -// free(buf); - return false; - } - - /* Locks a given FPGA Slot - * By levering the available lock infrastrucutre for the DMA - * Driver associated with the given FPGA slot - */ - bool AwsXcl::xclLockDevice() - { -#ifdef INTERNAL_TESTING -#else -// FIXME: do we need to flock the ocl_kernel interface as well ? -// -#endif - mLocked = true; - -// return zeroOutDDR(); - return true; - } - - std::string AwsXcl::getDSAName(unsigned short deviceId, unsigned short subsystemId) - { - std::string dsa("xilinx_aws-vu9p-f1-04261818_dynamic_5_0"); - return dsa; - } - - int AwsXcl::xclGetDeviceInfo2(xclDeviceInfo2 *info) - { - std::memset(info, 0, sizeof(xclDeviceInfo2)); - info->mMagic = 0X586C0C6C; - info->mHALMajorVersion = XCLHAL_MAJOR_VER; - info->mHALMajorVersion = XCLHAL_MINOR_VER; - info->mMinTransferSize = DDR_BUFFER_ALIGNMENT; - info->mDMAThreads = 4;//AWS has four threads. Others have only two threads - -#ifdef INTERNAL_TESTING - /* Sarab disabling xdma ioctl - xdma_ioc_info obj = {{0X586C0C6C, XDMA_IOCINFO}}; - /--* Calling the underlying DMA driver to extract - * DMA specific configuration - * A non-zero value reprent at error - *--/ - int ret = ioctl(mUserHandle, XDMA_IOCINFO, &obj); - // Log the return value for further debug - if (ret) - return ret; - info->mVendorId = obj.vendor; - info->mDeviceId = obj.device; - info->mSubsystemId = obj.subsystem_device; - info->mSubsystemVendorId = obj.subsystem_vendor; - info->mDeviceVersion = obj.subsystem_device & 0x00ff; - */ - awsmgmt_ioc_info mgmt_info_obj; - int ret = ioctl(mMgtHandle, AWSMGMT_IOCINFO, &mgmt_info_obj); - if (ret) - return ret; - - info->mVendorId = mgmt_info_obj.vendor; - info->mDeviceId = mgmt_info_obj.device; - info->mSubsystemId = mgmt_info_obj.subsystem_device; - info->mSubsystemVendorId = mgmt_info_obj.subsystem_vendor; - info->mDeviceVersion = mgmt_info_obj.subsystem_device & 0x00ff; - info->mPCIeLinkWidth = mgmt_info_obj.pcie_link_width; - info->mPCIeLinkSpeed = mgmt_info_obj.pcie_link_speed; - for (int i = 0; i < AWSMGMT_NUM_SUPPORTED_CLOCKS; ++i) { - info->mOCLFrequency[i] = mgmt_info_obj.ocl_frequency[i]; - } - info->mMigCalib = true; - for (int i = 0; i < 4; i++) { - info->mMigCalib = info->mMigCalib && mgmt_info_obj.mig_calibration[i]; - } -#else - struct fpga_slot_spec slot_info; - //fpga_pci_get_slot_spec(mBoardNumber,FPGA_APP_PF, &slot_info); - fpga_pci_get_slot_spec(mBoardNumber, &slot_info); - info->mVendorId = slot_info.map[0].vendor_id; - info->mDeviceId = slot_info.map[0].device_id; - // FIXME - update next 3 variables - info->mSubsystemId = slot_info.map[0].subsystem_device_id; - info->mSubsystemVendorId = slot_info.map[0].subsystem_vendor_id; - info->mDeviceVersion = 0; - info->mPCIeLinkWidth = 16; - info->mPCIeLinkSpeed = 8000; - fpga_mgmt_image_info imageInfo; - fpga_mgmt_describe_local_image( mBoardNumber, &imageInfo, 0 ); - for (int i = 0; i < AWSMGMT_NUM_SUPPORTED_CLOCKS; ++i) { - info->mOCLFrequency[i] = imageInfo.metrics.clocks[i].frequency[0] / 1000000; - } - info->mMigCalib = true; -#endif - - // F1 has 16 GiB per channel - info->mDDRSize = 0x400000000 * 4; - info->mDataAlignment = DDR_BUFFER_ALIGNMENT; - info->mNumClocks = AWSMGMT_NUM_ACTUAL_CLOCKS; - // Number of available channels - // TODO: add support for other FPGA configurations with less - // than 4 DRAM channels - info->mDDRBankCount = 4; - - const std::string deviceName = getDSAName(info->mDeviceId, info->mSubsystemId); - if (mLogStream.is_open()) - mLogStream << __func__ << ", " << std::this_thread::get_id() << ", " << deviceName << std::endl; - - std::size_t length = deviceName.copy(info->mName, deviceName.length(),0); - info->mName[length] = '\0'; - - if (mLogStream.is_open()) { - mLogStream << __func__ << ": name=" << deviceName << ", version=0x" << std::hex << info->mDeviceVersion - << ", clock freq=" << std::dec << info->mOCLFrequency[0] - << ", clock freq 2=" << std::dec << info->mOCLFrequency[1] << std::endl; - } - - info->mOnChipTemp = 25; - info->mFanTemp = 0; - info->mVInt = 0.9; - info->mVAux = 0.9; - info->mVBram = 0.9; - return 0; - } - - int AwsXcl::resetDevice(xclResetKind kind) { - - // Call a new IOCTL to just reset the OCL region -// if (kind == XCL_RESET_FULL) { -// xdma_ioc_base obj = {0X586C0C6C, XDMA_IOCHOTRESET}; -// return ioctl(mUserHandle, XDMA_IOCHOTRESET, &obj); -// } -// else if (kind == XCL_RESET_KERNEL) { -// xdma_ioc_base obj = {0X586C0C6C, XDMA_IOCOCLRESET}; -// return ioctl(mUserHandle, XDMA_IOCOCLRESET, &obj); -// } -// return -EINVAL; - - // AWS FIXME - add reset - return 0; - } - - int AwsXcl::xclReClock2(unsigned short region, const unsigned short *targetFreqMHz) - { - #ifdef INTERNAL_TESTING - awsmgmt_ioc_freqscaling obj = {0, targetFreqMHz[0], targetFreqMHz[1], targetFreqMHz[2], 0}; - return ioctl(mMgtHandle, AWSMGMT_IOCFREQSCALING, &obj); - #else -// # error "INTERNAL_TESTING macro disabled. AMZN code goes here. " -// # This API is not supported in AWS, the frequencies are set per AFI - return 0; - #endif - } - - ssize_t AwsXcl::xclUnmgdPwrite(unsigned flags, const void *buf, size_t count, uint64_t offset) - { - if (flags) - return -EINVAL; - drm_xocl_pwrite_unmgd unmgd = {0, 0, offset, count, reinterpret_cast(buf)}; - return ioctl(mUserHandle, DRM_IOCTL_XOCL_PWRITE_UNMGD, &unmgd); - } - - ssize_t AwsXcl::xclUnmgdPread(unsigned flags, void *buf, size_t count, uint64_t offset) - { - if (flags) - return -EINVAL; - drm_xocl_pread_unmgd unmgd = {0, 0, offset, count, reinterpret_cast(buf)}; - return ioctl(mUserHandle, DRM_IOCTL_XOCL_PREAD_UNMGD, &unmgd); - } - - int AwsXcl::xclExportBO(unsigned int boHandle) - { - drm_prime_handle info = {boHandle, 0, -1}; - int result = ioctl(mUserHandle, DRM_IOCTL_PRIME_HANDLE_TO_FD, &info); - return !result ? info.fd : result; - } - - unsigned int AwsXcl::xclImportBO(int fd, unsigned flags) - { - - /*Sarab - drm_xocl_userptr_bo user = {reinterpret_cast(userptr), size, mNullBO, flags}; - int result = ioctl(mUserHandle, DRM_IOCTL_XOCL_USERPTR_BO, &user); - - */ - - - drm_prime_handle info = {mNullBO, flags, fd}; - int result = ioctl(mUserHandle, DRM_IOCTL_PRIME_FD_TO_HANDLE, &info); - if (result) { - std::cout << __func__ << " ERROR: FD to handle IOCTL failed" << std::endl; - } - return !result ? info.handle : mNullBO; - } - - int AwsXcl::xclGetBOProperties(unsigned int boHandle, xclBOProperties *properties) - { - drm_xocl_info_bo info = {boHandle, 0, 0, 0}; - int result = ioctl(mUserHandle, DRM_IOCTL_XOCL_INFO_BO, &info); - properties->handle = info.handle; - properties->flags = info.flags; - properties->size = info.size; - properties->paddr = info.paddr; - properties->domain = XCL_BO_DEVICE_RAM; // currently all BO domains are XCL_BO_DEVICE_RAM - return result ? mNullBO : 0; - } - - bool AwsXcl::xclUnlockDevice() - { - flock(mUserHandle, LOCK_UN); - mLocked = false; - return true; - } - - // Assume that the memory is always - // created for the device ddr for now. Ignoring the flags as well. - unsigned int AwsXcl::xclAllocBO(size_t size, xclBOKind domain, unsigned flags) - { - drm_xocl_create_bo info = {size, mNullBO, flags}; - int result = ioctl(mUserHandle, DRM_IOCTL_XOCL_CREATE_BO, &info); - if (result) { - std::cout << __func__ << " ERROR: AllocBO IOCTL failed" << std::endl; - } - return result ? mNullBO : info.handle; - } - - unsigned int AwsXcl::xclAllocUserPtrBO(void *userptr, size_t size, unsigned flags) - { - drm_xocl_userptr_bo user = {reinterpret_cast(userptr), size, mNullBO, flags}; - int result = ioctl(mUserHandle, DRM_IOCTL_XOCL_USERPTR_BO, &user); - return result ? mNullBO : user.handle; - } - - void AwsXcl::xclFreeBO(unsigned int boHandle) - { - drm_gem_close closeInfo = {boHandle, 0}; - ioctl(mUserHandle, DRM_IOCTL_GEM_CLOSE, &closeInfo); - } - - int AwsXcl::xclWriteBO(unsigned int boHandle, const void *src, size_t size, size_t seek) - { - drm_xocl_pwrite_bo pwriteInfo = { boHandle, 0, seek, size, reinterpret_cast(src) }; - return ioctl(mUserHandle, DRM_IOCTL_XOCL_PWRITE_BO, &pwriteInfo); - } - - int AwsXcl::xclReadBO(unsigned int boHandle, void *dst, size_t size, size_t skip) - { - drm_xocl_pread_bo preadInfo = { boHandle, 0, skip, size, reinterpret_cast(dst) }; - return ioctl(mUserHandle, DRM_IOCTL_XOCL_PREAD_BO, &preadInfo); - } - - void *AwsXcl::xclMapBO(unsigned int boHandle, bool write) - { - drm_xocl_info_bo info = { boHandle, 0, 0 }; - int result = ioctl(mUserHandle, DRM_IOCTL_XOCL_INFO_BO, &info); - if (result) - return nullptr; - - drm_xocl_map_bo mapInfo = { boHandle, 0, 0 }; - result = ioctl(mUserHandle, DRM_IOCTL_XOCL_MAP_BO, &mapInfo); - if (result) - return nullptr; - - return mmap(0, info.size, (write ? (PROT_READ|PROT_WRITE) : PROT_READ), - MAP_SHARED, mUserHandle, mapInfo.offset); - } - - int AwsXcl::xclSyncBO(unsigned int boHandle, xclBOSyncDirection dir, - size_t size, size_t offset) - { - drm_xocl_sync_bo_dir drm_dir = (dir == XCL_BO_SYNC_BO_TO_DEVICE) ? - DRM_XOCL_SYNC_BO_TO_DEVICE : - DRM_XOCL_SYNC_BO_FROM_DEVICE; - drm_xocl_sync_bo syncInfo = {boHandle, 0, size, offset, drm_dir}; - return ioctl(mUserHandle, DRM_IOCTL_XOCL_SYNC_BO, &syncInfo); - } - -#ifndef INTERNAL_TESTING - int AwsXcl::loadDefaultAfiIfCleared( void ) - { - int array_len = 16; - fpga_slot_spec spec_array[ array_len ]; - std::memset( spec_array, mBoardNumber, sizeof(fpga_slot_spec) * array_len ); - fpga_pci_get_all_slot_specs( spec_array, array_len ); - if( spec_array[mBoardNumber].map[FPGA_APP_PF].device_id == AWS_UserPF_DEVICE_ID ) { - std::string agfi = DEFAULT_GLOBAL_AFI; - fpga_mgmt_load_local_image( mBoardNumber, const_cast(agfi.c_str()) ); - if( sleepUntilLoaded( agfi ) ) { - std::cout << "ERROR: Sleep until load failed." << std::endl; - return -1; - } - fpga_pci_rescan_slot_app_pfs( mBoardNumber ); - } - return 0; - } - - int AwsXcl::sleepUntilLoaded( const std::string afi ) - { - for( int i = 0; i < 20; i++ ) { - std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); - fpga_mgmt_image_info info; - std::memset( &info, 0, sizeof(struct fpga_mgmt_image_info) ); - int result = fpga_mgmt_describe_local_image( mBoardNumber, &info, 0 ); - if( result ) { - std::cout << "ERROR: Load image failed." << std::endl; - return 1; - } - if( (info.status == FPGA_STATUS_LOADED) && !std::strcmp(info.ids.afi_id, const_cast(afi.c_str())) ) { - break; - } - } - return 0; - } - - int AwsXcl::checkAndSkipReload( char *afi_id, fpga_mgmt_image_info *orig_info ) - { - if( (orig_info->status == FPGA_STATUS_LOADED) && !std::strcmp(orig_info->ids.afi_id, afi_id) ) { - std::cout << "This AFI already loaded. Skip reload!" << std::endl; - int result = 0; - //existing afi matched. - uint16_t status = 0; - result = fpga_mgmt_get_vDIP_status(mBoardNumber, &status); - if(result) { - printf("Error: can not get virtual DIP Switch state\n"); - return result; - } - //Set bit 0 to 1 - status |= (1 << 0); - result = fpga_mgmt_set_vDIP(mBoardNumber, status); - if(result) { - printf("Error trying to set virtual DIP Switch \n"); - return result; - } - std::this_thread::sleep_for(std::chrono::microseconds(250)); - //pulse the changes in. - result = fpga_mgmt_get_vDIP_status(mBoardNumber, &status); - if(result) { - printf("Error: can not get virtual DIP Switch state\n"); - return result; - } - //Set bit 0 to 0 - status &= ~(1 << 0); - result = fpga_mgmt_set_vDIP(mBoardNumber, status); - if(result) { - printf("Error trying to set virtual DIP Switch \n"); - return result; - } - std::this_thread::sleep_for(std::chrono::microseconds(250)); - - printf("Successfully skipped reloading of local image.\n"); - return result; - } else { - std::cout << "AFI not yet loaded, proceed to download." << std::endl; - return 1; - } - } -#endif -} /* end namespace awsbmhal */ - -xclDeviceHandle xclOpen(unsigned deviceIndex, const char *logFileName, xclVerbosityLevel level) -{ - if(xcldev::pci_device_scanner::device_list.size() <= deviceIndex) { - printf("Cannot find index %d \n", deviceIndex); - return nullptr; - } - - awsbwhal::AwsXcl *handle = new awsbwhal::AwsXcl(deviceIndex, logFileName, level); - if (!awsbwhal::AwsXcl::handleCheck(handle)) { - printf("WARNING: xclOpen Handle check failed\n"); - delete handle; - handle = nullptr; -#ifndef INTERNAL_TESTING - /* workaround necessary to load a default afi and program with xclbin when device is in a cleared state */ - xcldev::pci_device_scanner rescan; - rescan.clear_device_list(); - rescan.scan( true ); - for (unsigned int i=0; i(handle); -} - -void xclClose(xclDeviceHandle handle) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (drv) - delete drv; -} - - -int xclGetDeviceInfo2(xclDeviceHandle handle, xclDeviceInfo2 *info) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclGetDeviceInfo2(info); -} - -int xclLoadBitstream(xclDeviceHandle handle, const char *xclBinFileName) -{ - return -ENOSYS; -} - -int xclLoadXclBin(xclDeviceHandle handle, const xclBin *buffer) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclLoadXclBin(buffer); -} - -size_t xclWrite(xclDeviceHandle handle, xclAddressSpace space, uint64_t offset, const void *hostBuf, size_t size) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclWrite(space, offset, hostBuf, size); -} - -size_t xclRead(xclDeviceHandle handle, xclAddressSpace space, uint64_t offset, void *hostBuf, size_t size) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclRead(space, offset, hostBuf, size); -} - - -uint64_t xclAllocDeviceBuffer(xclDeviceHandle handle, size_t size) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclAllocDeviceBuffer(size); -} - - -uint64_t xclAllocDeviceBuffer2(xclDeviceHandle handle, size_t size, xclMemoryDomains domain, - unsigned flags) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclAllocDeviceBuffer2(size, domain, flags); -} - - -void xclFreeDeviceBuffer(xclDeviceHandle handle, uint64_t buf) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return; - return drv->xclFreeDeviceBuffer(buf); -} - - -size_t xclCopyBufferHost2Device(xclDeviceHandle handle, uint64_t dest, const void *src, size_t size, size_t seek) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclCopyBufferHost2Device(dest, src, size, seek); -} - - -size_t xclCopyBufferDevice2Host(xclDeviceHandle handle, void *dest, uint64_t src, size_t size, size_t skip) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclCopyBufferDevice2Host(dest, src, size, skip); -} - - -//This will be deprecated. -int xclUpgradeFirmware(xclDeviceHandle handle, const char *fileName) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return xclUpgradeFirmware2(handle, fileName, 0); -} - -int xclUpgradeFirmware2(xclDeviceHandle handle, const char *fileName1, const char* fileName2) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return -ENOSYS; -} - -/* - * xclBootFPGA - * - * Sequence: - * 1) call boot ioctl - * 2) close the device, unload the driver - * 3) remove and scan - * 4) rescan pci devices - * 5) reload the driver (done by the calling function xcldev::boot()) - * - * Return 0 on success, -1 on failure. - */ -int xclBootFPGA(xclDeviceHandle handle) -{ -// awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); -// if (!drv) -// return -1; -// return -ENOSYS; - int retVal = -1; - - //awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); -// retVal = drv->xclBootFPGA(); // boot ioctl - retVal = 0; // skip boot ioctl since this may not be possible for AWS - - if( retVal == 0 ) - { - xclClose(handle); // close the device, unload the driver - retVal = xclRemoveAndScanFPGA(); // remove and scan - } - - if( retVal == 0 ) - { - xcldev::pci_device_scanner devScanner; - devScanner.scan( true ); // rescan pci devices - } - - return retVal; -} - -int xclRemoveAndScanFPGA( void ) -{ - const std::string devPath = "/devices/"; - const std::string removePath = "/remove"; - const std::string pciPath = "/sys/bus/pci"; - const std::string rescanPath = "/rescan"; - const char *input = "1\n"; - - // remove devices "echo 1 > /sys/bus/pci/devices//remove" - for (unsigned int i = 0; i < xcldev::pci_device_scanner::device_list.size(); i++) - { - std::string dev_name_pf_user = pciPath + devPath + xcldev::pci_device_scanner::device_list[i].user_name + removePath; - std::string dev_name_pf_mgmt = pciPath + devPath + xcldev::pci_device_scanner::device_list[i].mgmt_name + removePath; - - std::ofstream userFile( dev_name_pf_user ); - if( !userFile.is_open() ) { - perror( dev_name_pf_user.c_str() ); - return errno; - } - userFile << input; - - std::ofstream mgmtFile( dev_name_pf_mgmt ); - if( !mgmtFile.is_open() ) { - perror( dev_name_pf_mgmt.c_str() ); - return errno; - } - mgmtFile << input; - } - - std::this_thread::sleep_for(std::chrono::seconds(1)); - // initiate rescan "echo 1 > /sys/bus/pci/rescan" - std::ofstream rescanFile( pciPath + rescanPath ); - if( !rescanFile.is_open() ) { - perror( std::string( pciPath + rescanPath ).c_str() ); - return errno; - } - rescanFile << input; - - return 0; -} - -unsigned xclProbe() -{ - return awsbwhal::AwsXcl::xclProbe(); -} - -int xclResetDevice(xclDeviceHandle handle, xclResetKind kind) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return -ENOSYS; -} - -int xclReClock2(xclDeviceHandle handle, unsigned short region, const unsigned short *targetFreqMHz) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclReClock2(region, targetFreqMHz); -} - - -int xclLockDevice(xclDeviceHandle handle) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return drv->xclLockDevice() ? 0 : -1; -} - -//Sarab: Added for HAL2 support with XOCL GEM Driver - -int xclExportBO(xclDeviceHandle handle, unsigned int boHandle) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - return drv ? drv->xclExportBO(boHandle) : -ENODEV; -} - - -unsigned int xclImportBO(xclDeviceHandle handle, int fd, unsigned flags) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) { - std::cout << __func__ << ", " << std::this_thread::get_id() << ", handle & XOCL Device are bad" << std::endl; - } - return drv ? drv->xclImportBO(fd, flags) : -ENODEV; -} - -ssize_t xclUnmgdPwrite(xclDeviceHandle handle, unsigned flags, const void *buf, - size_t count, uint64_t offset) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - return drv ? drv->xclUnmgdPwrite(flags, buf, count, offset) : -ENODEV; -} - -int xclGetBOProperties(xclDeviceHandle handle, unsigned int boHandle, xclBOProperties *properties) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - return drv ? drv->xclGetBOProperties(boHandle, properties) : -ENODEV; -} - -ssize_t xclUnmgdPread(xclDeviceHandle handle, unsigned flags, void *buf, - size_t count, uint64_t offset) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - return drv ? drv->xclUnmgdPread(flags, buf, count, offset) : -ENODEV; -} - -int xclUpgradeFirmwareXSpi(xclDeviceHandle handle, const char *fileName, int index) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return -ENOSYS; - //return drv->xclUpgradeFirmwareXSpi(fileName, index); Not supported by AWS -} - -int xclUnlockDevice(xclDeviceHandle handle) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) { - std::cout << "xclUnlockDevice returning -ENODEV\n"; - return -ENODEV; - } else { - return drv->xclUnlockDevice() ? 0 : 1; - } -} - -unsigned int xclAllocBO(xclDeviceHandle handle, size_t size, xclBOKind domain, unsigned flags) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - return drv ? drv->xclAllocBO(size, domain, flags) : -ENODEV; -} - -unsigned int xclAllocUserPtrBO(xclDeviceHandle handle, void *userptr, size_t size, unsigned flags) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - return drv ? drv->xclAllocUserPtrBO(userptr, size, flags) : -ENODEV; -} - -void xclFreeBO(xclDeviceHandle handle, unsigned int boHandle) { - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return; - drv->xclFreeBO(boHandle); -} - -size_t xclWriteBO(xclDeviceHandle handle, unsigned int boHandle, const void *src, size_t size, - size_t seek) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - return drv ? drv->xclWriteBO(boHandle, src, size, seek) : -ENODEV; -} - -size_t xclReadBO(xclDeviceHandle handle, unsigned int boHandle, void *dst, size_t size, - size_t skip) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - return drv ? drv->xclReadBO(boHandle, dst, size, skip) : -ENODEV; -} - -void *xclMapBO(xclDeviceHandle handle, unsigned int boHandle, bool write) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - return drv ? drv->xclMapBO(boHandle, write) : nullptr; -} - - -int xclSyncBO(xclDeviceHandle handle, unsigned int boHandle, xclBOSyncDirection dir, - size_t size, size_t offset) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - return drv ? drv->xclSyncBO(boHandle, dir, size, offset) : -ENODEV; -} - -unsigned int xclVersion () { - return 2; -} - -int xclGetErrorStatus(xclDeviceHandle handle, xclErrorStatus *info) -{ - awsbwhal::AwsXcl *drv = awsbwhal::AwsXcl::handleCheck(handle); - if (!drv) - return -1; - return -ENOSYS; - //return drv->xclGetErrorStatus(info); Not supported for AWS -} - -int xclXbsak(int argc, char *argv[]) -{ - return xcldev::xclXbsak(argc, argv); -} - diff --git a/SDAccel/userspace/src2/shim.h b/SDAccel/userspace/src2/shim.h deleted file mode 100755 index 753182fb..00000000 --- a/SDAccel/userspace/src2/shim.h +++ /dev/null @@ -1,380 +0,0 @@ -/** - * Copyright (C) 2017-2018 Xilinx, Inc - * Author: Sonal Santan - * AWS HAL Driver layered on top of kernel drivers - * - * Code copied from SDAccel XDMA based HAL driver - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -#ifndef _XDMA_SHIM_H_ -#define _XDMA_SHIM_H_ - -#include "xclhal2.h" -#include "xclperf2.h" -#include "drm.h" -#include -#include -#include -#include -#include -#include -#include - -#ifndef INTERNAL_TESTING -#include "fpga_pci.h" -#include "fpga_mgmt.h" -#endif - -// Work around GCC 4.8 + XDMA BAR implementation bugs -// With -O3 PCIe BAR read/write are not reliable hence force -O2 as max -// optimization level for pcieBarRead() and pcieBarWrite() -#if defined(__GNUC__) && defined(NDEBUG) -#define SHIM_O2 __attribute__ ((optimize("-O2"))) -#else -#define SHIM_O2 -#endif - -namespace awsbwhal { - - -struct AddresRange; - -std::ostream& operator<< (std::ostream &strm, const AddresRange &rng); - -/** - * Simple tuple struct to store non overlapping address ranges: address and size - */ -struct AddresRange : public std::pair { - // size will be zero when we are looking up an address that was passed by the user - AddresRange(uint64_t addr, size_t size = 0) : std::pair(std::make_pair(addr, size)) { - //std::cout << "CTOR(" << addr << ',' << size << ")\n"; - } - AddresRange(AddresRange && rhs) : std::pair(std::move(rhs)) { - //std::cout << "MOVE CTOR(" << rhs.first << ',' << rhs.second << ")\n"; - } - - AddresRange(const AddresRange &rhs) = delete; - AddresRange& operator=(const AddresRange &rhs) = delete; - - // Comparison operator is useful when using AddressRange as a key in std::map - // Note one operand in the comparator may have only the address without the size - // However both operands in the comparator will not have zero size - bool operator < (const AddresRange& other) const { - //std::cout << *this << " < " << other << "\n"; - if ((this->second != 0) && (other.second != 0)) - // regular ranges - return (this->first < other.first); - if (other.second == 0) - // second range just has an address - // (1000, 100) < (1200, 0) - // (1000, 100) < (1100, 0) first range ends at 1099 - return ((this->first + this->second) <= other.first); - assert(this->second == 0); - // this range just has an address - // (1100, 0) < (1200, 100) - return (this->first < other.first); - } -}; - -/** - * Simple map of address range to its bo handle and mapped virtual address - */ -static const std::pair mNullValue = std::make_pair(0xffffffff, nullptr); -class RangeTable { - std::map> mTable; - mutable std::mutex mMutex; -public: - void insert(uint64_t addr, size_t size, std::pair bo) { - // assert(find(addr) == 0xffffffff); - std::lock_guard lock(mMutex); - mTable[AddresRange(addr, size)] = bo; - } - - std::pair erase(uint64_t addr) { - std::lock_guard lock(mMutex); - std::map>::const_iterator i = mTable.find(AddresRange(addr)); - if (i == mTable.end()) - return mNullValue; - std::pair result = i->second; - mTable.erase(i); - return result; - } - - std::pair find(uint64_t addr) const { - std::lock_guard lock(mMutex); - std::map>::const_iterator i = mTable.find(AddresRange(addr)); - if (i == mTable.end()) - return mNullValue; - return i->second; - } -}; - - - // Memory alignment for DDR and AXI-MM trace access - template class AlignedAllocator { - void *mBuffer; - size_t mCount; - public: - T *getBuffer() { - return (T *)mBuffer; - } - - size_t size() const { - return mCount * sizeof(T); - } - - AlignedAllocator(size_t alignment, size_t count) : mBuffer(0), mCount(count) { - if (posix_memalign(&mBuffer, alignment, count * sizeof(T))) { - mBuffer = 0; - } - } - ~AlignedAllocator() { - if (mBuffer) - free(mBuffer); - } - }; - - const uint64_t mNullAddr = 0xffffffffffffffffull; - const uint64_t mNullBO = 0xffffffff; - - // XDMA Shim - class AwsXcl{ - - struct ELARecord { - unsigned mStartAddress; - unsigned mEndAddress; - unsigned mDataCount; - - std::streampos mDataPos; - ELARecord() : mStartAddress(0), mEndAddress(0), - mDataCount(0), mDataPos(0) {} - }; - - typedef std::list ELARecordList; - - typedef std::list > PairList; - - public: - //Sarab: Added for HAL2 XOCL Driver support - //int xclGetErrorStatus(xclErrorStatus *info); Not supported for AWS - bool xclUnlockDevice(); - unsigned int xclAllocBO(size_t size, xclBOKind domain, unsigned flags); - unsigned int xclAllocUserPtrBO(void *userptr, size_t size, unsigned flags); - void xclFreeBO(unsigned int boHandle); - int xclWriteBO(unsigned int boHandle, - const void *src, size_t size, size_t seek); - int xclReadBO(unsigned int boHandle, - void *dst, size_t size, size_t skip); - void *xclMapBO(unsigned int boHandle, bool write); - int xclSyncBO(unsigned int boHandle, xclBOSyncDirection dir, - size_t size, size_t offset); - int xclExportBO(unsigned int boHandle); - unsigned int xclImportBO(int fd, unsigned flags); - int xclGetBOProperties(unsigned int boHandle, xclBOProperties *properties); - ssize_t xclUnmgdPread(unsigned flags, void *buf, - size_t count, uint64_t offset); - ssize_t xclUnmgdPwrite(unsigned flags, const void *buf, - size_t count, uint64_t offset); - - - // Bitstreams - int xclGetXclBinIdFromSysfs(uint64_t &xclbinid); - int xclLoadXclBin(const xclBin *buffer); - int xclLoadAxlf(const axlf *buffer); - int xclUpgradeFirmware(const char *fileName); - int xclUpgradeFirmware2(const char *file1, const char* file2); - //int xclUpgradeFirmwareXSpi(const char *fileName, int device_index=0); Not supported by AWS - int xclTestXSpi(int device_index); - int xclBootFPGA(); - int xclRemoveAndScanFPGA(); - int resetDevice(xclResetKind kind); - int xclReClock2(unsigned short region, const unsigned short *targetFreqMHz); - - // Raw read/write - size_t xclWrite(xclAddressSpace space, uint64_t offset, const void *hostBuf, size_t size); - size_t xclRead(xclAddressSpace space, uint64_t offset, void *hostBuf, size_t size); - - // Buffer management - uint64_t xclAllocDeviceBuffer(size_t size); - uint64_t xclAllocDeviceBuffer2(size_t size, xclMemoryDomains domain, unsigned flags); - void xclFreeDeviceBuffer(uint64_t buf); - size_t xclCopyBufferHost2Device(uint64_t dest, const void *src, size_t size, size_t seek); - size_t xclCopyBufferDevice2Host(void *dest, uint64_t src, size_t size, size_t skip); - - // Performance monitoring - // Control - double xclGetDeviceClockFreqMHz(); - double xclGetReadMaxBandwidthMBps(); - double xclGetWriteMaxBandwidthMBps(); - //void xclSetOclRegionProfilingNumberSlots(uint32_t numSlots); - void xclSetProfilingNumberSlots(xclPerfMonType type, uint32_t numSlots); - size_t xclPerfMonClockTraining(xclPerfMonType type); - // Counters - size_t xclPerfMonStartCounters(xclPerfMonType type); - size_t xclPerfMonStopCounters(xclPerfMonType type); - size_t xclPerfMonReadCounters(xclPerfMonType type, xclCounterResults& counterResults); - //debug related - uint32_t getCheckerNumberSlots(int type); - uint32_t getIPCountAddrNames(int type, uint64_t *baseAddress, std::string * portNames); - size_t xclDebugReadCounters(xclDebugCountersResults* debugResult); - size_t xclDebugReadCheckers(xclDebugCheckersResults* checkerResult); - void readDebugIpLayout(); - - // Trace - size_t xclPerfMonStartTrace(xclPerfMonType type, uint32_t startTrigger); - size_t xclPerfMonStopTrace(xclPerfMonType type); - uint32_t xclPerfMonGetTraceCount(xclPerfMonType type); - size_t xclPerfMonReadTrace(xclPerfMonType type, xclTraceResultsVector& traceVector); - - // Sanity checks - int xclGetDeviceInfo2(xclDeviceInfo2 *info); - static AwsXcl *handleCheck(void *handle); - static unsigned xclProbe(); - bool xclLockDevice(); - unsigned getTAG() const { - return mTag; - } - bool isGood() const; - - ~AwsXcl(); - AwsXcl(unsigned index, const char *logfileName, xclVerbosityLevel verbosity); - - private: - - size_t xclReadModifyWrite(uint64_t offset, const void *hostBuf, size_t size); - size_t xclReadSkipCopy(uint64_t offset, void *hostBuf, size_t size); - bool zeroOutDDR(); - - bool isXPR() const { - return ((mDeviceInfo.mSubsystemId >> 12) == 4); - } - - bool isMultipleOCLClockSupported() { - unsigned dsaNum = ((mDeviceInfo.mDeviceId << 16) | mDeviceInfo.mSubsystemId); - // 0x82384431 : TUL KU115 4ddr 3.1 DSA - return ((dsaNum == 0x82384431) || (dsaNum == 0x82384432))? true : false; - } - - bool isUltraScale() const { - return (mDeviceInfo.mDeviceId & 0x8000); - } - - // Core DMA code - SHIM_O2 int pcieBarRead(int bar_num, unsigned long long offset, void* buffer, unsigned long long length); - SHIM_O2 int pcieBarWrite(int bar_num, unsigned long long offset, const void* buffer, unsigned long long length); - int freezeAXIGate(); - int freeAXIGate(); - - // PROM flashing - int prepare(unsigned startAddress, unsigned endAddress); - int program(std::ifstream& mcsStream, const ELARecord& record); - int program(std::ifstream& mcsStream); - int waitForReady(unsigned code, bool verbose = true); - int waitAndFinish(unsigned code, unsigned data, bool verbose = true); - - //XSpi flashing. - bool prepareXSpi(); - int programXSpi(std::ifstream& mcsStream, const ELARecord& record); - int programXSpi(std::ifstream& mcsStream); - bool waitTxEmpty(); - bool isFlashReady(); - //bool windDownWrites(); - bool bulkErase(); - bool sectorErase(unsigned Addr); - bool writeEnable(); -#if 0 - bool dataTransfer(bool read); -#endif - bool readPage(unsigned addr, uint8_t readCmd = 0xff); - bool writePage(unsigned addr, uint8_t writeCmd = 0xff); - unsigned readReg(unsigned offset); - int writeReg(unsigned regOffset, unsigned value); - bool finalTransfer(uint8_t *sendBufPtr, uint8_t *recvBufPtr, int byteCount); - bool getFlashId(); - //All remaining read /write register commands can be issued through this function. - bool readRegister(unsigned commandCode, unsigned bytes); - bool writeRegister(unsigned commandCode, unsigned value, unsigned bytes); - bool select4ByteAddressMode(); - bool deSelect4ByteAddressMode(); - - - // Performance monitoring helper functions - bool isDSAVersion(unsigned majorVersion, unsigned minorVersion, bool onlyThisVersion); - unsigned getBankCount(); - uint64_t getHostTraceTimeNsec(); - uint64_t getPerfMonBaseAddress(xclPerfMonType type, uint32_t slotNum); - uint64_t getPerfMonFifoBaseAddress(xclPerfMonType type, uint32_t fifonum); - uint64_t getPerfMonFifoReadBaseAddress(xclPerfMonType type, uint32_t fifonum); - uint32_t getPerfMonNumberSlots(xclPerfMonType type); - uint32_t getPerfMonNumberSamples(xclPerfMonType type); - uint32_t getPerfMonNumberFifos(xclPerfMonType type); - uint32_t getPerfMonByteScaleFactor(xclPerfMonType type); - uint8_t getPerfMonShowIDS(xclPerfMonType type); - uint8_t getPerfMonShowLEN(xclPerfMonType type); - uint32_t getPerfMonSlotStartBit(xclPerfMonType type, uint32_t slotnum); - uint32_t getPerfMonSlotDataWidth(xclPerfMonType type, uint32_t slotnum); - size_t resetFifos(xclPerfMonType type); - uint32_t bin2dec(std::string str, int start, int number); - uint32_t bin2dec(const char * str, int start, int number); - std::string dec2bin(uint32_t n); - std::string dec2bin(uint32_t n, unsigned bits); - static std::string getDSAName(unsigned short deviceId, unsigned short subsystemId); - - private: - // This is a hidden signature of this class and helps in preventing - // user errors when incorrect pointers are passed in as handles. - const unsigned mTag; - const int mBoardNumber; - const size_t maxDMASize; - bool mLocked; - const uint64_t mOffsets[XCL_ADDR_SPACE_MAX]; - int mUserHandle; -#ifdef INTERNAL_TESTING - int mMgtHandle; -#else - pci_bar_handle_t ocl_kernel_bar; // AppPF BAR0 for OpenCL kernels - pci_bar_handle_t sda_mgmt_bar; // MgmtPF BAR4, for SDAccel Perf mon etc - pci_bar_handle_t ocl_global_mem_bar; // AppPF BAR4 -#endif - uint32_t mMemoryProfilingNumberSlots; - uint32_t mOclRegionProfilingNumberSlots; - std::string mDevUserName; - - // Information extracted from platform linker - bool mIsDebugIpLayoutRead = false; - bool mIsDeviceProfiling = false; - uint64_t mPerfMonFifoCtrlBaseAddress; - uint64_t mPerfMonFifoReadBaseAddress; - uint64_t mPerfMonBaseAddress[XSPM_MAX_NUMBER_SLOTS]; - std::string mPerfMonSlotName[XSPM_MAX_NUMBER_SLOTS]; - - char *mUserMap; - std::ofstream mLogStream; - xclVerbosityLevel mVerbosity; - std::string mBinfile; - ELARecordList mRecordList; - xclDeviceInfo2 mDeviceInfo; - RangeTable mLegacyAddressTable; - -#ifndef INTERNAL_TESTING - int sleepUntilLoaded( std::string afi ); - int checkAndSkipReload( char *afi_id, fpga_mgmt_image_info *info ); - int loadDefaultAfiIfCleared( void ); -#endif - public: - static const unsigned TAG; - }; -} - -#endif diff --git a/SDAccel/userspace/src2/xclbin.cpp b/SDAccel/userspace/src2/xclbin.cpp deleted file mode 100755 index bf1c0184..00000000 --- a/SDAccel/userspace/src2/xclbin.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2017-2018 Xilinx, Inc - * Author: Sonal Santan - * AWS HAL Driver for SDAccel/OpenCL runtime evnrionemnt, for AWS EC2 F1 - * - * Code copied from SDAccel XDMA based HAL driver - * - * Licensed under the Apache License, Version 2.0 (the "License"). You may - * not use this file except in compliance with the License. A copy of the - * License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -//#define INTERNAL_TESTING 1 - -#include - -#include "xclbin2.h" - -#ifdef INTERNAL_TESTING -#define AFI_ID_STR_MAX 64 -#else -#include "hal/fpga_common.h" -#endif - -const char *get_afi_from_xclBin(const xclBin *buffer) -{ - const char *afid = reinterpret_cast(buffer); - afid += buffer->m_primaryFirmwareOffset; - if (buffer->m_primaryFirmwareLength > AFI_ID_STR_MAX) - return nullptr; - if (std::memcmp(afid, "afi-", 4) && std::memcmp(afid, "agfi-", 5)) - return nullptr; - return afid; -} - -const char *get_afi_from_axlf(const axlf *buffer) -{ - const axlf_section_header *bit_header = xclbin::get_axlf_section(buffer, BITSTREAM); - const char *afid = reinterpret_cast(buffer); - afid += bit_header->m_sectionOffset; - if (bit_header->m_sectionSize > AFI_ID_STR_MAX) - return nullptr; - if (std::memcmp(afid, "afi-", 4) && std::memcmp(afid, "agfi-", 5)) - return nullptr; - return afid; -} diff --git a/conftest.py b/conftest.py index 697ba1dc..47b71fa1 100644 --- a/conftest.py +++ b/conftest.py @@ -23,6 +23,8 @@ def pytest_addoption(parser): + parser.addoption("--batch", action="store", required=False, type=str, + help="batch option for internal simulations", default=0) parser.addoption("--simulator", action="store", required=False, type=str, help="Simulator tool requested for this test", default="vivado") parser.addoption("--examplePath", action="store", required=False, type=str, @@ -34,7 +36,12 @@ def pytest_addoption(parser): def pytest_generate_tests(metafunc): - + + if metafunc.cls.ADD_BATCH: + print("Configuring parameters of {}::{}".format(metafunc.module.__name__, metafunc.function.__name__)) + print("Batch = " + metafunc.config.getoption('batch')) + metafunc.parametrize("batch", [metafunc.config.getoption('batch')]) + if metafunc.cls.ADD_SIMULATOR: print("Configuring parameters of {}::{}".format(metafunc.module.__name__, metafunc.function.__name__)) print("Simulator = " + metafunc.config.getoption('simulator')) diff --git a/hdk/cl/examples/cl_dram_dma/README.md b/hdk/cl/examples/cl_dram_dma/README.md index 26497be8..00d1b33e 100644 --- a/hdk/cl/examples/cl_dram_dma/README.md +++ b/hdk/cl/examples/cl_dram_dma/README.md @@ -188,6 +188,6 @@ Alternatively, you can directly use a pre-generated AFI for this CL. | PCI Vendor ID | 0x1D0F (Amazon) | | PCI Subsystem ID | 0x1D51 | | PCI Subsystem Vendor ID | 0xFEDC | -| Pre-generated AFI ID | afi-0583e8d7a84ac7ce2 | -| Pre-generated AGFI ID | agfi-0d132ece5c8010bf7 | +| Pre-generated AFI ID | afi-08a7d9c0480bea3bd | +| Pre-generated AGFI ID | agfi-02f141212beac0cfb | diff --git a/hdk/cl/examples/cl_dram_dma/design/cl_tst.sv b/hdk/cl/examples/cl_dram_dma/design/cl_tst.sv index 93f8d490..e8d60b7f 100644 --- a/hdk/cl/examples/cl_dram_dma/design/cl_tst.sv +++ b/hdk/cl/examples/cl_dram_dma/design/cl_tst.sv @@ -157,7 +157,7 @@ always_ff @(negedge rst_n or posedge clk) // configuration //------------------------------------------- -//Offset 0x00: +//Offset 0x00: // 0 - Continuous mode - Keep looping through all the isntructions. // 1 - Incrementing loop data (every time through loop increment the start data) // 2 - PRBS mode (else incremeting). Data will be generated with PRBS. If not enabled, data will be incrementing per DW @@ -176,7 +176,7 @@ always_ff @(negedge rst_n or posedge clk) // 15:0 - Read Start -- This is not implemented (not sure we need this) // 31:0 - Max Write ahead -- This is not implemented (not sure we need this) //Offset 0x08: -// 0 - Write Go (read back write in progress) - Write this bit to start executing the write instructions. Reads back '1' while write instructions are in progress. +// 0 - Write Go (read back write in progress) - Write this bit to start executing the write instructions. Reads back '1' while write instructions are in progress. // 1 - Read Go (read back write in progress) - Write this bit to start executing the read instructions. Reads back '1' while read instructions are in progress. // 2 - Read response pending (read only). REad only, reads back '1' while read responses are pending. //Offset 0x0c: @@ -188,7 +188,7 @@ always_ff @(negedge rst_n or posedge clk) //Offset 0x14: // 3:0 - Max Read outstanding - Max number of read requests to issue (how many simultaneous read requests) // -// Offset 0x1c: Write Index - Write instruction Index +// Offset 0x1c: Write Index - Write instruction Index // Offset 0x20: Write address low - Write instruction address // Offset 0x24: Write address high - Write instruction address // Offset 0x28: Write data - Write instruction start data. All other data will be incrementing or PRBS @@ -351,7 +351,7 @@ always @(posedge clk) cfg_wr_stretch <= 0; cfg_rd_stretch <= 0; end - else + else begin cfg_wr_stretch <= cfg_wr || (cfg_wr_stretch && !tst_cfg_ack); cfg_rd_stretch <= cfg_rd || (cfg_rd_stretch && !tst_cfg_ack); @@ -455,28 +455,28 @@ always @(posedge clk) always @(posedge clk) begin case (cfg_addr_q) - 8'h0: tst_cfg_rdata <= {6'h0, cfg_const_data_mode, cfg_inc_id_mode, - 2'h0, cfg_rd_loop_addr_shift[5:0], - 2'h0, cfg_wr_loop_addr_shift[5:0], + 8'h0: tst_cfg_rdata <= {6'h0, cfg_const_data_mode, cfg_inc_id_mode, + 2'h0, cfg_rd_loop_addr_shift[5:0], + 2'h0, cfg_wr_loop_addr_shift[5:0], cfg_user_mode, cfg_loop_addr_mode, cfg_iter_mode, cfg_sync_mode, cfg_rd_compare_en, cfg_prbs_mode, cfg_inc_data_loop_mode, cfg_cont_mode}; 8'h4: tst_cfg_rdata <= {cfg_max_write, cfg_read_start}; 8'h8: tst_cfg_rdata <= {rd_resp_pend, rd_inp, wr_inp}; 8'hc: tst_cfg_rdata <= {wr_state[1:0], rd_tag_avail[15:0]}; 8'h10: tst_cfg_rdata <= {cfg_rd_num_inst, cfg_wr_num_inst}; 8'h14: tst_cfg_rdata <= {cfg_max_read_req}; - - 8'h1c: tst_cfg_rdata <= cfg_wr_inst_index; + + 8'h1c: tst_cfg_rdata <= cfg_wr_inst_index; 8'h20: tst_cfg_rdata <= wr_cfg_inst_rdata_q; - 8'h24: tst_cfg_rdata <= wr_cfg_inst_rdata_q >> 32; - 8'h28: tst_cfg_rdata <= wr_cfg_inst_rdata_q >> 64; + 8'h24: tst_cfg_rdata <= wr_cfg_inst_rdata_q >> 32; + 8'h28: tst_cfg_rdata <= wr_cfg_inst_rdata_q >> 64; 8'h2c: tst_cfg_rdata <= {wr_cfg_inst_rdata_q[127:96]}; 8'h30: tst_cfg_rdata <= {31'b0, cfg_atg_enable}; 8'h3c: tst_cfg_rdata <= cfg_rd_inst_index; 8'h40: tst_cfg_rdata <= rd_cfg_inst_rdata_q; - 8'h44: tst_cfg_rdata <= rd_cfg_inst_rdata_q >> 32; - 8'h48: tst_cfg_rdata <= rd_cfg_inst_rdata_q >> 64; + 8'h44: tst_cfg_rdata <= rd_cfg_inst_rdata_q >> 32; + 8'h48: tst_cfg_rdata <= rd_cfg_inst_rdata_q >> 64; 8'h4c: tst_cfg_rdata <= {rd_cfg_inst_rdata_q[127:96]}; 8'h60: tst_cfg_rdata <= cfg_rd_data_index; @@ -535,7 +535,7 @@ always_ff @(posedge clk) tst_cfg_ack <= 0; else tst_cfg_ack <= ((cfg_wr_stretch||cfg_rd_stretch) && !cfg_ram_access && !tst_cfg_ack) || - ((cfg_wr_stretch||cfg_rd_stretch) && cfg_ram_access && rd_cfg_read_ram_ack && !tst_cfg_ack); + ((cfg_wr_stretch||cfg_rd_stretch) && cfg_ram_access && rd_cfg_read_ram_ack && !tst_cfg_ack); //--------------------------------------- // Inst RAMs @@ -578,7 +578,7 @@ always @(posedge clk) //-------------------------------- -// Write state machine +// Write state machine //-------------------------------- logic[7:0] wr_running_length = 0; @@ -609,7 +609,7 @@ begin begin if (awready) wr_state_nxt = WR_DAT; - else + else wr_state_nxt = WR_ADDR; end @@ -658,11 +658,11 @@ always @(posedge clk) wr_loop_count <= wr_loop_count + 1; end -//Increment wr_cyc_count after the Write data for the read/write holdoff +//Increment wr_cyc_count after the Write data bresp for the read/write holdoff always @(posedge clk) if (cfg_wr_go) wr_cyc_count <= 0; - else if ((wr_state==WR_DAT) && (wr_state_nxt!=WR_DAT)) + else if (bvalid && bready) wr_cyc_count <= wr_cyc_count + 1; //Timer @@ -724,7 +724,7 @@ always_ff @( posedge clk) awlen <= inst_wr_rdata[103:96]; awuser <= (cfg_user_mode)? inst_wr_rdata[127:112]: ((inst_wr_rdata[103:96]+1) * user_length_mult) - wr_first_adj - inst_wr_rdata[104+:ADJ_DW_WIDTH]; end - else + else begin awid <= 0; awaddr <=0 ; @@ -757,7 +757,7 @@ logic[DATA_WIDTH-1:0] first_wdata = 0; //Pre-compute this for timing always @(posedge clk) begin for (int i=0; i= wr_cyc_count); -wire rd_wr_holdoff = cfg_sync_mode && wr_inp && rd_cyc_holdoff; +wire rd_wr_holdoff = cfg_sync_mode && rd_cyc_holdoff; -//Increment the read instruction +//Increment the read instruction assign rd_tag_pop = rd_inp && rd_tag_some_avail && !rd_fifo_full && !rd_wr_holdoff; always @(posedge clk) @@ -1085,7 +1084,7 @@ always_ff @(posedge clk) // rd_trk[rid_q].running_length <= rd_trk[rid].running_length + 1; // rd_trk[rid_q].req_data <= rd_data_nxt; // end -// end +// end //rd_trk_wr.req_data[32*i+:32] = inst_rd_rdata_q[95:64] + (rd_loop_count[7:0] & {32{cfg_inc_data_loop_mode}}) + i; always_comb @@ -1116,8 +1115,8 @@ always @(posedge clk) rd_md_ram_wr_addr <= rd_md_ram_wr_addr_pre; rd_md_ram_wr <= rd_md_ram_wr_pre; rd_md_ram_wr_data <= rd_md_ram_wr_data_pre; - end - + end + always @(posedge clk) begin @@ -1162,7 +1161,7 @@ begin rd_data_mask = ((rd_trk_rd.running_length==0) && rlast_q)? ({DATA_WIDTH{1'b1}} << (rd_trk_first_adj*32)) & (~({DATA_WIDTH{1'b1}} << (({ADJ_DW_WIDTH+5{1'b1}} + 1) - (rd_trk_rd.last_adj[0+:ADJ_DW_WIDTH] * 32)) )): (rd_trk_rd.running_length==0)? ({DATA_WIDTH{1'b1}} << (rd_trk_first_adj*32)): (rlast_q)? ~({DATA_WIDTH{1'b1}} << (({ADJ_DW_WIDTH+5{1'b1}} + 1) - (rd_trk_rd.last_adj[0+:ADJ_DW_WIDTH] * 32)) ): - {DATA_WIDTH{1'b1}}; + {DATA_WIDTH{1'b1}}; //for (int i=1; i> 2); @@ -1242,7 +1241,7 @@ flop_fifo #(.DEPTH(4), .WIDTH(9+11+8+64)) RD_REQ_FIFO ( .push(rd_tag_pop_qq), .push_data({rd_cur_req_tag, rd_push_user, inst_rd_rdata_q[103:96], rd_push_addr}), .pop(arvalid & arready), - + .pop_data({arid[8:0], aruser, arlen, araddr}), .half_full(), .watermark(rd_fifo_full), @@ -1250,7 +1249,7 @@ flop_fifo #(.DEPTH(4), .WIDTH(9+11+8+64)) RD_REQ_FIFO ( ); //------------------------------ -// Read track RAM +// Read track RAM bram_2rw #(.WIDTH(`RD_TRK_RAM_WIDTH), .ADDR_WIDTH(9), .DEPTH(512)) RD_TRK_RAM ( .clk(clk), @@ -1293,7 +1292,7 @@ always @(posedge clk) end assign rd_md_ram_rd_data = (rd_md_ram_col_q_pre)? rd_md_ram_wr_data_q_pre: - (rd_md_ram_col_q)? rd_md_ram_wr_data_q: + (rd_md_ram_col_q)? rd_md_ram_wr_data_q: rd_md_ram_rd_data_ram; @@ -1412,11 +1411,11 @@ always @(posedge clk) rresp_error_first; end - + ////Write addres recording //always_ff @(posedge clk) // if (cfg_wr_stretch && tst_cfg_ack && (cfg_addr_q==8'he0) && (cfg_wdata_q[31])) -// begin +// begin // for (int i=0; i<32; i++) // wr_addr_rec[i] <= {64{1'b1}}; // wr_addr_rec_ptr <= 0; @@ -1430,7 +1429,7 @@ always @(posedge clk) ////Read address recording //always_ff @(posedge clk) // if (cfg_wr_stretch && tst_cfg_ack && (cfg_addr_q==8'he0) && (cfg_wdata_q[31])) -// begin +// begin // for (int i=0; i<32; i++) // rd_addr_rec[i] <= {64{1'b1}}; // rd_addr_rec_ptr <= 0; @@ -1474,5 +1473,5 @@ begin end endfunction - + endmodule diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_axi_mstr_multi_rw.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_axi_mstr_multi_rw.sv index 717b1a3a..7bc3c9c5 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_axi_mstr_multi_rw.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_axi_mstr_multi_rw.sv @@ -134,7 +134,7 @@ for (int i = 0; i <= 12; i=i+4) begin //{ (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q), (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q) ); if (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0] !== tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q[31:0]) begin - $display("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", + $error("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", $realtime, tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_hi_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_lo_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0], @@ -200,7 +200,7 @@ for (int i = 0; i <= 12; i=i+4) begin //{ (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q), (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q) ); if (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0] !== tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q[31:0]) begin - $display("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", + $error("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", $realtime, tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_hi_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_lo_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0], @@ -266,7 +266,7 @@ for (int i = 0; i <= 12; i=i+4) begin //{ (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q), (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q) ); if (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0] !== tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q[31:0]) begin - $display("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", + $error("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", $realtime, tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_hi_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_lo_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0], @@ -333,7 +333,7 @@ for (int i = 0; i <= 12; i=i+4) begin //{ (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q), (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q) ); if (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0] !== tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q[31:0]) begin - $display("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", + $error("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", $realtime, tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_hi_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_lo_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0], @@ -356,7 +356,7 @@ end //} $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail || (tb.chk_prot_err_stat())) begin - $display("[%t] : TEST_FAILED", $realtime); + $error("[%t] : TEST_FAILED", $realtime); end else begin $display("[%t] : TEST_PASSED", $realtime); end diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_bar1.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_bar1.sv index 5fcc8731..4a6ce482 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_bar1.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_bar1.sv @@ -63,7 +63,7 @@ module test_bar1(); end while ((read_data[31:0] !== bar1_data[31:0]) && (timeout_count < 1000)); // UNMATCHED !! if ((timeout_count == 1000) || (read_data[31:0] !== bar1_data[31:0])) begin - $display("[%t] : *** ERROR *** Read data mismatch for bar1 exp_data %h act_data %h.", $realtime, bar1_data, read_data); + $error("[%t] : *** ERROR *** Read data mismatch for bar1 exp_data %h act_data %h.", $realtime, bar1_data, read_data); error_count++; end @@ -91,7 +91,7 @@ module test_bar1(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail || (tb.chk_prot_err_stat())) begin - $display("[%t] : TEST_FAILED", $realtime); + $error("[%t] : TEST_FAILED", $realtime); end else begin $display("[%t] : TEST_PASSED", $realtime); end diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_clk_recipe.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_clk_recipe.sv index d8c76ace..fe21b1c3 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_clk_recipe.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_clk_recipe.sv @@ -215,7 +215,7 @@ module test_clk_recipe(); tb.power_down(); if (tb.chk_clk_err_cnt()) begin - $display("[%t] : *** TEST FAILED ***", $realtime); + $error("[%t] : *** TEST FAILED ***", $realtime); end else begin $display("[%t] : *** TEST PASSED ***", $realtime); end diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_ddr.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_ddr.sv index 642deeed..dfcf96ad 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_ddr.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_ddr.sv @@ -82,7 +82,7 @@ module test_ddr(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail) begin - $display("[%t] : *** TEST FAILED ***", $realtime); + $error("[%t] : *** TEST FAILED ***", $realtime); end else begin $display("[%t] : *** TEST PASSED ***", $realtime); end @@ -163,7 +163,7 @@ module test_ddr(); end while ((read_data[2:0] !== 3'b000) && (timeout_count < 100)); if ((timeout_count == 100) && (read_data[2:0] !== 3'b000)) begin - $display("[%t] : *** ERROR *** Timeout waiting for writes and reads to complete.", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for writes and reads to complete.", $realtime); error_count++; end else begin // Stop reads and writes ([1] for reads, [0] for writes) @@ -178,7 +178,7 @@ module test_ddr(); tb.peek_ocl(.addr(base_addr + 64'h0f4), .data(read_data)); cycle_count[63:32] = read_data; if (cycle_count == 64'h0) begin - $display("[%t] : *** ERROR *** Write Timer value was 0x0 at end of test.", $realtime); + $error("[%t] : *** ERROR *** Write Timer value was 0x0 at end of test.", $realtime); error_count++; end @@ -189,7 +189,7 @@ module test_ddr(); tb.peek_ocl(.addr(base_addr + 64'h0fc), .data(read_data)); cycle_count[63:32] = read_data; if (cycle_count == 64'h0) begin - $display("[%t] : *** ERROR *** Read Timer value was 0x0 at end of test.", $realtime); + $error("[%t] : *** ERROR *** Read Timer value was 0x0 at end of test.", $realtime); error_count++; end @@ -204,7 +204,7 @@ module test_ddr(); error_addr[63:32] = read_data; tb.peek_ocl(.addr(base_addr + 64'h0bc), .data(read_data)); error_index = read_data[3:0]; - $display("[%t] : *** ERROR *** Read compare error from address 0x%016x, index 0x%1x", $realtime, error_addr, error_index); + $error("[%t] : *** ERROR *** Read compare error from address 0x%016x, index 0x%1x", $realtime, error_addr, error_index); error_count++; end end diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_ddr_peek_bdr_walking_ones.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_ddr_peek_bdr_walking_ones.sv index d339866a..d0a20a24 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_ddr_peek_bdr_walking_ones.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_ddr_peek_bdr_walking_ones.sv @@ -162,7 +162,7 @@ module test_ddr_peek_bdr_walking_ones(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail || (tb.chk_prot_err_stat())) begin - $display("[%t] : TEST_FAILED", $realtime); + $error("[%t] : TEST_FAILED", $realtime); end else begin $display("[%t] : TEST_PASSED", $realtime); end @@ -180,7 +180,7 @@ module test_ddr_peek_bdr_walking_ones(); $display("Read Data for Addr %h: Act %h", bdr_addr, read_data); if (read_data != data) begin - $display("Read Data mismatch for Addr %h: Exp %h, Act %h", bdr_addr, data, read_data); + $error("Read Data mismatch for Addr %h: Exp %h, Act %h", bdr_addr, data, read_data); error_count++; end end diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_ddr_peek_poke.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_ddr_peek_poke.sv index ea420f44..6ad3b844 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_ddr_peek_poke.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_ddr_peek_poke.sv @@ -61,7 +61,7 @@ module test_ddr_peek_poke(); $display("Read to Addr %b", addr); tb.peek(.addr(addr), .data(wide_read_data), .size(DataSize::UINT512)); if (wide_read_data != {512{1'b1}}) begin - $display("Read Data mismatch for Addr %h: Exp %h, Act %h", addr, {512{1'b1}}, wide_read_data); + $error("Read Data mismatch for Addr %h: Exp %h, Act %h", addr, {512{1'b1}}, wide_read_data); error_count++; end //Walk through DDR address range to check if two adjacent bits are wrongly wired. @@ -75,7 +75,7 @@ module test_ddr_peek_poke(); $display("Read to Addr %b", addr); tb.peek(.addr(addr), .data(wide_read_data), .size(DataSize::UINT512)); if (wide_read_data != {512{1'b1}}) begin - $display("Read Data mismatch for Addr %h: Exp %h, Act %h", addr, {512{1'b1}}, wide_read_data); + $error("Read Data mismatch for Addr %h: Exp %h, Act %h", addr, {512{1'b1}}, wide_read_data); error_count++; end end @@ -95,7 +95,7 @@ module test_ddr_peek_poke(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail) begin - $display("[%t] : *** TEST FAILED ***", $realtime); + $error("[%t] : *** TEST FAILED ***", $realtime); end else begin $display("[%t] : *** TEST PASSED ***", $realtime); end diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dma_pcim_concurrent.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dma_pcim_concurrent.sv index c0bb77ad..e2c42543 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dma_pcim_concurrent.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dma_pcim_concurrent.sv @@ -139,9 +139,14 @@ module test_dma_pcim_concurrent(); end while ((status[0] !== 'h1) && (timeout_count < 4000)); if (timeout_count > 4000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end + + // DMA transfers are posted writes. The above code checks only if the dma transfer is setup and done. + // We need to wait for writes to finish to memory before issuing reads. + $display("[%t] : Waiting for DMA write activity to complete", $realtime); + #500ns; $display("[%t] : starting C2H DMA channels ", $realtime); @@ -161,7 +166,7 @@ module test_dma_pcim_concurrent(); end while ((status[0] !== 'h1) && (timeout_count < 4000)); if (timeout_count > 4000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -174,7 +179,7 @@ module test_dma_pcim_concurrent(); host_memory_buffer_address = 64'h0_0001_0800; for (int i = 0 ; i 4000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end + // DMA transfers are posted writes. The above code checks only if the dma transfer is setup and done. + // We need to wait for writes to finish to memory before issuing reads. + $display("[%t] : Waiting for DMA write activity to complete", $realtime); + #500ns; + $display("[%t] : starting C2H DMA channels ", $realtime); // read the data from cl and put it in the host memory @@ -114,7 +119,7 @@ module test_dma_pcis_concurrent(); end while ((status[0] !== 'h1) && (timeout_count < 4000)); if (timeout_count > 4000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -127,22 +132,24 @@ module test_dma_pcis_concurrent(); host_memory_buffer_address = 64'h0_0001_0800; for (int i = 0 ; i 4000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end + // DMA transfers are posted writes. The above code checks only if the dma transfer is setup and done. + // We need to wait for writes to finish to memory before issuing reads. + $display("[%t] : Waiting for DMA write activity to complete", $realtime); + #500ns; + $display("[%t] : starting C2H DMA channels ", $realtime); // read the data from cl and put it in the host memory @@ -166,7 +171,7 @@ module test_dma_sda_concurrent(); end while ((status[0] !== 'h1) && (timeout_count < 4000)); if (timeout_count > 4000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -179,7 +184,7 @@ module test_dma_sda_concurrent(); host_memory_buffer_address = 64'h0_0001_0800; for (int i = 0 ; i= 4000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end - $display("[%t] : starting C2H DMA channels ", $realtime); + // DMA transfers are posted writes. The above code checks only if the dma transfer is setup and done. + // We need to wait for writes to finish to memory before issuing reads. + $display("[%t] : Waiting for DMA write transfers to complete", $realtime); + #2us; + $display("[%t] : starting C2H DMA channels ", $realtime); + // read the data from cl and put it in the host memory host_memory_buffer_address = 64'h0_0001_0800; tb.que_cl_to_buffer(.chan(0), .dst_addr(host_memory_buffer_address), .cl_addr(64'h0000_0000_1f00), .len(len0) ); // move DDR0 to buffer @@ -157,7 +162,7 @@ module test_dram_dma(); end while ((status != 4'hf) && (timeout_count < 1000)); if (timeout_count >= 1000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -170,7 +175,7 @@ module test_dram_dma(); host_memory_buffer_address = 64'h0_0001_0800; for (int i = 0 ; i= 4000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end + // DMA transfers are posted writes. The above code checks only if the dma transfer is setup and done. + // We need to wait for writes to finish to memory before issuing reads. + $display("[%t] : Waiting for DMA write activity to complete", $realtime); + #500ns; + $display("[%t] : starting C2H DMA channels ", $realtime); // read the data from cl and put it in the host memory @@ -154,7 +159,7 @@ module test_dram_dma_4k_crossing(); end while ((status != 4'hf) && (timeout_count < 1000)); if (timeout_count >= 1000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -167,7 +172,7 @@ module test_dram_dma_4k_crossing(); host_memory_buffer_address = 64'h0_0001_0800; for (int i = 0 ; i= 4000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end + // DMA transfers are posted writes. The above code checks only if the dma transfer is setup and done. + // We need to wait for writes to finish to memory before issuing reads. + $display("[%t] : Waiting for DMA write activity to complete", $realtime); + #500ns; + $display("[%t] : starting C2H DMA channels ", $realtime); // read the data from cl and put it in the host memory @@ -152,7 +157,7 @@ module test_dram_dma_allgn_addr_4k(); end while ((status != 4'hf) && (timeout_count < 1000)); if (timeout_count >= 1000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -165,7 +170,7 @@ module test_dram_dma_allgn_addr_4k(); host_memory_buffer_address = 64'h0_0001_0800; for (int i = 0 ; i= 1000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -129,7 +129,7 @@ module test_dram_dma_axi_mstr(); (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q), (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q) ); if (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0] !== tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q[31:0]) begin - $display("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", + $error("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", $realtime, tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_hi_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_lo_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0], @@ -175,7 +175,7 @@ module test_dram_dma_axi_mstr(); end while ((status != 4'hf) && (timeout_count < 1000)); if (timeout_count >= 1000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -188,7 +188,7 @@ module test_dram_dma_axi_mstr(); (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q), (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q) ); if (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0] !== tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q[31:0]) begin - $display("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", + $error("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", $realtime, tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_hi_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_lo_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0], @@ -234,7 +234,7 @@ module test_dram_dma_axi_mstr(); end while ((status != 4'hf) && (timeout_count < 1000)); if (timeout_count >= 1000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -247,7 +247,7 @@ module test_dram_dma_axi_mstr(); (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q), (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q) ); if (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0] !== tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q[31:0]) begin - $display("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", + $error("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", $realtime, tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_hi_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_lo_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0], @@ -293,7 +293,7 @@ module test_dram_dma_axi_mstr(); end while ((status != 4'hf) && (timeout_count < 1000)); if (timeout_count >= 1000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -306,7 +306,7 @@ module test_dram_dma_axi_mstr(); (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q), (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q) ); if (tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0] !== tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_rd_data_q[31:0]) begin - $display("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", + $error("[%t] : *** ERROR *** Data mismatch, addr:0x%0h_%0h write data is: 0x%h read data is: 0x%h", $realtime, tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_hi_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_addr_lo_q[31:0], tb.card.fpga.CL.CL_DRAM_DMA_AXI_MSTR.cmd_wr_data_q[31:0], @@ -328,7 +328,7 @@ module test_dram_dma_axi_mstr(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail || (tb.chk_prot_err_stat())) begin - $display("[%t] : *** TEST FAILED ***", $realtime); + $error("[%t] : *** TEST FAILED ***", $realtime); end else begin $display("[%t] : *** TEST PASSED ***", $realtime); end diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_bdr_common.svh b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_bdr_common.svh index a4a84954..394b4aed 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_bdr_common.svh +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_bdr_common.svh @@ -28,11 +28,6 @@ //Front Door read data for ( int i=0; i= 1000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -64,11 +59,11 @@ for (int i = 0 ; i> 8; end end // for ( int i=0; i<6; i++) - endtask// dma_c2h_transfers \ No newline at end of file + endtask// dma_c2h_transfers diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_dram_bdr_row_col_combo.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_dram_bdr_row_col_combo.sv index 340c0041..f5cbddbe 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_dram_bdr_row_col_combo.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_dram_bdr_row_col_combo.sv @@ -117,7 +117,7 @@ module test_dram_dma_dram_bdr_row_col_combo(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail || (tb.chk_prot_err_stat())) begin - $display("[%t] : TEST_FAILED", $realtime); + $error("[%t] : TEST_FAILED", $realtime); end else begin $display("[%t] : TEST_PASSED", $realtime); end diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_dram_bdr_wr.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_dram_bdr_wr.sv index 7b6b50da..802c7a0d 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_dram_bdr_wr.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_dram_bdr_wr.sv @@ -94,7 +94,7 @@ module test_dram_dma_dram_bdr_wr(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail || (tb.chk_prot_err_stat())) begin - $display("[%t] : *** TEST FAILED ***", $realtime); + $error("[%t] : *** TEST FAILED ***", $realtime); end else begin $display("[%t] : *** TEST PASSED ***", $realtime); end diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_mem_model_bdr_rd.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_mem_model_bdr_rd.sv index 459c1146..24e12978 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_mem_model_bdr_rd.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_mem_model_bdr_rd.sv @@ -117,7 +117,7 @@ module test_dram_dma_mem_model_bdr_rd(); end while ((status != 4'hf) && (timeout_count < 4000)); if (timeout_count >= 4000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -130,7 +130,7 @@ module test_dram_dma_mem_model_bdr_rd(); // Put test pattern in host memory for (int i = 0 ; i < len0 ; i++) begin if (tb.card.fpga.CL.SH_DDR.u_mem_model.bfm_inst[0].u_bfm.axi_mem_bdr_read(.addr(ddr_A_addr)) !== 8'hAA) begin - $display("[%t] : *** ERROR *** DDR0 Data mismatch, addr:%0x read data is: %0x", + $error("[%t] : *** ERROR *** DDR0 Data mismatch, addr:%0x read data is: %0x", $realtime, ddr_A_addr, (tb.card.fpga.CL.SH_DDR.u_mem_model.bfm_inst[0].u_bfm.axi_mem_bdr_read(.addr(ddr_A_addr)))); error_count++; end @@ -145,7 +145,7 @@ module test_dram_dma_mem_model_bdr_rd(); // Put test pattern in host memory for (int i = 0 ; i < len1 ; i++) begin if (tb.card.fpga.CL.SH_DDR.u_mem_model.bfm_inst[1].u_bfm.axi_mem_bdr_read(.addr(ddr_B_addr)) !== 8'hBB) begin - $display("[%t] : *** ERROR *** DDR1 Data mismatch, addr:%0x read data is: %0x", + $error("[%t] : *** ERROR *** DDR1 Data mismatch, addr:%0x read data is: %0x", $realtime, ddr_B_addr, (tb.card.fpga.CL.SH_DDR.u_mem_model.bfm_inst[1].u_bfm.axi_mem_bdr_read(.addr(ddr_B_addr)))); error_count++; end @@ -159,7 +159,7 @@ module test_dram_dma_mem_model_bdr_rd(); // Put test pattern in hst memory for (int i = 0 ; i < len2 ; i++) begin if (tb.card.fpga.sh.u_mem_model.axi_mem_bdr_read(.addr(ddr_C_addr)) !== 8'hCC) begin - $display("[%t] : *** ERROR *** DDR2 Data mismatch, addr:%0x read data is: %0x", + $error("[%t] : *** ERROR *** DDR2 Data mismatch, addr:%0x read data is: %0x", $realtime, ddr_C_addr, (tb.card.fpga.sh.u_mem_model.axi_mem_bdr_read(.addr(ddr_C_addr)))); error_count++; end @@ -173,7 +173,7 @@ module test_dram_dma_mem_model_bdr_rd(); // Put test pattern in host memory for (int i = 0 ; i < len3 ; i++) begin if (tb.card.fpga.CL.SH_DDR.u_mem_model.bfm_inst[2].u_bfm.axi_mem_bdr_read(.addr(ddr_D_addr)) !== 8'hDD) begin - $display("[%t] : *** ERROR *** DDR3 Data mismatch, addr:%0x read data is: %0x", + $error("[%t] : *** ERROR *** DDR3 Data mismatch, addr:%0x read data is: %0x", $realtime, ddr_D_addr, (tb.card.fpga.CL.SH_DDR.u_mem_model.bfm_inst[2].u_bfm.axi_mem_bdr_read(.addr(ddr_D_addr)))); error_count++; end @@ -194,7 +194,7 @@ module test_dram_dma_mem_model_bdr_rd(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail || (tb.chk_prot_err_stat())) begin - $display("[%t] : TEST_FAILED", $realtime); + $error("[%t] : TEST_FAILED", $realtime); end else begin $display("[%t] : TEST_PASSED", $realtime); end diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_mem_model_bdr_wr.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_mem_model_bdr_wr.sv index dfa3fce8..a5220eae 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_mem_model_bdr_wr.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_dram_dma_mem_model_bdr_wr.sv @@ -130,7 +130,7 @@ module test_dram_dma_mem_model_bdr_wr(); end while ((status != 4'hf) && (timeout_count < 1000)); if (timeout_count >= 1000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -143,7 +143,7 @@ module test_dram_dma_mem_model_bdr_wr(); host_memory_buffer_address = 64'h0_0001_0800; for (int i = 0 ; i= 4000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end + // DMA transfers are posted writes. The above code checks only if the dma transfer is setup and done. + // We need to wait for writes to finish to memory before issuing reads. + $display("[%t] : Waiting for DMA write activity to complete", $realtime); + #500ns; + $display("[%t] : starting C2H DMA channels ", $realtime); // read the data from cl and put it in the host memory @@ -172,7 +177,7 @@ module test_dram_dma_multi_ddr(); end while ((status != 4'hf) && (timeout_count < 1000)); if (timeout_count >= 1000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -186,7 +191,7 @@ module test_dram_dma_multi_ddr(); host_memory_buffer_address = 64'h0_0001_0800; for (int i = 0 ; i= 10000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -179,7 +179,7 @@ module test_dram_dma_rnd(); end while ((status != 4'hf) && (timeout_count < 10000)); if (timeout_count >= 10000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -192,7 +192,7 @@ module test_dram_dma_rnd(); host_memory_buffer_address = 64'h0_000A_0000; for (int i = 0 ; i= 4000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end + // DMA transfers are posted writes. The above code checks only if the dma transfer is setup and done. + // We need to wait for writes to finish to memory before issuing reads. + $display("[%t] : Waiting for DMA write activity to complete", $realtime); + #500ns; + $display("[%t] : starting C2H DMA channels ", $realtime); // read the data from cl and put it in the host memory @@ -152,7 +157,7 @@ module test_dram_dma_single_beat_4k(); end while ((status != 4'hf) && (timeout_count < 1000)); if (timeout_count >= 1000) begin - $display("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for dma transfers from cl", $realtime); error_count++; end @@ -165,7 +170,7 @@ module test_dram_dma_single_beat_4k(); host_memory_buffer_address = 64'h0_0001_0800; for (int i = 0 ; i Expected Data: %0h", + $error($time,,,"***ERROR*** : Data Mismatch. Actual Data:%0h <==> Expected Data: %0h", act_data, exp_data); error_count ++; end @@ -105,7 +105,7 @@ module test_peek_poke_pcis_axsize(); endtask task disp_err (input string s); - $display($time,,,"***ERROR*** : %s", s); + $error($time,,,"***ERROR*** : %s", s); error_count ++; endtask endmodule // test_peek_poke_pcis_axsize diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke_rnd_lengths.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke_rnd_lengths.sv index 78b07f2c..36ec6918 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke_rnd_lengths.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke_rnd_lengths.sv @@ -126,7 +126,7 @@ module test_peek_poke_rnd_lengths(); end while ((read_data[2:0] !== 3'b000) && (timeout_count < 100)); if ((timeout_count == 100) && (read_data[2:0] !== 3'b000)) begin - $display("[%t] : *** ERROR *** Timeout waiting for writes and reads to complete.", $realtime); + $error("[%t] : *** ERROR *** Timeout waiting for writes and reads to complete.", $realtime); error_count++; end else begin // Stop reads and writes ([1] for reads, [0] for writes) @@ -141,7 +141,7 @@ module test_peek_poke_rnd_lengths(); tb.peek_ocl(.addr(`WR_CYCLE_CNT_HIGH), .data(read_data)); cycle_count[63:32] = read_data; if (cycle_count == 64'h0) begin - $display("[%t] : *** ERROR *** Write Timer value was 0x0 at end of test.", $realtime); + $error("[%t] : *** ERROR *** Write Timer value was 0x0 at end of test.", $realtime); error_count++; end @@ -152,7 +152,7 @@ module test_peek_poke_rnd_lengths(); tb.peek_ocl(.addr(`RD_CYCLE_CNT_HIGH), .data(read_data)); cycle_count[63:32] = read_data; if (cycle_count == 64'h0) begin - $display("[%t] : *** ERROR *** Read Timer value was 0x0 at end of test.", $realtime); + $error("[%t] : *** ERROR *** Read Timer value was 0x0 at end of test.", $realtime); error_count++; end @@ -167,7 +167,7 @@ module test_peek_poke_rnd_lengths(); error_addr[63:32] = read_data; tb.peek_ocl(.addr(`RD_ERR_INDEX), .data(read_data)); error_index = read_data[3:0]; - $display("[%t] : *** ERROR *** Read compare error from address 0x%016x, index 0x%1x", $realtime, error_addr, error_index); + $error("[%t] : *** ERROR *** Read compare error from address 0x%016x, index 0x%1x", $realtime, error_addr, error_index); error_count++; end end @@ -185,7 +185,7 @@ module test_peek_poke_rnd_lengths(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail || (tb.chk_prot_err_stat())) begin - $display("[%t] : *** TEST FAILED ***", $realtime); + $error("[%t] : *** TEST FAILED ***", $realtime); end else begin $display("[%t] : *** TEST PASSED ***", $realtime); end diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke_wc.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke_wc.sv index a9d61b38..99fc0f2c 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke_wc.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_peek_poke_wc.sv @@ -123,7 +123,7 @@ module test_peek_poke_wc(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail || (tb.chk_prot_err_stat())) begin - $display("[%t] : *** TEST FAILED ***", $realtime); + $error("[%t] : *** TEST FAILED ***", $realtime); end else begin $display("[%t] : *** TEST PASSED ***", $realtime); end @@ -133,7 +133,7 @@ module test_peek_poke_wc(); task compare_data(logic [511:0] act_data, exp_data); if(act_data !== exp_data) begin - $display($time,,,"***ERROR*** : Data Mismatch. Actual Data:%0h <==> Expected Data: %0h", + $error($time,,,"***ERROR*** : Data Mismatch. Actual Data:%0h <==> Expected Data: %0h", act_data, exp_data); error_count ++; end @@ -143,7 +143,7 @@ module test_peek_poke_wc(); endtask // compare_data task disp_err (input string s); - $display($time,,,"***ERROR*** : %s", s); + $error($time,,,"***ERROR*** : %s", s); error_count ++; endtask // disp_err diff --git a/hdk/cl/examples/cl_dram_dma/verif/tests/test_sda.sv b/hdk/cl/examples/cl_dram_dma/verif/tests/test_sda.sv index c208a7db..4ab86cd9 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/tests/test_sda.sv +++ b/hdk/cl/examples/cl_dram_dma/verif/tests/test_sda.sv @@ -58,7 +58,7 @@ module test_sda(); end while ((read_data[31:0] !== sda_data[31:0]) && (timeout_count < 1000)); // UNMATCHED !! if ((timeout_count == 1000) || (read_data[31:0] !== sda_data[31:0])) begin - $display("[%t] : *** ERROR *** Read data mismatch for sda exp_data %h act_data %h.", $realtime, sda_data, read_data); + $error("[%t] : *** ERROR *** Read data mismatch for sda exp_data %h act_data %h.", $realtime, sda_data, read_data); error_count++; end @@ -84,7 +84,7 @@ module test_sda(); $display("[%t] : Detected %3d errors during this test", $realtime, error_count); if (fail || (tb.chk_prot_err_stat())) begin - $display("[%t] : *** TEST FAILED ***", $realtime); + $error("[%t] : *** TEST FAILED ***", $realtime); end else begin $display("[%t] : *** TEST PASSED ***", $realtime); end diff --git a/hdk/cl/examples/cl_hello_world/software/runtime/test_hello_world.c b/hdk/cl/examples/cl_hello_world/software/runtime/test_hello_world.c index 1471055b..54b671f9 100644 --- a/hdk/cl/examples/cl_hello_world/software/runtime/test_hello_world.c +++ b/hdk/cl/examples/cl_hello_world/software/runtime/test_hello_world.c @@ -52,10 +52,6 @@ static uint16_t pci_device_id = 0xF000; /* PCI Device ID preassigned by Amazon f * check if the corresponding AFI for hello_world is loaded */ int check_afi_ready(int slot_id); -/* - * An example to attach to an arbitrary slot, pf, and bar with register access. - */ -int peek_poke_example(uint32_t value, int slot_id, int pf_id, int bar_id); void usage(char* program_name) { printf("usage: %s [--slot ][]\n", program_name); @@ -65,6 +61,11 @@ uint32_t byte_swap(uint32_t value); #endif +/* + * An example to attach to an arbitrary slot, pf, and bar with register access. + */ +int peek_poke_example(uint32_t value, int slot_id, int pf_id, int bar_id); + uint32_t byte_swap(uint32_t value) { uint32_t swapped_value = 0; int b; @@ -76,14 +77,15 @@ uint32_t byte_swap(uint32_t value) { #ifdef SV_TEST //For cadence and questa simulators the main has to return some value - #ifdef INT_MAIN - int test_main(uint32_t *exit_code) { - #else - void test_main(uint32_t *exit_code) { - #endif +# ifdef INT_MAIN +int test_main(uint32_t *exit_code) +# else +void test_main(uint32_t *exit_code) +# endif #else - int main(int argc, char **argv) { +int main(int argc, char **argv) #endif +{ //The statements within SCOPE ifdef below are needed for HW/SW co-simulation with VCS #ifdef SCOPE svScope scope; @@ -121,8 +123,8 @@ uint32_t byte_swap(uint32_t value) { } #endif - /* initialize the fpga_pci library so we could have access to FPGA PCIe from this applications */ - rc = fpga_pci_init(); + /* initialize the fpga_mgmt library */ + rc = fpga_mgmt_init(); fail_on(rc, out, "Unable to initialize the fpga_pci library"); #ifndef SV_TEST @@ -172,7 +174,7 @@ uint32_t byte_swap(uint32_t value) { /* As HW simulation test is not run on a AFI, the below function is not valid */ #ifndef SV_TEST - int check_afi_ready(int slot_id) { +int check_afi_ready(int slot_id) { struct fpga_mgmt_image_info info = {0}; int rc; @@ -218,7 +220,7 @@ uint32_t byte_swap(uint32_t value) { return rc; out: return 1; - } +} #endif diff --git a/hdk/cl/examples/cl_sde/README.md b/hdk/cl/examples/cl_sde/README.md index db6f7525..cb82f592 100644 --- a/hdk/cl/examples/cl_sde/README.md +++ b/hdk/cl/examples/cl_sde/README.md @@ -74,5 +74,5 @@ The following table displays information about the CL that is required to regist | PCI Vendor ID | 0x1D0F (Amazon) | | PCI Subsystem ID | 0x1D51 | | PCI Subsystem Vendor ID | 0xFEDC | -| Pre-generated AFI ID (N.Virginia:us-east-1) | afi-08fca33060fff4a62 | -| Pre-generated AGFI ID | agfi-0f4eca32dc6100729 | +| Pre-generated AFI ID (N.Virginia:us-east-1) | afi-030f5efdbdb03e186 | +| Pre-generated AGFI ID | agfi-0e6adf0cd6932d880 | diff --git a/hdk/cl/examples/cl_sde/build/scripts/encrypt.tcl b/hdk/cl/examples/cl_sde/build/scripts/encrypt.tcl index 6e662da4..651018b1 100644 --- a/hdk/cl/examples/cl_sde/build/scripts/encrypt.tcl +++ b/hdk/cl/examples/cl_sde/build/scripts/encrypt.tcl @@ -68,7 +68,7 @@ file copy -force $CL_DIR/design/sde_desc.sv $TARGET_DIR file copy -force $CL_DIR/design/sde_pm.sv $TARGET_DIR file copy -force $CL_DIR/design/sde_ps_acc.sv $TARGET_DIR file copy -force $CL_DIR/design/sde_ps.sv $TARGET_DIR - +file copy -force $CL_DIR/design/cl_sde_defines.vh $TARGET_DIR file copy -force $CL_DIR/design/cl_id_defines.vh $TARGET_DIR file copy -force $CL_DIR/design/cl_pkt_tst.sv $TARGET_DIR file copy -force $CL_DIR/design/cl_tst.sv $TARGET_DIR diff --git a/hdk/cl/examples/cl_sde/design/cl_pkt_tst.sv b/hdk/cl/examples/cl_sde/design/cl_pkt_tst.sv index 923f9c12..1b8da105 100644 --- a/hdk/cl/examples/cl_sde/design/cl_pkt_tst.sv +++ b/hdk/cl/examples/cl_sde/design/cl_pkt_tst.sv @@ -79,18 +79,18 @@ module cl_pkt_tst #(parameter DATA_WIDTH = 512, // Should be atleast 32 ); - parameter DATA_DW = DATA_WIDTH / 32; + localparam DATA_DW = DATA_WIDTH / 32; `ifdef SIM // For simulation - parameter PREAMBLE_PKT_CNT = 32'hF; - parameter PREAMBLE_TKEEP = {{(TKEEP_WIDTH-4){1'b0}}, {4{1'b1}}}; + localparam PREAMBLE_PKT_CNT = 32'hF; + localparam PREAMBLE_TKEEP = {{(TKEEP_WIDTH-4){1'b0}}, {4{1'b1}}}; `else - parameter PREAMBLE_PKT_CNT = 32'hFF; - parameter PREAMBLE_TKEEP = {{(TKEEP_WIDTH-8){1'b0}}, {8{1'b1}}}; + localparam PREAMBLE_PKT_CNT = 32'hFF; + localparam PREAMBLE_TKEEP = {{(TKEEP_WIDTH-8){1'b0}}, {8{1'b1}}}; `endif - parameter TX_WAIT_CNT = 32'hF; - parameter RX_LOCK_CNT_MINUS1 = 32'h4; + localparam TX_WAIT_CNT = 32'hF; + localparam RX_LOCK_CNT_MINUS1 = 32'h4; typedef enum logic [2:0] {IDLE = 0, PREAMBLE = 1, diff --git a/hdk/cl/examples/cl_sde/design/cl_sde.sv b/hdk/cl/examples/cl_sde/design/cl_sde.sv index 2438d2ba..e5ebf42e 100644 --- a/hdk/cl/examples/cl_sde/design/cl_sde.sv +++ b/hdk/cl/examples/cl_sde/design/cl_sde.sv @@ -16,6 +16,7 @@ // CL Streaming +`include "cl_sde_defines.vh" module cl_sde @@ -210,6 +211,9 @@ module cl_sde logic [2:0] pre_sde_arid_q; logic [2:0] pre_sde_rid_q; + logic [9:0] float_bid ; + logic [9:0] float_rid ; + `include "unused_flr_template.inc" `include "unused_ddr_a_b_d_template.inc" `include "unused_ddr_c_template.inc" @@ -393,7 +397,7 @@ always @(posedge clk_main_a0) .aclk (clk_main_a0), .aresetn (rst_main_n_sync_bot_slr), - .s_axi_awid (sh_cl_dma_pcis_awid ), + .s_axi_awid ({10'b0, sh_cl_dma_pcis_awid} ), .s_axi_awaddr (sh_cl_dma_pcis_awaddr ), .s_axi_awlen (sh_cl_dma_pcis_awlen ), .s_axi_awsize (sh_cl_dma_pcis_awsize ), @@ -404,17 +408,17 @@ always @(posedge clk_main_a0) .s_axi_wlast (sh_cl_dma_pcis_wlast ), .s_axi_wvalid (sh_cl_dma_pcis_wvalid ), .s_axi_wready (cl_sh_dma_pcis_wready ), - .s_axi_bid (cl_sh_dma_pcis_bid ), + .s_axi_bid ({float_bid, cl_sh_dma_pcis_bid} ), .s_axi_bresp (cl_sh_dma_pcis_bresp ), .s_axi_bvalid (cl_sh_dma_pcis_bvalid ), .s_axi_bready (sh_cl_dma_pcis_bready ), - .s_axi_arid (sh_cl_dma_pcis_arid ), + .s_axi_arid ({10'b0, sh_cl_dma_pcis_arid} ), .s_axi_araddr (sh_cl_dma_pcis_araddr ), .s_axi_arlen (sh_cl_dma_pcis_arlen ), .s_axi_arsize (sh_cl_dma_pcis_arsize ), .s_axi_arvalid (sh_cl_dma_pcis_arvalid ), .s_axi_arready (cl_sh_dma_pcis_arready ), - .s_axi_rid (cl_sh_dma_pcis_rid ), + .s_axi_rid ({float_rid, cl_sh_dma_pcis_rid} ), .s_axi_rdata (cl_sh_dma_pcis_rdata ), .s_axi_rresp (cl_sh_dma_pcis_rresp ), .s_axi_rlast (cl_sh_dma_pcis_rlast ), @@ -653,6 +657,7 @@ sde #(.C2H_BUF_DEPTH(`C2H_BUF_DEPTH), //If simulation instantiate the Stream BFM `ifdef SIMULATION + stream_bfm STREAM_BFM (.clk (clk_main_a0), .rst_n (rst_main_n_sync), @@ -673,13 +678,14 @@ sde #(.C2H_BUF_DEPTH(`C2H_BUF_DEPTH), ); `else - logic bfm_h2c_axis_ready = 0; - logic bfm_c2h_axis_valid = 0; - logic [511:0] bfm_c2h_axis_data = 0; - logic [63:0] bfm_c2h_axis_keep = 0; - logic bfm_c2h_axis_last = 0; - logic [63:0] bfm_c2h_axis_user = 0; + assign bfm_h2c_axis_ready = 0; + + assign bfm_c2h_axis_valid = 0; + assign bfm_c2h_axis_data = 0; + assign bfm_c2h_axis_keep = 0; + assign bfm_c2h_axis_last = 0; + assign bfm_c2h_axis_user = 0; `endif //Instantiate the RTL Stream block diff --git a/hdk/cl/examples/cl_sde/design/cl_sde_defines.vh b/hdk/cl/examples/cl_sde/design/cl_sde_defines.vh index 46228c4f..923b784a 100644 --- a/hdk/cl/examples/cl_sde/design/cl_sde_defines.vh +++ b/hdk/cl/examples/cl_sde/design/cl_sde_defines.vh @@ -25,5 +25,6 @@ // Uncomment to disable Virtual JTAG //`define DISABLE_VJTAG_DEBUG +`define NO_SDE_DEBUG_ILA `endif diff --git a/hdk/cl/examples/cl_sde/design/cl_tst.sv b/hdk/cl/examples/cl_sde/design/cl_tst.sv index 3f23e563..dbc10afa 100644 --- a/hdk/cl/examples/cl_sde/design/cl_tst.sv +++ b/hdk/cl/examples/cl_sde/design/cl_tst.sv @@ -63,7 +63,7 @@ module cl_tst #(parameter DATA_WIDTH=512, parameter NUM_RD_TAG=512) ( output logic rready ); -parameter DATA_DW = DATA_WIDTH / 32; + localparam DATA_DW = DATA_WIDTH / 32; //-------------------------- // Internal signals @@ -157,7 +157,7 @@ always_ff @(negedge rst_n or posedge clk) // configuration //------------------------------------------- -//Offset 0x00: +//Offset 0x00: // 0 - Continuous mode - Keep looping through all the isntructions. // 1 - Incrementing loop data (every time through loop increment the start data) // 2 - PRBS mode (else incremeting). Data will be generated with PRBS. If not enabled, data will be incrementing per DW @@ -177,7 +177,7 @@ always_ff @(negedge rst_n or posedge clk) // 15:0 - Read Start -- This is not implemented (not sure we need this) // 31:0 - Max Write ahead -- This is not implemented (not sure we need this) //Offset 0x08: -// 0 - Write Go (read back write in progress) - Write this bit to start executing the write instructions. Reads back '1' while write instructions are in progress. +// 0 - Write Go (read back write in progress) - Write this bit to start executing the write instructions. Reads back '1' while write instructions are in progress. // 1 - Read Go (read back write in progress) - Write this bit to start executing the read instructions. Reads back '1' while read instructions are in progress. // 2 - Read response pending (read only). REad only, reads back '1' while read responses are pending. //Offset 0x0c: @@ -189,7 +189,7 @@ always_ff @(negedge rst_n or posedge clk) //Offset 0x14: // 3:0 - Max Read outstanding - Max number of read requests to issue (how many simultaneous read requests) // -// Offset 0x1c: Write Index - Write instruction Index +// Offset 0x1c: Write Index - Write instruction Index // Offset 0x20: Write address low - Write instruction address // Offset 0x24: Write address high - Write instruction address // Offset 0x28: Write data - Write instruction start data. All other data will be incrementing or PRBS @@ -353,7 +353,7 @@ always @(posedge clk) cfg_wr_stretch <= 0; cfg_rd_stretch <= 0; end - else + else begin cfg_wr_stretch <= cfg_wr || (cfg_wr_stretch && !tst_cfg_ack); cfg_rd_stretch <= cfg_rd || (cfg_rd_stretch && !tst_cfg_ack); @@ -458,28 +458,28 @@ always @(posedge clk) always @(posedge clk) begin case (cfg_addr_q) - 8'h0: tst_cfg_rdata <= {5'h0, cfg_inc_awid, cfg_const_data_mode, cfg_inc_id_mode, - 2'h0, cfg_rd_loop_addr_shift[5:0], - 2'h0, cfg_wr_loop_addr_shift[5:0], + 8'h0: tst_cfg_rdata <= {5'h0, cfg_inc_awid, cfg_const_data_mode, cfg_inc_id_mode, + 2'h0, cfg_rd_loop_addr_shift[5:0], + 2'h0, cfg_wr_loop_addr_shift[5:0], cfg_user_mode, cfg_loop_addr_mode, cfg_iter_mode, cfg_sync_mode, cfg_rd_compare_en, cfg_prbs_mode, cfg_inc_data_loop_mode, cfg_cont_mode}; 8'h4: tst_cfg_rdata <= {cfg_max_write, cfg_read_start}; 8'h8: tst_cfg_rdata <= {rd_resp_pend, rd_inp, wr_inp}; 8'hc: tst_cfg_rdata <= {wr_state[1:0], rd_tag_avail[15:0]}; 8'h10: tst_cfg_rdata <= {cfg_rd_num_inst, cfg_wr_num_inst}; 8'h14: tst_cfg_rdata <= {cfg_max_read_req}; - - 8'h1c: tst_cfg_rdata <= cfg_wr_inst_index; + + 8'h1c: tst_cfg_rdata <= cfg_wr_inst_index; 8'h20: tst_cfg_rdata <= wr_cfg_inst_rdata_q; - 8'h24: tst_cfg_rdata <= wr_cfg_inst_rdata_q >> 32; - 8'h28: tst_cfg_rdata <= wr_cfg_inst_rdata_q >> 64; + 8'h24: tst_cfg_rdata <= wr_cfg_inst_rdata_q >> 32; + 8'h28: tst_cfg_rdata <= wr_cfg_inst_rdata_q >> 64; 8'h2c: tst_cfg_rdata <= {wr_cfg_inst_rdata_q[127:96]}; 8'h30: tst_cfg_rdata <= {31'b0, cfg_atg_enable}; 8'h3c: tst_cfg_rdata <= cfg_rd_inst_index; 8'h40: tst_cfg_rdata <= rd_cfg_inst_rdata_q; - 8'h44: tst_cfg_rdata <= rd_cfg_inst_rdata_q >> 32; - 8'h48: tst_cfg_rdata <= rd_cfg_inst_rdata_q >> 64; + 8'h44: tst_cfg_rdata <= rd_cfg_inst_rdata_q >> 32; + 8'h48: tst_cfg_rdata <= rd_cfg_inst_rdata_q >> 64; 8'h4c: tst_cfg_rdata <= {rd_cfg_inst_rdata_q[127:96]}; 8'h60: tst_cfg_rdata <= cfg_rd_data_index; @@ -538,7 +538,7 @@ always_ff @(posedge clk) tst_cfg_ack <= 0; else tst_cfg_ack <= ((cfg_wr_stretch||cfg_rd_stretch) && !cfg_ram_access && !tst_cfg_ack) || - ((cfg_wr_stretch||cfg_rd_stretch) && cfg_ram_access && rd_cfg_read_ram_ack && !tst_cfg_ack); + ((cfg_wr_stretch||cfg_rd_stretch) && cfg_ram_access && rd_cfg_read_ram_ack && !tst_cfg_ack); //--------------------------------------- // Inst RAMs @@ -581,7 +581,7 @@ always @(posedge clk) //-------------------------------- -// Write state machine +// Write state machine //-------------------------------- logic[7:0] wr_running_length = 0; @@ -612,7 +612,7 @@ begin begin if (awready) wr_state_nxt = WR_DAT; - else + else wr_state_nxt = WR_ADDR; end @@ -665,7 +665,7 @@ always @(posedge clk) always @(posedge clk) if (cfg_wr_go) wr_cyc_count <= 0; - else if ((wr_state==WR_DAT) && (wr_state_nxt!=WR_DAT)) + else if (bvalid && bready) wr_cyc_count <= wr_cyc_count + 1; //Timer @@ -705,7 +705,7 @@ assign wr_loop_addr_adj = (cfg_loop_addr_mode)? wr_loop_count << cfg_wr_loop_add //assign awuser = (cfg_user_mode)? inst_wr_rdata[127:112]: (inst_wr_rdata[103:96]+1) * user_length_mult; //This is the number of DW to adjust -parameter ADJ_DW_WIDTH = (DATA_WIDTH==512)? 4: +localparam ADJ_DW_WIDTH = (DATA_WIDTH==512)? 4: (DATA_WIDTH==256)? 3: (DATA_WIDTH==128)? 2: 1; @@ -727,7 +727,7 @@ always_ff @( posedge clk) awlen <= inst_wr_rdata[103:96]; awuser <= (cfg_user_mode)? inst_wr_rdata[127:112]: ((inst_wr_rdata[103:96]+1) * user_length_mult) - wr_first_adj - inst_wr_rdata[104+:ADJ_DW_WIDTH]; end - else + else begin awid <= (cfg_inc_awid)? awid + 1: 0; awaddr <=0 ; @@ -760,7 +760,7 @@ logic[DATA_WIDTH-1:0] first_wdata = 0; //Pre-compute this for timing always @(posedge clk) begin for (int i=0; i= wr_cyc_count); -wire rd_wr_holdoff = cfg_sync_mode && wr_inp && rd_cyc_holdoff; +wire rd_wr_holdoff = cfg_sync_mode && rd_cyc_holdoff; -//Increment the read instruction +//Increment the read instruction assign rd_tag_pop = rd_inp && rd_tag_some_avail && !rd_fifo_full && !rd_wr_holdoff; always @(posedge clk) @@ -1088,7 +1087,7 @@ always_ff @(posedge clk) // rd_trk[rid_q].running_length <= rd_trk[rid].running_length + 1; // rd_trk[rid_q].req_data <= rd_data_nxt; // end -// end +// end //rd_trk_wr.req_data[32*i+:32] = inst_rd_rdata_q[95:64] + (rd_loop_count[7:0] & {32{cfg_inc_data_loop_mode}}) + i; always_comb @@ -1119,8 +1118,8 @@ always @(posedge clk) rd_md_ram_wr_addr <= rd_md_ram_wr_addr_pre; rd_md_ram_wr <= rd_md_ram_wr_pre; rd_md_ram_wr_data <= rd_md_ram_wr_data_pre; - end - + end + always @(posedge clk) begin @@ -1165,7 +1164,7 @@ begin rd_data_mask = ((rd_trk_rd.running_length==0) && rlast_q)? ({DATA_WIDTH{1'b1}} << (rd_trk_first_adj*32)) & (~({DATA_WIDTH{1'b1}} << (({ADJ_DW_WIDTH+5{1'b1}} + 1) - (rd_trk_rd.last_adj[0+:ADJ_DW_WIDTH] * 32)) )): (rd_trk_rd.running_length==0)? ({DATA_WIDTH{1'b1}} << (rd_trk_first_adj*32)): (rlast_q)? ~({DATA_WIDTH{1'b1}} << (({ADJ_DW_WIDTH+5{1'b1}} + 1) - (rd_trk_rd.last_adj[0+:ADJ_DW_WIDTH] * 32)) ): - {DATA_WIDTH{1'b1}}; + {DATA_WIDTH{1'b1}}; //for (int i=1; i> 2); @@ -1245,7 +1244,7 @@ flop_fifo #(.DEPTH(4), .WIDTH(9+11+8+64)) RD_REQ_FIFO ( .push(rd_tag_pop_qq), .push_data({rd_cur_req_tag, rd_push_user, inst_rd_rdata_q[103:96], rd_push_addr}), .pop(arvalid & arready), - + .pop_data({arid[8:0], aruser, arlen, araddr}), .half_full(), .watermark(rd_fifo_full), @@ -1253,7 +1252,7 @@ flop_fifo #(.DEPTH(4), .WIDTH(9+11+8+64)) RD_REQ_FIFO ( ); //------------------------------ -// Read track RAM +// Read track RAM bram_1w1r #(.WIDTH(`RD_TRK_RAM_WIDTH), .ADDR_WIDTH(9), .DEPTH(512)) RD_TRK_RAM ( .clk(clk), @@ -1290,7 +1289,7 @@ always @(posedge clk) end assign rd_md_ram_rd_data = (rd_md_ram_col_q_pre)? rd_md_ram_wr_data_q_pre: - (rd_md_ram_col_q)? rd_md_ram_wr_data_q: + (rd_md_ram_col_q)? rd_md_ram_wr_data_q: rd_md_ram_rd_data_ram; @@ -1400,11 +1399,11 @@ always @(posedge clk) rresp_error_first; end - + ////Write addres recording //always_ff @(posedge clk) // if (cfg_wr_stretch && tst_cfg_ack && (cfg_addr_q==8'he0) && (cfg_wdata_q[31])) -// begin +// begin // for (int i=0; i<32; i++) // wr_addr_rec[i] <= {64{1'b1}}; // wr_addr_rec_ptr <= 0; @@ -1418,7 +1417,7 @@ always @(posedge clk) ////Read address recording //always_ff @(posedge clk) // if (cfg_wr_stretch && tst_cfg_ack && (cfg_addr_q==8'he0) && (cfg_wdata_q[31])) -// begin +// begin // for (int i=0; i<32; i++) // rd_addr_rec[i] <= {64{1'b1}}; // rd_addr_rec_ptr <= 0; @@ -1462,5 +1461,5 @@ begin end endfunction - + endmodule diff --git a/hdk/cl/examples/cl_sde/design/sde_c2h_data.sv b/hdk/cl/examples/cl_sde/design/sde_c2h_data.sv index 9b4edfcf..7c61f0d1 100644 --- a/hdk/cl/examples/cl_sde/design/sde_c2h_data.sv +++ b/hdk/cl/examples/cl_sde/design/sde_c2h_data.sv @@ -202,44 +202,44 @@ module sde_c2h_data #(parameter bit DESC_TYPE = 0, // 0 - Regular, 1 - Compact always_comb begin - req_state_next <= req_state; + req_state_next = req_state; case (req_state) REQ_IDLE : if (desc_dm_desc_valid) - req_state_next <= REQ_WAIT_DATA; // REQ_GET_DESC; + req_state_next = REQ_WAIT_DATA; // REQ_GET_DESC; else - req_state_next <= REQ_IDLE; + req_state_next = REQ_IDLE; // REQ_GET_DESC: -// req_state_next <= REQ_WAIT_DATA; +// req_state_next = REQ_WAIT_DATA; REQ_WAIT_DATA: if (curr_txn_data_avail & ~dp_wb_ff_full & bresp_prealloc_avail) - req_state_next <= REQ_ADDR; + req_state_next = REQ_ADDR; else - req_state_next <= REQ_WAIT_DATA; + req_state_next = REQ_WAIT_DATA; REQ_ADDR: if (dm_pm_awvalid & pm_dm_awready) - req_state_next <= REQ_DATA; + req_state_next = REQ_DATA; else - req_state_next <= REQ_ADDR; + req_state_next = REQ_ADDR; REQ_DATA: if (data_tx_done && data_desc_done) - req_state_next <= REQ_IDLE; + req_state_next = REQ_IDLE; else if (data_tx_done) - req_state_next <= REQ_WAIT_CALC; + req_state_next = REQ_WAIT_CALC; else - req_state_next <= REQ_DATA; + req_state_next = REQ_DATA; REQ_WAIT_CALC: // Only required to be in this state when servicing multiple packets per descriptor // Need to wait 1 clock for the buf_dm_num_bytes to get updated after the end of REQ_DATA phase - req_state_next <= REQ_WAIT_DATA; + req_state_next = REQ_WAIT_DATA; default: - req_state_next <= req_state; + req_state_next = req_state; endcase // case (req_state) end // always_comb diff --git a/hdk/cl/examples/cl_sde/design/sde_h2c_data.sv b/hdk/cl/examples/cl_sde/design/sde_h2c_data.sv index 67efcb4d..70e4f5ea 100644 --- a/hdk/cl/examples/cl_sde/design/sde_h2c_data.sv +++ b/hdk/cl/examples/cl_sde/design/sde_h2c_data.sv @@ -183,33 +183,33 @@ module sde_h2c_data #(parameter bit DESC_TYPE = 0, // 0 - Regular, 1 - Compact always_comb begin - req_state_next <= req_state; + req_state_next = req_state; case (req_state) REQ_IDLE : if (desc_dm_desc_valid) - req_state_next <= REQ_WAIT_DATA; // REQ_GET_DESC; + req_state_next = REQ_WAIT_DATA; // REQ_GET_DESC; else - req_state_next <= REQ_IDLE; + req_state_next = REQ_IDLE; // REQ_GET_DESC: -// req_state_next <= REQ_WAIT_DATA; +// req_state_next = REQ_WAIT_DATA; REQ_WAIT_DATA: if (curr_txn_space_avail && ~rd_txn_trk_ff_full) - req_state_next <= REQ_ADDR; + req_state_next = REQ_ADDR; else - req_state_next <= REQ_WAIT_DATA; + req_state_next = REQ_WAIT_DATA; REQ_ADDR: if (desc_req_done && desc_done) - req_state_next <= REQ_IDLE; + req_state_next = REQ_IDLE; else if (desc_req_done) - req_state_next <= REQ_WAIT_DATA; + req_state_next = REQ_WAIT_DATA; else - req_state_next <= REQ_ADDR; + req_state_next = REQ_ADDR; default: - req_state_next <= req_state; + req_state_next = req_state; endcase // case (req_state) end // always_comb diff --git a/hdk/cl/examples/cl_sde/design/sde_ps_acc.sv b/hdk/cl/examples/cl_sde/design/sde_ps_acc.sv index e0628bdd..b4e8b6a1 100644 --- a/hdk/cl/examples/cl_sde/design/sde_ps_acc.sv +++ b/hdk/cl/examples/cl_sde/design/sde_ps_acc.sv @@ -71,10 +71,12 @@ if (LIMITED_SUPPORT == 0) begin logic [ACC_WIDTH-1:0] acc_in_wdata_d; logic [ACC_DW_IDX_WIDTH:0] acc_wr_num_dw; - always_comb + always_comb begin + pcis_wr_num_dw_d = '0; for (int dw_idx = 0; dw_idx < (PCIS_DATA_WIDTH>>5); dw_idx++) if (pcis_wstrb[dw_idx*4]) - pcis_wr_num_dw_d <= dw_idx + 1; + pcis_wr_num_dw_d = dw_idx + 1; + end always @(posedge clk) if (!rst_n) begin @@ -190,10 +192,12 @@ else begin logic [ACC_WIDTH-1:0] acc_in_wdata_d; logic [ACC_DW_IDX_WIDTH:0] acc_wr_num_dw; - always_comb + always_comb begin + pcis_wr_num_dw_d = '0; for (int dw_idx = 0; dw_idx < (PCIS_DATA_WIDTH>>5)/2; dw_idx++) //(512/32)/2=8 if ((pcis_wstrb[dw_idx*4]) && (dw_idx == 0 || dw_idx == 3 || dw_idx == 7)) - pcis_wr_num_dw_d <= dw_idx + 1; //Supported DW= 1DW, 4DW and 8DW + pcis_wr_num_dw_d = dw_idx + 1; //Supported DW= 1DW, 4DW and 8DW + end always @(posedge clk) if (!rst_n) begin diff --git a/hdk/cl/examples/cl_sde/design/sde_wb.sv b/hdk/cl/examples/cl_sde/design/sde_wb.sv index 3d37da34..12eb10cb 100644 --- a/hdk/cl/examples/cl_sde/design/sde_wb.sv +++ b/hdk/cl/examples/cl_sde/design/sde_wb.sv @@ -742,7 +742,7 @@ end // if (~H2C_N_C2H) if (rst_n) begin wr_done_q <= wr_done; - if (cfg_desc_cdt_wc_en & (desc_wb_limit_q != 32'h0) & ~wr_done_q & ~desc_cdt_req_pend) + if (cfg_wb_desc_cnt_en & cfg_desc_cdt_wc_en & (desc_wb_limit_q != 32'h0) & ~wr_done_q & ~desc_cdt_req_pend) assert (desc_wb_limit - desc_wb_limit_q <= (cfg_wc_cnt * 2)) else begin $display("%m: *** ERROR ***: Desc Limit Write Coalesce Error. desc_wb_limit = 0x%x, desc_wb_limit_q = 0x%x, cfg_wc_cnt = 0x%x. @ %0t", desc_wb_limit, desc_wb_limit_q, cfg_wc_cnt, $time); $finish; @@ -760,7 +760,7 @@ end // if (~H2C_N_C2H) $finish; end - if (cfg_md_wr_ptr_wc_en && (md_wr_ptr >= md_wr_ptr_q) & ~wr_done_q & ~md_wr_ptr_req_pend) + if (cfg_wb_md_ptr_en & cfg_md_wr_ptr_wc_en && (md_wr_ptr >= md_wr_ptr_q) & ~wr_done_q & ~md_wr_ptr_req_pend) assert (md_wr_ptr - md_wr_ptr_q <= (cfg_wc_cnt * 2)) else begin $display("%m: *** ERROR ***: Desc Limit Write Coalesce Error. md_wr_ptr = 0x%x, md_wr_ptr_q = 0x%x, cfg_wc_cnt = 0x%x. @ %0t", md_wr_ptr, md_wr_ptr_q, cfg_wc_cnt, $time); $finish; diff --git a/hdk/cl/examples/cl_sde/lib/ram_fifo_ft.sv b/hdk/cl/examples/cl_sde/lib/ram_fifo_ft.sv index fc51ce3b..f221580f 100644 --- a/hdk/cl/examples/cl_sde/lib/ram_fifo_ft.sv +++ b/hdk/cl/examples/cl_sde/lib/ram_fifo_ft.sv @@ -37,7 +37,7 @@ module ram_fifo_ft #(parameter WIDTH=32, parameter PTR_WIDTH=7, parameter WATERM // to see if FIFO is not ); -parameter[31:0] NUM_LOC = 1'b1 << PTR_WIDTH; +localparam[31:0] NUM_LOC = 1'b1 << PTR_WIDTH; logic ram_pop; logic[WIDTH-1:0] ram_rdata; diff --git a/hdk/cl/examples/cl_sde/software/runtime/Makefile b/hdk/cl/examples/cl_sde/software/runtime/Makefile index ae9df9a4..5b9e1609 100644 --- a/hdk/cl/examples/cl_sde/software/runtime/Makefile +++ b/hdk/cl/examples/cl_sde/software/runtime/Makefile @@ -15,26 +15,29 @@ export TEST ?= test_sde_loopback -INCLUDES = -I$(SDK_DIR)/userspace/include +SLOT_NUM = 0 +APP_SCRIPTS_DIR = $(SDK_DIR)/apps/virtual-ethernet/scripts +APP_INSTALL_DIR = veth_app +DPDK_DIR = $(APP_INSTALL_DIR)/dpdk +RMDIR = sudo rm -rf +STATS_PERIOD = 0 -CC = gcc -CFLAGS = -DCONFIG_LOGLEVEL=4 -std=gnu99 -g -Wall -Werror $(INCLUDES) +.PHONY: all clean -LDLIBS = -lfpga_mgmt -lrt -lpthread +all: check_env install run -SRC = common_dma.c $(TEST).c -OBJ = $(SRC:.c=.o) -BIN = $(TEST) +install: check_env + sudo $(APP_SCRIPTS_DIR)/virtual_ethernet_install.py $(APP_INSTALL_DIR) + sudo $(APP_SCRIPTS_DIR)/virtual_ethernet_setup.py $(DPDK_DIR) $(SLOT_NUM) -all: check_env - -#$(BIN): $(OBJ) -# $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LDLIBS) +run: check_env + sudo $(DPDK_DIR)/x86_64-native-linuxapp-gcc/app/testpmd -l 0-1 -- --port-topology=loop --auto-start --tx-first --stats-period=$(STATS_PERIOD) & \ clean: - rm -f *.o $(BIN) + $(RMDIR) $(APP_INSTALL_DIR) check_env: ifndef SDK_DIR $(error SDK_DIR is undefined. Try "source sdk_setup.sh" to set the software environment) endif + diff --git a/hdk/cl/examples/cl_uram_example/software/runtime/test_uram_example.c b/hdk/cl/examples/cl_uram_example/software/runtime/test_uram_example.c index 7a072173..c056057f 100644 --- a/hdk/cl/examples/cl_uram_example/software/runtime/test_uram_example.c +++ b/hdk/cl/examples/cl_uram_example/software/runtime/test_uram_example.c @@ -187,10 +187,10 @@ uint32_t glb_value; /* initialize the fpga_pci library so we could have access to FPGA PCIe from this applications */ - printf("Starting to initialize the fpga_pci library \n"); - rc = fpga_pci_init(); - fail_on(rc, out, "Unable to initialize the fpga_pci library\n TEST FAILED\n"); - printf("Done initializing the fpga_pci library \n"); + printf("Starting to initialize the fpga_mgmt library\n"); + rc = fpga_mgmt_init(); + fail_on(rc, out, "Unable to initialize the fpga_mgmt library\n TEST FAILED\n"); + printf("Done initializing the fpga_mgmt library\n"); #ifndef SV_TEST rc = check_afi_ready(slot_id); @@ -203,14 +203,18 @@ uint32_t glb_value; rc = uram_example(slot_id, FPGA_APP_PF, APP_PF_BAR0, value); fail_on(rc, out, "peek-poke example failed\n TEST FAILED\n"); + fpga_mgmt_close(); + #ifndef SV_TEST return rc; out: + fpga_mgmt_close(); return 1; #else out: + fpga_mgmt_close(); if (rc != 0) { printf("TEST_FAILED \n"); } diff --git a/hdk/common/software/include/fpga_pci_sv.h b/hdk/common/software/include/fpga_pci_sv.h index 26886b52..efcc4c96 100644 --- a/hdk/common/software/include/fpga_pci_sv.h +++ b/hdk/common/software/include/fpga_pci_sv.h @@ -71,6 +71,23 @@ typedef int pci_bar_handle_t; */ int fpga_pci_init(void); +/** + * Initialize the fpga_mgmt library. + * Calls fpga_pci_init. + * + * @returns 0 on success, non-zero on error + */ +int fpga_mgmt_init(void); + +/** + * Closes the fpga_mgmt library and its dependencies and releases any acquired + * resources. + * + * @returns 0 on success, non-zero on error + */ +int fpga_mgmt_close(void); + + /** * Attach to an FPGA memory space. * diff --git a/hdk/common/software/src/fpga_pci_sv.c b/hdk/common/software/src/fpga_pci_sv.c index d6725f65..88b922ad 100644 --- a/hdk/common/software/src/fpga_pci_sv.c +++ b/hdk/common/software/src/fpga_pci_sv.c @@ -24,6 +24,16 @@ int fpga_pci_init(void) return 0; } +int fpga_mgmt_init(void) +{ + return 0; +} + +int fpga_mgmt_close(void) +{ + return 0; +} + /** * Attach to an FPGA memory space. * diff --git a/hdk/docs/RTL_Simulating_CL_Designs.md b/hdk/docs/RTL_Simulating_CL_Designs.md index 35997127..39540f1f 100644 --- a/hdk/docs/RTL_Simulating_CL_Designs.md +++ b/hdk/docs/RTL_Simulating_CL_Designs.md @@ -7,7 +7,7 @@ Developers tend to simulate their designs to validate the RTL design and functio | 3rd party simulator Tool | 2017.4 Vivado tool | 2018.2 Vivado tool | 2018.3 Vivado tool | |--------------------------|--------------------|--------------------|--------------------| | Xilinx Vivado XSIM | Vivado v2017.4.op (64-bit) | Vivado v2018.2_AR71275_op (64-bit) | Vivado v2018.3.op (64-bit) | -| Synopsys VCS | vcs-mx/L-2016.06-1 | vcs-mx/N-2017.12-SP1-1 | vcs-mx/N-2017.12-SP2 | +| Synopsys VCS | vcs-mx/M-2017.03-SP2-11 | vcs-mx/N-2017.12-SP1-1 | vcs-mx/N-2017.12-SP2 | | Mentor Graphics Questa | 10.6b | 10.6c_1 | 10.6c_1 | | Cadence Incisive Enterprise Simulator(IES) | 15.20.063 | 15.20.063 | 15.20.063 | diff --git a/hdk/hdk_version.txt b/hdk/hdk_version.txt index a1664e02..ed64e996 100644 --- a/hdk/hdk_version.txt +++ b/hdk/hdk_version.txt @@ -1 +1 @@ -HDK_VERSION=1.4.9 +HDK_VERSION=1.4.10 \ No newline at end of file diff --git a/hdk/tests/simulation_tests/run_sim.sh b/hdk/tests/simulation_tests/run_sim.sh index 9c34a7cc..b4b9a083 100755 --- a/hdk/tests/simulation_tests/run_sim.sh +++ b/hdk/tests/simulation_tests/run_sim.sh @@ -36,9 +36,19 @@ case $key in ;; --simulator) simulator="$2" - shift - shift - ;; + shift + shift + ;; + --batch) + batch="$2" + shift + shift + ;; + --vivado-version) + vivado_version="$2" + shift + shift + ;; --test-type) test_type="$2" shift @@ -51,43 +61,52 @@ case $key in esac done +vivado_version=${vivado_version//./_} +if [ $batch == "TRUE" ]; then +COMMAND="batch_submit.py -q vcs-lo --jd Cad-centos7_2 --jn github_regress_${test_name}_${test_type}_${vivado_version}_${simulator} --wait --echo -c make" +else +COMMAND="make" +fi + +echo "$COMMAND" + # Run the test pushd $test_dir case "$simulator" in vcs) case "$test_type" in sv) - make TEST="$test_name" VCS=1 + $COMMAND TEST="$test_name" VCS=1 ;; sv_fast) - make TEST="$test_name" AXI_MEMORY_MODEL=1 VCS=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 VCS=1 ;; sv_fast_ecc_direct) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_DIRECT=1 ECC_ADDR_HI=1000 ECC_ADDR_LO=0 VCS=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_DIRECT=1 ECC_ADDR_HI=1000 ECC_ADDR_LO=0 VCS=1 ;; sv_fast_ecc_rnd) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 VCS=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 VCS=1 ;; sv_fast_ecc_rnd_100) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 VCS=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 VCS=1 ;; sv_fast_ecc_rnd_50) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=50 VCS=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=50 VCS=1 ;; sv_fast_ecc_rnd_10) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=10 VCS=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=10 VCS=1 ;; sv_fast_ecc_rnd_0) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=0 VCS=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=0 VCS=1 ;; sv_ddr_bkdr) - make TEST="$test_name" DDR_BKDR=1 VCS=1 + $COMMAND TEST="$test_name" DDR_BKDR=1 VCS=1 ;; vhdl) - make TEST="$test_name" VCS=1 + $COMMAND TEST="$test_name" VCS=1 ;; c) - make C_TEST="$test_name" VCS=1 + $COMMAND C_TEST="$test_name" VCS=1 ;; *) echo -e >&2 "ERROR: Invalid option: $1\n" @@ -98,37 +117,37 @@ case "$simulator" in ies) case "$test_type" in sv) - make TEST="$test_name" IES=1 + $COMMAND TEST="$test_name" IES=1 ;; sv_fast) - make TEST="$test_name" AXI_MEMORY_MODEL=1 IES=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 IES=1 ;; sv_fast_ecc_direct) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_DIRECT=1 ECC_ADDR_HI=1000 ECC_ADDR_LO=0 IES=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_DIRECT=1 ECC_ADDR_HI=1000 ECC_ADDR_LO=0 IES=1 ;; sv_fast_ecc_rnd) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 IES=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 IES=1 ;; sv_fast_ecc_rnd_100) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 IES=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 IES=1 ;; sv_fast_ecc_rnd_50) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=50 IES=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=50 IES=1 ;; sv_fast_ecc_rnd_10) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=10 IES=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=10 IES=1 ;; sv_fast_ecc_rnd_0) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=0 IES=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=0 IES=1 ;; sv_ddr_bkdr) - make TEST="$test_name" DDR_BKDR=1 IES=1 + $COMMAND TEST="$test_name" DDR_BKDR=1 IES=1 ;; vhdl) - make TEST="$test_name" IES=1 + $COMMAND TEST="$test_name" IES=1 ;; c) - make C_TEST="$test_name" IES=1 + $COMMAND C_TEST="$test_name" IES=1 ;; *) echo -e >&2 "ERROR: Invalid option: $1\n" @@ -139,37 +158,37 @@ case "$simulator" in questa) case "$test_type" in sv) - make TEST="$test_name" QUESTA=1 + $COMMAND TEST="$test_name" QUESTA=1 ;; sv_fast) - make TEST="$test_name" AXI_MEMORY_MODEL=1 QUESTA=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 QUESTA=1 ;; sv_fast_ecc_direct) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_DIRECT=1 ECC_ADDR_HI=1000 ECC_ADDR_LO=0 QUESTA=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_DIRECT=1 ECC_ADDR_HI=1000 ECC_ADDR_LO=0 QUESTA=1 ;; sv_fast_ecc_rnd) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 QUESTA=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 QUESTA=1 ;; sv_fast_ecc_rnd_100) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 QUESTA=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 QUESTA=1 ;; sv_fast_ecc_rnd_50) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=50 QUESTA=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=50 QUESTA=1 ;; sv_fast_ecc_rnd_10) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=10 QUESTA=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=10 QUESTA=1 ;; sv_fast_ecc_rnd_0) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=0 QUESTA=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=0 QUESTA=1 ;; sv_ddr_bkdr) - make TEST="$test_name" DDR_BKDR=1 QUESTA=1 + $COMMAND TEST="$test_name" DDR_BKDR=1 QUESTA=1 ;; vhdl) - make TEST="$test_name" QUESTA=1 + $COMMAND TEST="$test_name" QUESTA=1 ;; c) - make C_TEST="$test_name" QUESTA=1 + $COMMAND C_TEST="$test_name" QUESTA=1 ;; *) echo -e >&2 "ERROR: Invalid option: $1\n" @@ -180,37 +199,37 @@ case "$simulator" in *) case "$test_type" in sv) - make TEST="$test_name" + $COMMAND TEST="$test_name" ;; sv_fast) - make TEST="$test_name" AXI_MEMORY_MODEL=1 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ;; sv_fast_ecc_direct) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_DIRECT=1 ECC_ADDR_HI=1000 ECC_ADDR_LO=0 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_DIRECT=1 ECC_ADDR_HI=1000 ECC_ADDR_LO=0 ;; sv_fast_ecc_rnd) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 ;; sv_fast_ecc_rnd_100) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=100 ;; sv_fast_ecc_rnd_50) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=50 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=50 ;; sv_fast_ecc_rnd_10) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=10 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=10 ;; sv_fast_ecc_rnd_0) - make TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=0 + $COMMAND TEST="$test_name" AXI_MEMORY_MODEL=1 ECC_RAND=1 RND_ECC_WEIGHT=0 ;; sv_ddr_bkdr) - make TEST="$test_name" DDR_BKDR=1 + $COMMAND TEST="$test_name" DDR_BKDR=1 ;; vhdl) - make TEST="$test_name" + $COMMAND TEST="$test_name" ;; c) - make C_TEST="$test_name" + $COMMAND C_TEST="$test_name" ;; *) echo -e >&2 "ERROR: Invalid option: $1\n" diff --git a/hdk/tests/simulation_tests/test_sims.py b/hdk/tests/simulation_tests/test_sims.py index 158038e2..0c725c49 100644 --- a/hdk/tests/simulation_tests/test_sims.py +++ b/hdk/tests/simulation_tests/test_sims.py @@ -44,6 +44,7 @@ class TestSims(AwsFpgaTestBase): """ ADD_SIMULATOR = True + ADD_BATCH = True @classmethod def setup_class(cls): @@ -121,7 +122,9 @@ def parse_simulation_output(cls, test_name, test_type, test_stdout, test_stderr) return return_dict - def run_sim(self, test_dir="", test_name="", test_type="", simulator=""): + def run_sim(self, test_dir="", test_name="", test_type="", simulator="", batch=""): + + vivado_version = os.environ.get('VIVADO_TOOL_VERSION', 'unknown') # Error on defaults if not(test_dir and test_name and test_type): @@ -131,12 +134,13 @@ def run_sim(self, test_dir="", test_name="", test_type="", simulator=""): '--test-name', test_name, '--test-dir', test_dir, '--test-type', test_type, - '--simulator', simulator + '--simulator', simulator, + '--batch', batch, + '--vivado-version', vivado_version ] (rc, stdout_lines, stderr_lines) = self.run_cmd(" ".join(command_line)) - vivado_version = os.environ.get('VIVADO_TOOL_VERSION', 'unknown') # write simulation output if simulator == "vivado": @@ -172,506 +176,505 @@ def run_sim(self, test_dir="", test_name="", test_type="", simulator=""): # cl_dram_dma sv - def test_cl_dram_dma__dram_dma__sv(self, simulator): + def test_cl_dram_dma__dram_dma__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma__sv_fast(self, simulator): + def test_cl_dram_dma__dram_dma__sv_fast(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma' test_type = 'sv_fast' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_axi_mstr__sv(self, simulator): + def test_cl_dram_dma__dram_dma_axi_mstr__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_axi_mstr' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_rnd__sv(self, simulator): + def test_cl_dram_dma__dram_dma_rnd__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_rnd' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_rnd__sv_fast(self, simulator): + def test_cl_dram_dma__dram_dma_rnd__sv_fast(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_rnd' test_type = 'sv_fast' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_rnd__sv_fast_ecc_direct(self, simulator): + def test_cl_dram_dma__dram_dma_rnd__sv_fast_ecc_direct(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_rnd' test_type = 'sv_fast_ecc_direct' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_rnd__sv_fast_ecc_rnd(self, simulator): + def test_cl_dram_dma__dram_dma_rnd__sv_fast_ecc_rnd(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_rnd' test_type = 'sv_fast_ecc_rnd' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_4k_crossing__sv(self, simulator): + def test_cl_dram_dma__dram_dma_4k_crossing__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_4k_crossing' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_single_beat_4k__sv(self, simulator): + def test_cl_dram_dma__dram_dma_single_beat_4k__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_single_beat_4k' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_single_beat_4k__sv_fast(self, simulator): + def test_cl_dram_dma__dram_dma_single_beat_4k__sv_fast(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_single_beat_4k' test_type = 'sv_fast' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_single_beat_4k__sv_fast_ecc_direct(self, simulator): + def test_cl_dram_dma__dram_dma_single_beat_4k__sv_fast_ecc_direct(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_single_beat_4k' test_type = 'sv_fast_ecc_direct' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_single_beat_4k__sv_fast_ecc_rnd(self, simulator): + def test_cl_dram_dma__dram_dma_single_beat_4k__sv_fast_ecc_rnd(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_single_beat_4k' test_type = 'sv_fast_ecc_rnd' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dma_pcis_concurrent__sv(self, simulator): + def test_cl_dram_dma__dma_pcis_concurrent__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dma_pcis_concurrent' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dma_pcis_concurrent__sv_fast(self, simulator): + def test_cl_dram_dma__dma_pcis_concurrent__sv_fast(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dma_pcis_concurrent' test_type = 'sv_fast' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dma_pcis_concurrent__sv_fast_ecc_direct(self, simulator): + def test_cl_dram_dma__dma_pcis_concurrent__sv_fast_ecc_direct(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dma_pcis_concurrent' test_type = 'sv_fast_ecc_direct' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dma_pcis_concurrent__sv_fast_ecc_rnd(self, simulator): + def test_cl_dram_dma__dma_pcis_concurrent__sv_fast_ecc_rnd(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dma_pcis_concurrent' test_type = 'sv_fast_ecc_rnd' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__host_pcim__sv(self, simulator): + def test_cl_dram_dma__host_pcim__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_host_pcim' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) - - def test_cl_dram_dma__dma_pcim_concurrent__sv(self, simulator): + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) + def test_cl_dram_dma__dma_pcim_concurrent__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dma_pcim_concurrent' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dma_pcim_concurrent__sv_fast(self, simulator): + def test_cl_dram_dma__dma_pcim_concurrent__sv_fast(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dma_pcim_concurrent' test_type = 'sv_fast' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) - def test_cl_dram_dma__dma_pcim_concurrent__sv_fast_ecc_direct(self, simulator): + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) + def test_cl_dram_dma__dma_pcim_concurrent__sv_fast_ecc_direct(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dma_pcim_concurrent' test_type = 'sv_fast_ecc_direct' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dma_pcim_concurrent__sv_fast_ecc_rnd(self, simulator): + def test_cl_dram_dma__dma_pcim_concurrent__sv_fast_ecc_rnd(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dma_pcim_concurrent' test_type = 'sv_fast_ecc_rnd' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dma_sda_concurrent__sv(self, simulator): + def test_cl_dram_dma__dma_sda_concurrent__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dma_sda_concurrent' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dma_sda_concurrent__sv_fast(self, simulator): + def test_cl_dram_dma__dma_sda_concurrent__sv_fast(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dma_sda_concurrent' test_type = 'sv_fast' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dma_sda_concurrent__sv_fast_ecc_direct(self, simulator): + def test_cl_dram_dma__dma_sda_concurrent__sv_fast_ecc_direct(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dma_sda_concurrent' test_type = 'sv_fast_ecc_direct' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) - def test_cl_dram_dma__dma_sda_concurrent__sv_fast_ecc_rnd(self, simulator): + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) + def test_cl_dram_dma__dma_sda_concurrent__sv_fast_ecc_rnd(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dma_sda_concurrent' test_type = 'sv_fast_ecc_rnd' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__ddr__sv(self, simulator): + def test_cl_dram_dma__ddr__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_ddr' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__clk_recipe__sv(self, simulator): + def test_cl_dram_dma__clk_recipe__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_clk_recipe' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__int__sv(self, simulator): + def test_cl_dram_dma__int__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_int' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke__sv(self, simulator): + def test_cl_dram_dma__peek_poke__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke__sv_fast(self, simulator): + def test_cl_dram_dma__peek_poke__sv_fast(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke' test_type = 'sv_fast' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke__sv_fast_ecc_direct(self, simulator): + def test_cl_dram_dma__peek_poke__sv_fast_ecc_direct(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke' test_type = 'sv_fast_ecc_direct' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke__sv_fast_ecc_rnd(self, simulator): + def test_cl_dram_dma__peek_poke__sv_fast_ecc_rnd(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke' test_type = 'sv_fast_ecc_rnd' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke_wc__sv(self, simulator): + def test_cl_dram_dma__peek_poke_wc__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke_wc' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke_wc__sv_fast(self, simulator): + def test_cl_dram_dma__peek_poke_wc__sv_fast(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke_wc' test_type = 'sv_fast' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke_wc__sv_fast_ecc_direct(self, simulator): + def test_cl_dram_dma__peek_poke_wc__sv_fast_ecc_direct(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke_wc' test_type = 'sv_fast_ecc_direct' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke_wc__sv_fast_ecc_rnd(self, simulator): + def test_cl_dram_dma__peek_poke_wc__sv_fast_ecc_rnd(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke_wc' test_type = 'sv_fast_ecc_rnd' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke_len__sv(self, simulator): + def test_cl_dram_dma__peek_poke_len__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke_len' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke_len__sv_fast(self, simulator): + def test_cl_dram_dma__peek_poke_len__sv_fast(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke_len' test_type = 'sv_fast' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke_len__sv_fast_ecc_direct(self, simulator): + def test_cl_dram_dma__peek_poke_len__sv_fast_ecc_direct(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke_len' test_type = 'sv_fast_ecc_direct' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke_len__sv_fast_ecc_rnd(self, simulator): + def test_cl_dram_dma__peek_poke_len__sv_fast_ecc_rnd(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke_len' test_type = 'sv_fast_ecc_rnd' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke_pcis_axsize__sv(self, simulator): + def test_cl_dram_dma__peek_poke_pcis_axsize__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke_pcis_axsize' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke_pcis_axsize__sv_fast(self, simulator): + def test_cl_dram_dma__peek_poke_pcis_axsize__sv_fast(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke_pcis_axsize' test_type = 'sv_fast' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke_pcis_axsize__sv_fast_ecc_direct(self, simulator): + def test_cl_dram_dma__peek_poke_pcis_axsize__sv_fast_ecc_direct(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke_pcis_axsize' test_type = 'sv_fast_ecc_direct' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__peek_poke_pcis_axsize__sv_fast_ecc_rnd(self, simulator): + def test_cl_dram_dma__peek_poke_pcis_axsize__sv_fast_ecc_rnd(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_peek_poke_pcis_axsize' test_type = 'sv_fast_ecc_rnd' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__ddr_peek_poke__sv(self, simulator): + def test_cl_dram_dma__ddr_peek_poke__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_ddr_peek_poke' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__ddr_peek_bdr_walking_ones__sv(self, simulator): + def test_cl_dram_dma__ddr_peek_bdr_walking_ones__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_ddr_peek_bdr_walking_ones' test_type = 'sv_ddr_bkdr' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_dram_bdr_row_col_combo__sv(self, simulator): + def test_cl_dram_dma__dram_dma_dram_bdr_row_col_combo__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_dram_bdr_row_col_combo' test_type = 'sv_ddr_bkdr' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_mem_model_bdr_wr__sv(self, simulator): + def test_cl_dram_dma__dram_dma_mem_model_bdr_wr__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_mem_model_bdr_wr' test_type = 'sv_fast' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_mem_model_bdr_rd__sv(self, simulator): + def test_cl_dram_dma__dram_dma_mem_model_bdr_rd__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_mem_model_bdr_rd' test_type = 'sv_fast' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__axi_mstr_multi_rw__sv(self, simulator): + def test_cl_dram_dma__axi_mstr_multi_rw__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_axi_mstr_multi_rw' test_type = 'sv' - def test_cl_dram_dma__bar1__sv(self, simulator): + def test_cl_dram_dma__bar1__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_bar1' test_type = 'sv' - def test_cl_dram_dma__dram_dma_allgn_addr_4k__sv(self, simulator): + def test_cl_dram_dma__dram_dma_allgn_addr_4k__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_allgn_addr_4k' test_type = 'sv' - def test_ddr_peek_bdr_walking_ones__sv(self, simulator): + def test_ddr_peek_bdr_walking_ones__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_ddr_peek_bdr_walking_ones' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) # cl_uram_example c - def test_cl_uram_example__uram_example__c(self, simulator): + def test_cl_uram_example__uram_example__c(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_uram_example/verif/scripts' test_name = 'test_uram_example' test_type = 'c' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) # cl_dram_dma c - def test_cl_dram_dma__sda__sv(self, simulator): + def test_cl_dram_dma__sda__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_sda' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - def test_cl_dram_dma__dram_dma_hwsw_cosim__c(self, simulator): + def test_cl_dram_dma__dram_dma_hwsw_cosim__c(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_hwsw_cosim' test_type = 'c' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) # cl_hello_world sv - def test_cl_hello_world__hello_world__sv(self, simulator): + def test_cl_hello_world__hello_world__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_hello_world/verif/scripts' test_name = 'test_hello_world' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) # cl_test_gl_cntr sv - def test_cl_hello_world__gl_cntr__sv(self, simulator): + def test_cl_hello_world__gl_cntr__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_hello_world/verif/scripts' test_name = 'test_gl_cntr' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) # cl_hello_world vhdl - def test_cl_hello_world__hello_world__vhdl(self, simulator): + def test_cl_vhdl_hello_world__hello_world__vhdl(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts' test_name = 'test_hello_world' test_type = 'vhdl' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) # cl_hello_world c - def test_cl_hello_world__hello_world__c(self, simulator): + def test_cl_hello_world__hello_world__c(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_hello_world/verif/scripts' test_name = 'test_hello_world' test_type = 'c' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) # cl_sde_c2h sv - def test_cl_sde__test_simple_c2h__sv(self, simulator): + def test_cl_sde__test_simple_c2h__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_sde/verif/scripts' test_name = 'test_simple_c2h' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) # cl_sde_h2c sv - def test_cl_sde__test_simple_h2c__sv(self, simulator): + def test_cl_sde__test_simple_h2c__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_sde/verif/scripts' test_name = 'test_simple_h2c' test_type = 'sv' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator) + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) diff --git a/hdk/tests/test_gen_dcp.py b/hdk/tests/test_gen_dcp.py index 176e4a4c..d2ccd22d 100644 --- a/hdk/tests/test_gen_dcp.py +++ b/hdk/tests/test_gen_dcp.py @@ -69,11 +69,14 @@ def setup_class(cls): def set_allowed_warnings(cls): cls.allowed_warnings = ( - (('.*',), r'^WARNING: \[Constraints 18-838\] Failed to create SRL placer macro for cell SH/SH/MGT_TOP'), + (('.*',), r'^WARNING: \[Constraints 18-838\] Failed to create SRL placer macro for cell SH/SH/MGT_TOP.*'), + (('.*',), r'^WARNING: \[Shape Builder 18-838\] Failed to create SRL placer macro for cell WRAPPER_INST/SH/SH/MGT_TOP.*'), + (('.*',), r'^WARNING: \[Common 17-576\] \'fanout_opt\' is deprecated.*'), (('.*',), r'^CRITICAL WARNING: \[Place 30-823\] Failed to process clock nets that should have matching clock routes\. Reason: Found incompatible user defined or fixed clock roots for related clocks \'CL/SH_DDR/ddr_cores\.DDR4'), (('.*',), r'^CRITICAL WARNING: \[Constraints 18-850\] Failed to place register with ASYNC_REG property shape that starts with register SH/SH/MGT_TOP/SH_ILA_0/inst/ila_core_inst/u_ila_reset_ctrl/asyncrounous_transfer\.arm_in_transfer_inst/dout_reg0_reg\. '), (('.*',), r'^CRITICAL WARNING: \[Constraints 18-850\] Failed to place register with ASYNC_REG property shape that starts with register SH/SH/MGT_TOP/SH_ILA_0/inst/ila_core_inst/capture_qual_ctrl_2_reg\[0\]\. '), (('.*',), r'^CRITICAL WARNING: \[Constraints 18-850\] Failed to place register with ASYNC_REG property shape that starts with register SH/SH/MGT_TOP/SH_ILA_0/inst/ila_core_inst/en_adv_trigger_2_reg\. '), + (('.*',), r'^CRITICAL WARNING: \[Shape Builder 18-850\] Failed to place register with ASYNC_REG property shape that starts with register WRAPPER_INST/SH/SH/MGT_TOP.*'), (('.*',), r'^CRITICAL WARNING: \[Vivado 12-1433\] Expecting a non-empty list of cells to be added to the pblock\. Please verify the correctness of the argument. \[/home/centos/src/project_data/workspace/test_develop_manual/hdk/cl/examples/cl_dram_dma/build/constraints/cl_pnr_user\.xdc:15'), (('.*',), r'^CRITICAL WARNING: \[filemgmt 20-1741\] File \'axi_register_slice_v2_1_vl_rfs.v\'.*'), (('.*',), r'^CRITICAL WARNING: \[filemgmt 20-1741\] File \'blk_mem_gen_v8_3_vhsyn_rfs.vhd\'.*'), @@ -87,10 +90,17 @@ def set_allowed_warnings(cls): (('.*',), r'WARNING: \[BD 41-1661\] .*'), (('.*',), r'WARNING: \[Vivado 12-584\] No ports matched \'tck\''), (('.*',), r'WARNING: \[Vivado 12-830\] No fanout objects found for'), - (('.*',), r'WARNING: \[Place 30-640\] Place Check.*'), + (('.*',), r'WARNING: \[Place 30-640\] Place Check.*'), (('.*',), r'WARNING: \[BD 41-2180\] Resetting the memory initialization file.*'), + (('.*',), r'WARNING: \[Synth 8-689\] .*'), + (('cl_sde_*',), r'WARNING: \[Vivado 12-180\] No cells matched .*'), + (('cl_sde_*',), r'WARNING: \[Vivado 12-1008\] No clocks found for command.*'), + (('cl_sde_*',), r'CRITICAL WARNING: \[Designutils 20-1280\] .*'), + (('cl_sde_*',), r'^CRITICAL WARNING: \[Constraints 18-952\] .*'), + (('cl_sde_*',), r'^CRITICAL WARNING: \[Vivado 12-1039\] .*'), + (('cl_sde_*',), r'^CRITICAL WARNING: \[Vivado 12-1433\] .*'), (('cl_dram_dma_A1_B2_C0_2_(CONGESTION|BASIC)',), r'^CRITICAL WARNING: \[Route 35-39\] The design did not meet timing requirements'), - (('cl_dram_dma_A1_B2_C0_2_(CONGESTION|TIMING)',), r'WARNING: \[Vivado 12-180\] No cells matched \'CL/CL_DMA_PCIS_SLV/CL_TST_DDR_B/CL_TST/sync_rst_n_reg\''), + (('cl_dram_dma_A1_B2_C0_2_(CONGESTION|TIMING)',), r'WARNING: \[Vivado 12-180\] No cells matched \'CL/CL_DMA_PCIS_SLV/CL_TST_DDR_B/CL_TST/sync_rst_n_reg\''), (('cl_dram_dma_*',), r'CRITICAL WARNING: \[Designutils 20-1280\] Could not find module \'bd_bf3f_microblaze_I_0\''), (('cl_dram_dma_*',), r'CRITICAL WARNING: \[Designutils 20-1280\] Could not find module \'bd_bf3f_rst_0_0\''), (('cl_dram_dma_*',), r'CRITICAL WARNING: \[Designutils 20-1280\] Could not find module \'bd_bf3f_ilmb_0\''), @@ -103,8 +113,8 @@ def set_allowed_warnings(cls): (('cl_dram_dma_*',), r'WARNING: \[Synth 8-6104\] Input port \'value\' has an internal driver .*'), (('cl_dram_dma_*',), r'WARNING: \[Vivado 12-180\] No cells matched .*'), (('cl_dram_dma_*',), r'WARNING: \[Vivado 12-1008\] No clocks found for command.*'), - (('cl_dram_dma_*',), r'WARNING: \[Memdata 28-146\] Could not find a netlist instance for the specified SCOPED_TO_REF value of: ddr4_core'), - (('cl_dram_dma_*',), r'WARNING: \[Memdata 28-146\] Could not find a netlist instance for the specified SCOPED_TO_REF value of: bd_bf3f'), + (('.*',), r'WARNING: \[Memdata 28-146\] Could not find a netlist instance for the specified SCOPED_TO_REF value of: ddr4_core'), + (('.*',), r'WARNING: \[Memdata 28-146\] Could not find a netlist instance for the specified SCOPED_TO_REF value of: bd_bf3f'), (('cl_dram_dma_*',), r'WARNING: \[Place 46-14\] The placer has determined'), (('cl_dram_dma_*',), r'WARNING: \[Synth 8-5856\]*'), (('cl_hello_world_vhdl_A.*',), r'WARNING: \[Memdata 28-146\] Could not find a netlist instance for the specified SCOPED_TO_REF value of: ddr4_core'), diff --git a/hdk/tests/test_load_afi.py b/hdk/tests/test_load_afi.py index 43ab95ed..c2d47f36 100644 --- a/hdk/tests/test_load_afi.py +++ b/hdk/tests/test_load_afi.py @@ -248,7 +248,7 @@ def check_runtime_software(self, cl, slot): assert find_fail_re.match(stdout_lines[-2]), "{} didn't fail. stdout:\n{}".format(command, "\n".join(stdout_lines)) elif re.match(r'cl_sde', cl): - (rc, stdout_lines, stderr_lines) = self.run_cmd("cd {}/hdk/cl/examples/{}/software/runtime".format( + (rc, stdout_lines, stderr_lines) = self.run_cmd("cd {}/hdk/cl/examples/{}/software/runtime && make clean && make all".format( self.WORKSPACE, cl), echo=True) assert rc == 0, "Runtime example failed." @@ -264,9 +264,12 @@ def base_test(self, cl, agfi, afi, install_xdma_driver, slots_to_test, option_ta slots_to_test = range(self.num_slots) # Make sure that the test can be built first - logger.info("Building runtime software") - (rc, stdout_lines, stderr_lines) = self.run_cmd("cd {}/hdk/cl/examples/{}/software/runtime && make -f Makefile SDK_DIR={}/sdk".format(self.WORKSPACE, cl, self.WORKSPACE)) - assert rc == 0, "Runtime software build failed." + if cl != 'cl_sde': + logger.info("Building runtime software") + (rc, stdout_lines, stderr_lines) = self.run_cmd("cd {}/hdk/cl/examples/{}/software/runtime && make -f Makefile SDK_DIR={}/sdk".format(self.WORKSPACE, cl, self.WORKSPACE)) + assert rc == 0, "Runtime software build failed." + else: + logger.info("cl_sde runtime test is app. No build needed") # Load the AFI onto all available FPGAs # This is required for the XDMA driver to correctly install for all slots @@ -294,6 +297,10 @@ def test_precompiled_cl_hello_world(self, xilinxVersion): cl = 'cl_hello_world' self.base_precompiled_test(cl, install_xdma_driver=False) + def test_precompiled_cl_sde(self, xilinxVersion): + cl = 'cl_sde' + self.base_precompiled_test(cl, install_xdma_driver=False) + @pytest.mark.parametrize("build_strategy", AwsFpgaTestBase.DCP_BUILD_STRATEGIES) @pytest.mark.parametrize("clock_recipe_c", sorted(AwsFpgaTestBase.DCP_CLOCK_RECIPES['C']['recipes'].keys())) @pytest.mark.parametrize("clock_recipe_b", sorted(AwsFpgaTestBase.DCP_CLOCK_RECIPES['B']['recipes'].keys())) diff --git a/hdk_setup.sh b/hdk_setup.sh index e3d8482c..3171c42e 100644 --- a/hdk_setup.sh +++ b/hdk_setup.sh @@ -30,18 +30,6 @@ current_dir=$(pwd) debug=0 -# This function checks if an environment module exists -# Returns 0 if it exists, and returns 1 if it doesn't -function does_module_exist() { - - output=`/usr/bin/ls /usr/local/Modules/$MODULE_VERSION/modulefiles | grep $1` - - if [[ $output == "$1" ]]; then - return 0; - else - return 1; - fi -} function usage { echo -e "USAGE: source [\$AWS_FPGA_REPO_DIR/]$script_name [-d|-debug] [-h|-help]" @@ -88,7 +76,7 @@ hdk_shell_version=$(readlink $HDK_COMMON_DIR/shell_stable) debug_msg "Checking for Vivado install:" # before going too far make sure Vivado is available -if ! is_vivado_available; then +if ! exists vivado; then err_msg "Please install/enable Vivado." err_msg " If you are using the FPGA Developer AMI then please request support." return 1 @@ -127,10 +115,7 @@ debug_msg "Done setting environment variables."; # Download correct shell DCP info_msg "Using HDK shell version $hdk_shell_version" debug_msg "Checking HDK shell's checkpoint version" -hdk_shell_s3_bucket=aws-fpga-hdk-resources -declare -a s3_hdk_ltx_files=("cl_hello_world.debug_probes.ltx" - "cl_dram_dma.debug_probes.ltx" - ) +hdk_resources_s3_bucket=aws-fpga-hdk-resources # Shell files to be downloaded declare -a s3_hdk_files=("SH_CL_BB_routed.dcp" @@ -148,13 +133,13 @@ do fi hdk_shell_dir=$HDK_SHELL_DIR/build/$sub_dir/from_aws hdk_file=$hdk_shell_dir/$shell_file - s3_shell_dir=$hdk_shell_s3_bucket/hdk/$hdk_shell_version/build/$sub_dir/from_aws + s3_shell_dir=hdk/$hdk_shell_version/build/$sub_dir/from_aws # Download the sha256 if [ ! -e $hdk_shell_dir ]; then mkdir -p $hdk_shell_dir || { err_msg "Failed to create $hdk_shell_dir"; return 2; } fi # Use curl instead of AWS CLI so that credentials aren't required. - curl -s https://s3.amazonaws.com/$s3_shell_dir/$shell_file.sha256 -o $hdk_file.sha256 || { err_msg "Failed to download HDK shell's $shell_file version from $s3_shell_dir/$shell_file.sha256 -o $hdk_file.sha256"; return 2; } + curl -s https://$hdk_resources_s3_bucket.s3.amazonaws.com/$s3_shell_dir/$shell_file.sha256 -o $hdk_file.sha256 || { err_msg "Failed to download HDK shell's $shell_file version from $s3_shell_dir/$shell_file.sha256 -o $hdk_file.sha256"; return 2; } if grep -q ' #include #include "xclfeatures.h" -#include "xclbin2.h" // originally xclbin.h +#include "xclbin.h" #include "xocl_ioctl.h" #include "xocl_exec.h" #include "xocl_xvc.h" diff --git a/sdk/tests/test_fpga_tools.py b/sdk/tests/test_fpga_tools.py index 95bbae4d..53a5805d 100644 --- a/sdk/tests/test_fpga_tools.py +++ b/sdk/tests/test_fpga_tools.py @@ -26,6 +26,7 @@ import time import traceback import ctypes +import multiprocessing.dummy try: import aws_fpga_test_utils from aws_fpga_test_utils.AwsFpgaTestBase import AwsFpgaTestBase @@ -53,6 +54,9 @@ def test_describe_local_image_slots(self): logger.info("PCI devices:\n{}".format("\n".join(self.list_pci_devices()))) + logger.info("verify that the slots are in order") + assert self.slot2device.values() == sorted(self.slot2device.values()) + (rc, stdout, stderr) = self.run_cmd("sudo fpga-describe-local-image-slots", echo=True) assert len(stdout) == self.num_slots + 1 assert len(stderr) == 1 @@ -255,3 +259,15 @@ def test_virtual_dip_switch(self): assert len(stderr) == 1 assert stdout[0] == 'FPGA slot id {} has the following Virtual DIP Switches:'.format(slot) assert stdout[1] == '1111-1111-1111-1111' + + def test_parallel_slot_loads(self): + def run_slot(slot): + for afi in [self.cl_dram_dma_agfi, self.cl_hello_world_agfi, self.cl_dram_dma_agfi]: + (rc, stdout, stderr) = self.run_cmd("sudo fpga-load-local-image -HS{} -I {}".format(slot, afi)) + assert rc == 0 + logger.info(stdout) + + + slots = range(self.num_slots) + pool = multiprocessing.dummy.Pool(len(slots)) + pool.map(run_slot, slots) diff --git a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c index 87110d4c..5eba76c1 100644 --- a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c +++ b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt.c @@ -37,11 +37,21 @@ int fpga_mgmt_init(void) for (unsigned int i = 0; i < sizeof_array(fpga_mgmt_state.slots); ++i) { fpga_mgmt_state.slots[i].handle = PCI_BAR_HANDLE_INIT; } + fpga_mgmt_state.initialized = true; return fpga_pci_init(); } int fpga_mgmt_close(void) { + if (!fpga_mgmt_state.initialized) { + return FPGA_ERR_OK; + } + fpga_mgmt_state.initialized = false; + for (unsigned int i = 0; i < sizeof_array(fpga_mgmt_state.slots); ++i) { + if (fpga_mgmt_state.slots[i].handle != PCI_BAR_HANDLE_INIT) { + fpga_mgmt_mbox_detach(i); + } + } return FPGA_ERR_OK; } @@ -75,14 +85,10 @@ int fpga_mgmt_get_sh_version(int slot_id, uint32_t *sh_version) *sh_version = ver.sh_version; err: - if (handle != PCI_BAR_HANDLE_INIT) { - fpga_mgmt_mbox_detach(slot_id); - } - return ret; } -int fpga_mgmt_describe_local_image(int slot_id, +static int fpga_mgmt_describe_cmd(int slot_id, struct fpga_mgmt_image_info *info, uint32_t flags) { int ret; @@ -125,9 +131,6 @@ int fpga_mgmt_describe_local_image(int slot_id, fail_on(ret, out, "fpga_mgmt_get_sh_version failed"); info->sh_version = sh_version; - ret = fpga_pci_get_slot_spec(slot_id, &info->spec); - fail_on(ret, out, "fpga_pci_get_slot_spec failed"); - /* copy the metrics into the out param */ info->metrics = metrics->fmc; @@ -135,11 +138,34 @@ int fpga_mgmt_describe_local_image(int slot_id, return ret; } +int fpga_mgmt_describe_local_image(int slot_id, + struct fpga_mgmt_image_info *info, uint32_t flags) +{ + int ret; + + fail_on_with_code(!fpga_mgmt_state.initialized, out, ret, + FPGA_ERR_SOFTWARE_PROBLEM, + "fpga_mgmt_init must be called before the library can be used"); + + ret = fpga_mgmt_describe_cmd(slot_id, info, flags); + fail_on(ret, out, "fpga_mgmt_describe_cmd"); + + ret = fpga_pci_get_slot_spec(slot_id, &info->spec); + fail_on(ret, out, "fpga_pci_get_slot_spec failed"); + +out: + return ret; +} + int fpga_mgmt_get_status(int slot_id, int *status, int *status_q) { int ret; struct fpga_mgmt_image_info info; + fail_on_with_code(!fpga_mgmt_state.initialized, out, ret, + FPGA_ERR_SOFTWARE_PROBLEM, + "fpga_mgmt_init must be called before the library can be used"); + fail_slot_id(slot_id, out, ret); if (!status) { @@ -268,6 +294,10 @@ int fpga_mgmt_clear_local_image(int slot_id) union afi_cmd cmd; union afi_cmd rsp; + fail_on_with_code(!fpga_mgmt_state.initialized, out, ret, + FPGA_ERR_SOFTWARE_PROBLEM, + "fpga_mgmt_init must be called before the library can be used"); + fail_slot_id(slot_id, out, ret); memset(&cmd, 0, sizeof(union afi_cmd)); @@ -298,12 +328,18 @@ int fpga_mgmt_clear_local_image_sync(int slot_id, int status; int ret; + fail_on_with_code(!fpga_mgmt_state.initialized, out, ret, + FPGA_ERR_SOFTWARE_PROBLEM, + "fpga_mgmt_init must be called before the library can be used"); + /** Allow timeout adjustments that are greater than the defaults */ uint32_t timeout_tmp = (timeout > FPGA_MGMT_SYNC_TIMEOUT) ? timeout : FPGA_MGMT_SYNC_TIMEOUT; uint32_t delay_msec_tmp = (delay_msec > FPGA_MGMT_SYNC_DELAY_MSEC) ? delay_msec : FPGA_MGMT_SYNC_DELAY_MSEC; + fail_on_with_code(slot_id >= FPGA_SLOT_MAX, out, ret, -EINVAL, "invalid slot"); + memset(&tmp_info, 0, sizeof(tmp_info)); /** @@ -322,7 +358,7 @@ int fpga_mgmt_clear_local_image_sync(int slot_id, /** Wait until the status is "cleared" or timeout */ while (!done) { - ret = fpga_mgmt_describe_local_image(slot_id, &tmp_info, 0); /** flags==0 */ + ret = fpga_mgmt_describe_cmd(slot_id, &tmp_info, 0); /** flags==0 */ status = (ret == 0) ? tmp_info.status : FPGA_STATUS_END; if (status == FPGA_STATUS_CLEARED) { @@ -373,6 +409,10 @@ int fpga_mgmt_clear_local_image_sync(int slot_id, fail_on(ret, out, "fpga_pci_rescan_slot_app_pfs failed"); } + /* now fill in the slot spec information after the rescan */ + ret = fpga_pci_get_slot_spec(slot_id, &tmp_info.spec); + fail_on(ret, out, "fpga_pci_get_slot_spec failed"); + if (info) { *info = tmp_info; } @@ -408,6 +448,10 @@ int fpga_mgmt_load_local_image_with_options(union fpga_mgmt_load_local_image_opt union afi_cmd cmd; union afi_cmd rsp; + fail_on_with_code(!fpga_mgmt_state.initialized, out, ret, + FPGA_ERR_SOFTWARE_PROBLEM, + "fpga_mgmt_init must be called before the library can be used"); + fail_slot_id(opt->slot_id, out, ret); memset(&cmd, 0, sizeof(union afi_cmd)); @@ -463,12 +507,18 @@ int fpga_mgmt_load_local_image_sync_with_options(union fpga_mgmt_load_local_imag int status; int ret; + fail_on_with_code(!fpga_mgmt_state.initialized, out, ret, + FPGA_ERR_SOFTWARE_PROBLEM, + "fpga_mgmt_init must be called before the library can be used"); + /** Allow timeout adjustments that are greater than the defaults */ uint32_t timeout_tmp = (timeout > FPGA_MGMT_SYNC_TIMEOUT) ? timeout : FPGA_MGMT_SYNC_TIMEOUT; uint32_t delay_msec_tmp = (delay_msec > FPGA_MGMT_SYNC_DELAY_MSEC) ? delay_msec : FPGA_MGMT_SYNC_DELAY_MSEC; + fail_on_with_code(opt->slot_id >= FPGA_SLOT_MAX, out, ret, -EINVAL, "invalid slot"); + memset(&tmp_info, 0, sizeof(tmp_info)); /** @@ -487,7 +537,7 @@ int fpga_mgmt_load_local_image_sync_with_options(union fpga_mgmt_load_local_imag /** Wait until the status is "loaded" or timeout */ while (!done) { - ret = fpga_mgmt_describe_local_image(opt->slot_id, &tmp_info, 0); /** flags==0 */ + ret = fpga_mgmt_describe_cmd(opt->slot_id, &tmp_info, 0); /** flags==0 */ status = (ret == 0) ? tmp_info.status : FPGA_STATUS_END; if (status == FPGA_STATUS_LOADED) { @@ -543,6 +593,10 @@ int fpga_mgmt_load_local_image_sync_with_options(union fpga_mgmt_load_local_imag fail_on(ret, out, "fpga_pci_rescan_slot_app_pfs failed"); } + /* now fill in the slot spec information after the rescan */ + ret = fpga_pci_get_slot_spec(opt->slot_id, &tmp_info.spec); + fail_on(ret, out, "fpga_pci_get_slot_spec failed"); + if (info) { *info = tmp_info; } diff --git a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c index acdc5155..d5b59bad 100644 --- a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c +++ b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_cmd.c @@ -249,22 +249,26 @@ fpga_mgmt_mbox_attach(int slot_id) int ret; pci_bar_handle_t handle; - ret = fpga_pci_attach(slot_id, - FPGA_MGMT_PF, - F1_MBOX_RESOURCE_NUM, - 0 /* flags */, - &handle); - fail_on(ret != 0, err, "Unable to attach to mbox bar"); - - fpga_mgmt_state.slots[slot_id].handle = handle; - - struct fpga_hal_mbox mbox = { - .timeout = fpga_mgmt_state.timeout, - .delay_msec = fpga_mgmt_state.delay_msec, - }; - - ret = fpga_hal_mbox_init(&mbox); - fail_on(ret != 0, err, "fpga_hal_mbox_init failed"); + if (fpga_mgmt_state.slots[slot_id].handle == PCI_BAR_HANDLE_INIT) { + ret = fpga_pci_attach(slot_id, + FPGA_MGMT_PF, + F1_MBOX_RESOURCE_NUM, + 0 /* flags */, + &handle); + fail_on(ret != 0, err, "Unable to attach to mbox bar"); + + fpga_mgmt_state.slots[slot_id].handle = handle; + + struct fpga_hal_mbox mbox = { + .timeout = fpga_mgmt_state.timeout, + .delay_msec = fpga_mgmt_state.delay_msec, + }; + + ret = fpga_hal_mbox_init(&mbox); + fail_on(ret != 0, err, "fpga_hal_mbox_init failed"); + } else { + handle = fpga_mgmt_state.slots[slot_id].handle; + } ret = fpga_hal_mbox_attach(handle, true); /**< clear_state=true */ fail_on(ret != 0, err, "fpga_hal_mbox_attach failed"); @@ -449,7 +453,6 @@ int fpga_mgmt_process_cmd(int slot_id, const union afi_cmd *cmd, union afi_cmd *rsp, uint32_t *len) { - bool attached = false; int ret; fail_slot_id(slot_id, err, ret); @@ -457,14 +460,8 @@ fpga_mgmt_process_cmd(int slot_id, ret = fpga_mgmt_mbox_attach(slot_id); fail_on(ret, err, "fpga_mgmt_mbox_attach failed"); - attached = true; - ret = fpga_mgmt_send_cmd(slot_id, cmd, rsp, len); fail_on(ret, err, "fpga_mgmt_send_cmd failed"); err: - if (attached) { - fpga_mgmt_mbox_detach(slot_id); - } - return ret; } diff --git a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_internal.h b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_internal.h index bf5aaa13..0469891c 100644 --- a/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_internal.h +++ b/sdk/userspace/fpga_libs/fpga_mgmt/fpga_mgmt_internal.h @@ -13,6 +13,14 @@ * permissions and limitations under the License. */ +#pragma once + +#include + +#include "afi_cmd_api.h" +#include "hal/fpga_common.h" +#include "fpga_pci.h" + /** * Default timeout: * CLI_TIMEOUT_DFLT * CLI_DELAY_MSEC_DFLT @@ -40,6 +48,7 @@ extern struct fgpa_mgmt_state_s { } slots[FPGA_SLOT_MAX]; uint32_t timeout; uint32_t delay_msec; + bool initialized; } fpga_mgmt_state; // FIXME diff --git a/sdk/userspace/fpga_libs/fpga_pci/fpga_pci_sysfs.c b/sdk/userspace/fpga_libs/fpga_pci/fpga_pci_sysfs.c index ef3829e2..0e3f32a6 100644 --- a/sdk/userspace/fpga_libs/fpga_pci/fpga_pci_sysfs.c +++ b/sdk/userspace/fpga_libs/fpga_pci/fpga_pci_sysfs.c @@ -419,8 +419,43 @@ int fpga_release_readdir_lock() { #endif } -int -fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) +static inline bool fpga_slot_spec_is_initialized(struct fpga_slot_spec *spec) +{ + struct fpga_pci_resource_map *map = &spec->map[FPGA_MGMT_PF]; + return !(map->domain == 0 && map->bus == 0 && + map->dev == 0 && map->func == 0); +} + + +static int +fpga_pci_slot_spec_compare(const void *a, const void *b) +{ + struct fpga_slot_spec *spec_a = (*((struct fpga_slot_spec **)a)); + struct fpga_slot_spec *spec_b = (*((struct fpga_slot_spec **)b)); + + int test; + + /* make sure than uninitialized entries fall to the bottom of the list */ + bool a_initialized = fpga_slot_spec_is_initialized(spec_a); + bool b_initialized = fpga_slot_spec_is_initialized(spec_b); + if (a_initialized != b_initialized) { + return (a_initialized) ? -1 : 1; + } + + test = spec_a->map[FPGA_MGMT_PF].domain - spec_b->map[FPGA_MGMT_PF].domain; + if (test != 0) return test; + + test = spec_a->map[FPGA_MGMT_PF].bus - spec_b->map[FPGA_MGMT_PF].bus; + if (test != 0) return test; + + test = spec_a->map[FPGA_MGMT_PF].dev - spec_b->map[FPGA_MGMT_PF].dev; + if (test != 0) return test; + + return spec_a->map[FPGA_MGMT_PF].func - spec_b->map[FPGA_MGMT_PF].func; +} + +static int +fpga_pci_mbox_scan(struct fpga_slot_spec spec_array_out[], int size) { int ret; bool found_afi_slot = false; @@ -434,7 +469,7 @@ fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) entry = &entry_stack; memset(entry, 0, sizeof(struct dirent)); #else - /** + /* * Protect calls to readdir with a mutex because multiple threads may call * this function, which always reads from the same directory. The man page * for readdir says the POSIX spec does not require threadsafety. @@ -442,21 +477,22 @@ fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) fpga_acquire_readdir_lock(); #endif - int slot_dev_index = 0; - struct fpga_slot_spec search_spec; - struct fpga_pci_resource_map search_map, app_map; - char app_dir_name[NAME_MAX + 1]; + unsigned int slot_dev_index = 0; + struct fpga_pci_resource_map search_map; - memset(&search_spec, 0, sizeof(struct fpga_slot_spec)); + /* allocate space for sorting the spec_array */ + struct fpga_slot_spec *spec_array[FPGA_SLOT_MAX]; + struct fpga_slot_spec spec_array_storage[FPGA_SLOT_MAX]; + memset(spec_array_storage, 0, sizeof(spec_array_storage)); + for (int i = 0; i < FPGA_SLOT_MAX; ++i) { + spec_array[i] = &spec_array_storage[i]; + } - /** - * Loop through the sysfs device directories + /* + * Loop through the sysfs device directories * -we first find the mbox dev then handle the app dev as a fixed * mapping based off of the mbox dev's pci resource map * (see fpga_pci_mbox2app). - * -this approach is simple and more efficient than the - * alternative of requiring an additional sort of the dirent entries by - * the PCI device number (DBDF). */ while (true) { @@ -488,23 +524,11 @@ fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) ret = fpga_pci_get_resources(entry->d_name, &search_map); fail_on(ret != 0, err_unlock, "Error retrieving resource information"); - /* app resources */ - memset(&app_map, 0, sizeof(struct fpga_pci_resource_map)); - app_dir_name[0] = 0; - ret = fpga_pci_mbox2app(&search_map, &app_map, - app_dir_name, sizeof(app_dir_name)); - fail_on(ret != 0, err_unlock, "Error retrieving app pf information"); - - ret = fpga_pci_get_resources(app_dir_name, &app_map); - fail_on(ret != 0, err_unlock, "Error retrieving resource information"); - /* copy the results into the spec_array */ - spec_array[slot_dev_index].map[FPGA_APP_PF] = app_map; - spec_array[slot_dev_index].map[FPGA_MGMT_PF] = search_map; - + spec_array[slot_dev_index]->map[FPGA_MGMT_PF] = search_map; found_afi_slot = true; slot_dev_index += 1; - if (slot_dev_index >= size) { + if (slot_dev_index >= sizeof_array(spec_array)) { break; } } @@ -517,6 +541,13 @@ fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) closedir(dirp); + /* sort the spec_array and copy it into the out parameter */ + qsort(spec_array, sizeof_array(spec_array), sizeof(spec_array[0]), + fpga_pci_slot_spec_compare); + for (unsigned int i = 0; i < min((unsigned) size, sizeof_array(spec_array)); ++i) { + spec_array_out[i] = *spec_array[i]; + } + errno = 0; return 0; @@ -533,6 +564,56 @@ fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) return ret; } +/** + * Fill in the application PF information in a slot spec which already + * has the mailbox PF initialized. + */ +static int +fpga_pci_complete_slot_spec(struct fpga_slot_spec *spec) +{ + int ret; + char app_dir_name[NAME_MAX + 1]; + struct fpga_pci_resource_map app_map; + + /* fill in app resources */ + memset(&app_map, 0, sizeof(struct fpga_pci_resource_map)); + app_dir_name[0] = 0; + ret = fpga_pci_mbox2app(&spec->map[FPGA_MGMT_PF], &app_map, + app_dir_name, sizeof(app_dir_name)); + fail_on(ret != 0, out, "Error retrieving app pf information"); + + ret = fpga_pci_get_resources(app_dir_name, &app_map); + fail_on(ret != 0, out, "Error retrieving resource information"); + + /* copy the results into the spec_array */ + spec->map[FPGA_APP_PF] = app_map; + +out: + return ret; +} + +int +fpga_pci_get_all_slot_specs(struct fpga_slot_spec spec_array[], int size) +{ + int rc; + + rc = fpga_pci_mbox_scan(spec_array, size); + fail_on(rc, out, "failed to enumerate FPGA slots"); + + for (int i = 0; i < size; ++i) { + /* after encountering the first empty slot, stop iterating */ + if (!fpga_slot_spec_is_initialized(&spec_array[i])) { + break; + } + /* fill in app resources */ + rc = fpga_pci_complete_slot_spec(&spec_array[i]); + fail_on(rc, out, "unabled to get APP PF info for slot %d", i); + } + +out: + return rc; +} + int fpga_pci_get_slot_spec(int slot_id, struct fpga_slot_spec *spec) { @@ -548,10 +629,14 @@ fpga_pci_get_slot_spec(int slot_id, struct fpga_slot_spec *spec) /* tell fpga_pci_get_all_slot_specs not to search past the slot number */ size = min(sizeof_array(spec_array), (unsigned) slot_id + 1); - ret = fpga_pci_get_all_slot_specs(spec_array, size); - fail_on(ret, err, "Unable to read PCI device information."); - if (spec_array[slot_id].map[FPGA_APP_PF].vendor_id == 0) { + ret = fpga_pci_mbox_scan(spec_array, size); + fail_on(ret, err, "failed to enumerate FPGA slots"); + + ret = fpga_pci_complete_slot_spec(&spec_array[slot_id]); + fail_on(ret, err, "unabled to get APP PF info for slot %d", slot_id); + + if (!fpga_slot_spec_is_initialized(&spec_array[slot_id])) { log_error("No device matching specified id: %d", slot_id); return -ENOENT; } diff --git a/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.c b/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.c index 1b51a6d5..a68db443 100644 --- a/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.c +++ b/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.c @@ -27,6 +27,8 @@ #include #include +#include + #include #include @@ -640,7 +642,7 @@ main(int argc, char *argv[]) int ret = cli_create(); fail_on(ret != 0, err, "cli_create failed"); - ret = log_init("fpga-local-cmd"); + ret = log_init("fpga-local-cmd(%u)", getpid()); fail_on(ret != 0, err, "log_init failed"); ret = log_attach(logger, NULL, 0); diff --git a/shared/bin/set_common_functions.sh b/shared/bin/set_common_functions.sh index 519b5e83..5d31ee34 100644 --- a/shared/bin/set_common_functions.sh +++ b/shared/bin/set_common_functions.sh @@ -41,12 +41,13 @@ function is_myvivado_set { fi } - -function is_vivado_available { - if ! vivado -version > /dev/null 2>&1 ; then - false +# Function to check whether a command exists. +exists() { + if command -v $1 >/dev/null 2>&1 + then + return 0 else - true + return 1 fi } diff --git a/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py b/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py index 3fe20875..c2183725 100644 --- a/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py +++ b/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py @@ -66,6 +66,7 @@ class AwsFpgaTestBase(object): git_repo_dir = get_git_repo_root(dirname(__file__)) WORKSPACE = git_repo_dir + ADD_BATCH = False ADD_SIMULATOR = False ADD_EXAMPLEPATH = False ADD_RTENAME = False diff --git a/shared/tests/bin/setup_test_env.sh b/shared/tests/bin/setup_test_env.sh index fdfb8af9..2668c68f 100644 --- a/shared/tests/bin/setup_test_env.sh +++ b/shared/tests/bin/setup_test_env.sh @@ -27,7 +27,7 @@ full_script=$(readlink -f $script) script_name=$(basename $full_script) script_dir=$(dirname $full_script) -python_versions=(2.7 3.4) +python_versions=(2.7 3.6) python_packages=(\ pytest \ @@ -53,13 +53,12 @@ for python_version in ${python_versions[@]}; do echo "error: Install of $yum_pip_package failed" return 1 fi - sudo $pip install --upgrade pip fi for p in ${python_packages[@]}; do if ! $pip show $p > /dev/null; then echo "Installing $p" - if ! sudo $pip install $p; then + if ! $pip install --user $p; then echo "error: Install of $python $p failed" return 1 fi diff --git a/shared/tests/bin/setup_test_env_al2.sh b/shared/tests/bin/setup_test_env_al2.sh index 0323a458..1004e667 100644 --- a/shared/tests/bin/setup_test_env_al2.sh +++ b/shared/tests/bin/setup_test_env_al2.sh @@ -55,13 +55,12 @@ for python_version in ${python_versions[@]}; do echo "error: Install of $yum_pip_package failed" return 1 fi - sudo $pip install --upgrade pip fi for p in ${python_packages[@]}; do if ! $pip show $p > /dev/null; then echo "Installing $p" - if ! sudo $pip install $p; then + if ! $pip install --user $p; then echo "error: Install of $python $p failed" return 1 fi diff --git a/shared/tests/bin/setup_test_xrtpatch.sh b/shared/tests/bin/setup_test_xrtpatch.sh index 5881917e..07fd9e80 100644 --- a/shared/tests/bin/setup_test_xrtpatch.sh +++ b/shared/tests/bin/setup_test_xrtpatch.sh @@ -28,13 +28,6 @@ script_name=$(basename $full_script) script_dir=$(dirname $full_script) s3_ami_bucket=aws-fpga-developer-ami -s3_ami_version=1.5.0 -xrt_release_version=XRT_2018_2_XDF_RC5 -xrt_rpm_name=xrt_201802.2.1.0_7.5.1804-xrt.rpm -aws_xrt_rpm_name=xrt_201802.2.1.0_7.5.1804-aws.rpm - -xrt_rpm_path=$s3_ami_bucket/$s3_ami_version/Patches/$xrt_release_version/$xrt_rpm_name -aws_xrt_rpm_path=$s3_ami_bucket/$s3_ami_version/Patches/$xrt_release_version/$aws_xrt_rpm_name VIVADO_TOOL_VERSION=`vivado -version | grep Vivado | head -1 | sed 's:Vivado *::' | sed 's: .*$::' | sed 's:v::'` export VIVADO_TOOL_VERSION=${VIVADO_TOOL_VERSION:0:6} @@ -44,6 +37,14 @@ echo "VIVADO_TOOL_VERSION is $VIVADO_TOOL_VERSION" if [[ "$VIVADO_TOOL_VERSION" =~ .*2018\.2.* ]]; then echo "Xilinx Vivado version is 2018.2" + s3_ami_version=1.5.0 + xrt_release_version=XRT_2018_2_XDF_RC5 + xrt_rpm_name=xrt_201802.2.1.0_7.5.1804-xrt.rpm + aws_xrt_rpm_name=xrt_201802.2.1.0_7.5.1804-aws.rpm + + xrt_rpm_path=$s3_ami_bucket/$s3_ami_version/Patches/$xrt_release_version/$xrt_rpm_name + aws_xrt_rpm_path=$s3_ami_bucket/$s3_ami_version/Patches/$xrt_release_version/$aws_xrt_rpm_name + if [ -f "/opt/xilinx/xrt/include/version.h" ]; then echo "XRT installed. proceeding to check version compatibility" xrt_build_ver=$(grep 'xrt_build_version_hash\[\]' /opt/xilinx/xrt/include/version.h | sed 's/";//' | sed 's/^.*"//') @@ -70,6 +71,43 @@ if [[ "$VIVADO_TOOL_VERSION" =~ .*2018\.2.* ]]; then sudo yum install -y $aws_xrt_rpm_name echo " XRT patch aws rpm installed successfully" fi +elif [[ "$VIVADO_TOOL_VERSION" =~ .*2018\.3.* ]]; then + echo "Xilinx Vivado version is 2018.3" + + s3_ami_version=1.6.0 + xrt_release_version=XRT_2018_3_RC3_Patch2 + xrt_rpm_name=xrt_201830.2.1.0_7.6.1810-xrt.rpm + aws_xrt_rpm_name=xrt_201830.2.1.0_7.6.1810-aws.rpm + + xrt_rpm_path=$s3_ami_bucket/$s3_ami_version/Patches/$xrt_release_version/$xrt_rpm_name + aws_xrt_rpm_path=$s3_ami_bucket/$s3_ami_version/Patches/$xrt_release_version/$aws_xrt_rpm_name + + if [ -f "/opt/xilinx/xrt/include/version.h" ]; then + echo "XRT installed. proceeding to check version compatibility" + xrt_build_ver=$(grep 'xrt_build_version_hash\[\]' /opt/xilinx/xrt/include/version.h | sed 's/";//' | sed 's/^.*"//') + echo "Installed XRT version hash : $xrt_build_ver" + if grep -Fxq "$xrt_build_ver" $AWS_FPGA_REPO_DIR/SDAccel/sdaccel_xrt_version.txt + then + echo "XRT version $xrt_build_ver is up-to-date." + else + echo "$xrt_build_ver is stale. upgrading XRT to" + cat $AWS_FPGA_REPO_DIR/SDAccel/sdaccel_xrt_version.txt + curl -s https://s3.amazonaws.com/$xrt_rpm_path -o $xrt_rpm_name || { echo " Error: Failed to download xrt rpm from $xrt_rpm_path"; return 2; } + curl -s https://s3.amazonaws.com/$aws_xrt_rpm_path -o $aws_xrt_rpm_name || { echo " Error: Failed to download aws xrt rpm from $aws_xrt_rpm_path"; return 2; } + sudo yum reinstall -y $xrt_rpm_name + echo " XRT patch rpm installed successfully" + sudo yum reinstall -y $aws_xrt_rpm_name + echo " XRT patch aws rpm installed successfully" + fi + else + echo "XRT not installed. Please install XRT" + curl -s https://s3.amazonaws.com/$xrt_rpm_path -o $xrt_rpm_name || { echo " Error: Failed to download xrt rpm from $xrt_rpm_path"; return 2; } + curl -s https://s3.amazonaws.com/$aws_xrt_rpm_path -o $aws_xrt_rpm_name || { echo " Error: Failed to download aws xrt rpm from $aws_xrt_rpm_path"; return 2; } + sudo yum reinstall -y $xrt_rpm_name + echo " XRT patch rpm installed successfully" + sudo yum install -y $aws_xrt_rpm_name + echo " XRT patch aws rpm installed successfully" + fi else echo "Xilinx Vivado version is $VIVADO_TOOL_VERSION . Proceeding with base runtime version " fi From 099d4898d1a8c5a9f23c1053eb1a8071ffb6d1a5 Mon Sep 17 00:00:00 2001 From: Deep Patel Date: Thu, 19 Sep 2019 20:11:15 -0500 Subject: [PATCH 04/31] RC 1.4.11 (#464) Release 1.4.11 * FPGA developer kit now supports Xilinx SDx/Vivado 2019.1 * To upgrade, use Developer AMI v1.7.0 on the AWS Marketplace. The Developer Kit scripts (hdk_setup.sh or sdaccel_setup.sh) will detect the tool version and update the environment based on requirements needed for Xilinx 2019.1 tools. * New functionality: * Added a developer resources section that provides guides on how to setup your own GUI Desktop and compute cluster environment. * Developers can now ask for AFI limit increases via the AWS Support Center Console * Create a case to increase your `EC2 FPGA` service limit from the console. * HLx IPI flow updates * HLx support for AXI Fast Memory mode. * HLx support for 3rd party simulations. * HLx support for changes in shell and AWS IP updates(e.g. sh_ddr). * Bug Fixes: * Documentation fixes in the Shell Interface Specification * Fixes for forum questions * Unable to compile aws_v1_0_vl_rfs.sv in Synopsys VCS * Use fpga_mgmt init in HLx runtime * New XRT versions added to the XRT Installation Instructions to fix segmentation faults when using xclbin instead of awsxclbin files. * Deprecations: * Removed GUI Setup scripts from AMI v1.7.0 onwards. --- .gitmodules | 3 + ERRATA.md | 9 + FAQs.md | 119 +- Jenkinsfile | 140 +- Jenkinsfile_int_sims | 813 +---- README.md | 24 +- RELEASE_NOTES.md | 36 +- SDAccel/FAQ.md | 53 +- SDAccel/README.md | 13 +- SDAccel/docs/Create_Runtime_AMI.md | 27 +- SDAccel/docs/README_GUI.md | 2 +- SDAccel/docs/SDAccel_Guide_AWS_F1.md | 51 +- SDAccel/docs/SDAccel_HLS_Debug.md | 2 +- SDAccel/docs/SDAccel_Migrate_dynamic_DSA.md | 2 +- SDAccel/docs/Setup_AWS_CLI_and_S3_Bucket.md | 4 +- SDAccel/docs/XRT_installation_instructions.md | 184 +- .../vector_addition_main.cpp.diff | 45 +- .../{2018.3 => 2018.3_2019.1}/helloworld | Bin .../helloworld_ocl_afi-ids.txt | 0 .../helloworld_ocl_agfi-ids.txt | 0 .../{2018.3 => 2018.3_2019.1}/sdaccel.ini | 0 ...aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin | Bin .../aws/helloworld_ocl_runtime/README.md | 14 +- SDAccel/examples/xilinx_2019.1 | 1 + SDAccel/kernel_version.txt | 1 + SDAccel/sdaccel_xrt_version.txt | 6 +- SDAccel/tests/test_find_sdaccel_examples.py | 27 +- SDAccel/tests/test_run_sdaccel_example.py | 3 +- developer_resources/DCV.md | 126 + .../DCV_with_ParallelCluster.md | 457 +++ developer_resources/README.md | 15 + .../images/Continue_to_Subscribe.png | Bin 0 -> 58123 bytes developer_resources/images/Launch_on_AWS.png | Bin 0 -> 12864 bytes .../images/capabilities_checkbox.png | Bin 0 -> 40732 bytes developer_resources/images/dcv_desktop.png | Bin 0 -> 709382 bytes developer_resources/images/dcv_login.png | Bin 0 -> 17974 bytes developer_resources/images/stack_details.png | Bin 0 -> 256019 bytes .../images/vivado_dcv_diagram.png | Bin 0 -> 395275 bytes developer_resources/images/vivado_launch.png | Bin 0 -> 145888 bytes developer_resources/images/vivado_startup.png | Bin 0 -> 296078 bytes hdk/README.md | 13 +- .../cl_dram_dma/verif/scripts/Makefile.ies | 2 +- .../cl_dram_dma/verif/scripts/Makefile.questa | 6 + .../cl_dram_dma/verif/scripts/Makefile.vcs | 4 +- .../software/runtime/test_hello_world.c | 2 +- .../cl_hello_world/verif/scripts/Makefile.ies | 2 +- .../verif/scripts/Makefile.questa | 6 + .../cl_hello_world/verif/scripts/Makefile.vcs | 4 +- .../verif/scripts/Makefile.questa | 2 + .../verif/scripts/Makefile.vcs | 4 +- .../cl_sde/verif/scripts/Makefile.ies | 2 +- .../cl_sde/verif/scripts/Makefile.questa | 6 + .../cl_sde/verif/scripts/Makefile.vcs | 4 +- .../verif/scripts/Makefile.ies | 2 +- .../verif/scripts/Makefile.questa | 6 + .../verif/scripts/Makefile.vcs | 4 +- hdk/cl/examples/hello_world_hlx/README.md | 1 + .../hlx/design/ip/aws_v1_0/component.xml | 108 +- .../ip/aws_v1_0/doc/aws_v1_0_changelog.txt | 3 +- .../design/ip/aws_v1_0/hdl/aws_v1_0_top.sv | 1006 ++++++ .../design/ip/aws_v1_0/hdl/aws_v1_0_vl_rfs.sv | 3076 ---------------- .../ip/aws_v1_0/hdl/aws_v1_0_vlsyn_rfs.sv | 3099 ----------------- .../hlx/design/ip/aws_v1_0/hdl/lib_pipe.sv | 1 + .../hlx/design/ip/aws_v1_0/hdl/sim | 1 + .../hlx/design/ip/aws_v1_0/hdl/sim/gray.inc | 54 - .../hlx/design/ip/aws_v1_0/hdl/synth | 1 + .../hlx/design/ip/aws_v1_0/hdl/synth/gray.inc | 61 - .../build/IPI/cl_hls_dds/software/test_cl.c | 4 +- .../IPI/cl_ipi_cdma_test/software/test_cl.c | 6 +- .../build/IPI/hello_world/software/test_cl.c | 9 +- hdk/docs/AFI_Manifest.md | 1 + hdk/docs/AWS_Shell_Interface_Specification.md | 3 +- hdk/docs/IPI_GUI_Vivado_Setup.md | 2 +- hdk/docs/RTL_Simulating_CL_Designs.md | 12 +- hdk/docs/on_premise_licensing_help.md | 8 + hdk/hdk_version.txt | 2 +- hdk/tests/test_gen_dcp.py | 3 + hdk/tests/test_hdk_scripts.py | 6 - sdaccel_runtime_setup.sh | 21 +- sdaccel_setup.sh | 6 +- sdk/linux_kernel_drivers/xdma/xdma_install.md | 2 +- sdk/tests/test_fpga_tools.py | 8 + sdk/tests/test_non_root_access.py | 4 +- sdk/tests/test_sdk_scripts.py | 7 +- sdk/userspace/fpga_mgmt_tools/README.md | 2 +- sdk/userspace/install_fpga_mgmt_tools.sh | 1 + .../aws_fpga_test_utils/AwsFpgaTestBase.py | 17 +- shared/lib/check_src_headers.py | 6 +- shared/tests/bin/install_python_venv.sh | 89 + shared/tests/bin/requirements.txt | 6 + shared/tests/bin/setup_test_env.sh | 46 +- shared/tests/bin/setup_test_env_al2.sh | 77 - .../bin/setup_test_runtime_sdaccel_env.sh | 2 + shared/tests/bin/setup_test_sdk_env.sh | 14 +- shared/tests/bin/setup_test_sdk_env_al2.sh | 43 - shared/tests/bin/setup_test_xrtpatch.sh | 2 +- supported_vivado_versions.txt | 2 + 97 files changed, 2372 insertions(+), 7696 deletions(-) rename SDAccel/examples/aws/helloworld_ocl_runtime/{2018.3 => 2018.3_2019.1}/helloworld (100%) rename SDAccel/examples/aws/helloworld_ocl_runtime/{2018.3 => 2018.3_2019.1}/helloworld_ocl_afi-ids.txt (100%) rename SDAccel/examples/aws/helloworld_ocl_runtime/{2018.3 => 2018.3_2019.1}/helloworld_ocl_agfi-ids.txt (100%) rename SDAccel/examples/aws/helloworld_ocl_runtime/{2018.3 => 2018.3_2019.1}/sdaccel.ini (100%) rename SDAccel/examples/aws/helloworld_ocl_runtime/{2018.3 => 2018.3_2019.1}/vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin (100%) create mode 160000 SDAccel/examples/xilinx_2019.1 create mode 100644 developer_resources/DCV.md create mode 100644 developer_resources/DCV_with_ParallelCluster.md create mode 100644 developer_resources/README.md create mode 100644 developer_resources/images/Continue_to_Subscribe.png create mode 100644 developer_resources/images/Launch_on_AWS.png create mode 100644 developer_resources/images/capabilities_checkbox.png create mode 100644 developer_resources/images/dcv_desktop.png create mode 100644 developer_resources/images/dcv_login.png create mode 100644 developer_resources/images/stack_details.png create mode 100644 developer_resources/images/vivado_dcv_diagram.png create mode 100644 developer_resources/images/vivado_launch.png create mode 100644 developer_resources/images/vivado_startup.png mode change 100755 => 100644 hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/component.xml mode change 100755 => 100644 hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/doc/aws_v1_0_changelog.txt create mode 100644 hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/aws_v1_0_top.sv delete mode 100755 hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/aws_v1_0_vl_rfs.sv delete mode 100755 hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/aws_v1_0_vlsyn_rfs.sv create mode 120000 hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/lib_pipe.sv create mode 120000 hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/sim delete mode 100755 hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/sim/gray.inc create mode 120000 hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/synth delete mode 100755 hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/synth/gray.inc create mode 100755 shared/tests/bin/install_python_venv.sh create mode 100644 shared/tests/bin/requirements.txt delete mode 100644 shared/tests/bin/setup_test_env_al2.sh delete mode 100644 shared/tests/bin/setup_test_sdk_env_al2.sh diff --git a/.gitmodules b/.gitmodules index a31a1562..7c5393bd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ path = SDAccel/examples/xilinx_2018.3 url = https://github.com/Xilinx/SDAccel_Examples.git branch = master +[submodule "SDAccel/examples/xilinx_2019.1"] + path = SDAccel/examples/xilinx_2019.1 + url = https://github.com/Xilinx/SDAccel_Examples.git diff --git a/ERRATA.md b/ERRATA.md index fc379d81..6bf60595 100644 --- a/ERRATA.md +++ b/ERRATA.md @@ -9,6 +9,15 @@ * DRAM Data retention is not supported for CL designs with less than 4 DDRs enabled * Combinatorial loops in CL designs are not supported. +### 2019.1 +* Vivado `compile_simlib` command fails to generate the following verilog IP libraries for the following simulators. + +| Library(verilog) | Simulator | +|---|---| +| `sync_ip` | Cadence IES | +| `hdmi_gt_controller_v1_0_0` | Synopsys VCS | +* We are working with Xilinx to provide a fix for these. + ## SDK ## SDAccel (For additional restrictions see [SDAccel ERRATA](./SDAccel/ERRATA.md)) diff --git a/FAQs.md b/FAQs.md index 4a12d4eb..46aec1b9 100644 --- a/FAQs.md +++ b/FAQs.md @@ -19,14 +19,13 @@ ## General F1 FAQs -**Q: How is developing a FPGA design for the cloud different from the common practice outside the cloud?** +**Q: How is developing an FPGA design for the cloud different from the common practice outside the cloud?** AWS designed its FPGA instances to provide a developer experience with ease of use and as similar as possible to on-premises development environment with the following differences (advantages): - - Developers don’t need to purchase / design / bringup or debug the physical hardware where the FPGA is hosted, nor the platform/server hardware: all the hardware is verified, monitored, and maintained by AWS. -- AWS provides an [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) that contains Xilinx Vivado development environment, with all the needed licenses. By using the FPGA developer AMI developers have a choice to a wide range of instance (different CPU and Memory configuration) allowing developers to optimize their development flow. +- AWS provides an [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) that contains Xilinx Vivado development environment, with all the needed licenses. By using the FPGA Developer AMI developers have a choice to a wide range of instance (different CPU and Memory configuration) allowing developers to optimize their development flow. - AWS provides cloud based debug tools: [Virtual JTAG](./hdk/docs/Virtual_JTAG_XVC.md) which is equivalent to debug using JTAG with on-premises development, and Virtual LED together with Virtual DIP Switch emulation the LED and DIP switches in typical development board. @@ -46,30 +45,32 @@ There are two parts to answer this question: For developers that are familiar with AWS, there is almost no additional time to get right into F1 development environment, as long as the documentation and guidances in the [FPGA HDK/SDK](https://github.com/aws/aws-fpga) are followed. -For developers who are new to AWS, there is typically a one to two days ramp on AWS general topics such as launching EC2 instance, setting up S3 storage and its permissions, using AWS console, etc… For new developers to AWS, we recommend to start with the [FPGA Developer Forum](https://forums.aws.amazon.com/ann.jspa?annID=4448) +For developers who are new to AWS, there is typically a one to two days ramp on AWS general topics such as launching EC2 instance, setting up S3 storage and its permissions, using AWS console, etc… For new developers to AWS, we recommend starting with the [FPGA Developer Forum](https://forums.aws.amazon.com/ann.jspa?annID=4448) - On-going development flow: -Once developers complete their DCP, they submit the design through an AWS EC2 API to create the Amazon FGPA Image (aka AFI, this API call can take a few hours to complete, and the status of the process is reported in the S3 log bucket provides by the developers. AWS is working to improve the turn time of AFI generation. +Once developers create their DCP, they submit the design through an AWS EC2 API to create the Amazon FPGA Image (aka AFI, this API call can take a few hours to complete, and the status of the process is reported in the S3 log bucket provides by the developers. AWS is working to improve the turn time of AFI generation. **Q: What new skill sets will be required from an FPGA developer in the cloud?** -As AWS has taken all the non-differentiating, heavy lifting of hardware design, debug and implementation of PCIe tuning, FPGA I/O assignment, power, thermal management, and runtime health monitoring. Therefore AWS FPGA developers can focus on their own differentiating logic, instead of spending time on hardware bringup/debug and maintenance. +AWS takes care of all the non-differentiating, heavy lifting of hardware design, debug and implementation of PCIe tuning, FPGA I/O assignment, power, thermal management, and runtime health monitoring. + +This enables AWS FPGA developers to focus on their own differentiating logic, instead of spending time on hardware bring-up/debug and maintenance. -On the business side, AWS Marketplace (MP) provides FPGA developers the opportunity to sell hardware accelerations to all of AWS users: Ramping on AWS MP services, capabilities and commercial opportunities are recommended knowledge for developers interested in selling their AFIs on AWS MP. Education and research institutes can use AWS MP to distribute their research work ; having access to vast amounts of free [public data-sets](https://aws.amazon.com/public-datasets/ ) can be of value when running research hardware accelerations on AWS. +On the business side, AWS Marketplace (MP) provides FPGA developers the opportunity to sell hardware accelerations to all of AWS users: Ramping on AWS MP services, capabilities and commercial opportunities are recommended knowledge for developers interested in selling their AFIs on AWS MP. Education and research institutes can use AWS MP to distribute their research work. Having access to vast amounts of free [public data-sets](https://aws.amazon.com/public-datasets/ ) can be of value when running research hardware accelerations on AWS. Finally, AWS consulting and technology partners can offer their services through the [AWS Partner Network](https://aws.amazon.com/ec2/instance-types/f1/partners/) to AWS users that don’t have specific FPGA development knowledge, in order to develop FPGA accelerations in the cloud by themselves. -**Q: How is deployment FPGA in the cloud different compared to on-premises?** +**Q: How is developing on FPGA's in the cloud different from on-premises?** With AWS, FPGAs developers have a few advantages: - Low entry bar: AWS FPGAs are charged on an hourly rate instead of the many thousands of dollars spent on hardware/licenses and 12+ months time it takes to design/manufacture and ship a production-ready FPGA hardware solution. -- Scalability and Elasticity: Developers can ramp up / down the number of deployed FPGAs within seconds based on offered load. +- Scalability and Elasticity: Developers can ramp up / down the number of deployed FPGAs within seconds based on required load. - Share: FPGA developers can share their designs easily through AWS Marketplace or APN. This is important for businesses as well as education and research use. @@ -80,11 +81,11 @@ With AWS, FPGAs developers have a few advantages: The HDK includes the following main components: -1) Documentation for the Shell interface and other Custom Logic implementation guidelines, the Shell models needed for Custom Logic development, simulation models for the Shell, software for exercising. +1) Documentation for the Shell interface and other Custom Logic implementation guidelines, shell models needed for Custom Logic development, simulation models for the shell, scripts for building and simulating, etc. 2) Custom Logic examples, a getting started guide for building your own Custom Logic, and examples for starting a Custom Logic Design. -3) Scripts for building and submitting Amazon FPGA Image (AFI) from a Custom Logic. +3) Scripts for building and creating Amazon FPGA Images (AFI) from a Custom Logic. 4) Reference software drivers to be used in conjunction with the Custom Logic examples. @@ -93,7 +94,7 @@ The HDK includes the following main components: **Q: What is in the AWS Shell?** -The AWS Shell is the part of the FPGA that is provided and managed by AWS: it implements the non-differentiated development and heavy lifting tasks like setting up the PCIe interface, FPGA image download, security, health monitoring, metrics and debug hooks. +The AWS Shell is the part of the FPGA that is provided and managed by AWS: it implements the non-differentiated development and heavy lifting tasks like setting up the PCIe interface, security, health monitoring, metrics and debug hooks. Every FPGA deployed in AWS cloud includes an AWS Shell, and the developer Custom Logic (CL) interfaces with the available AWS Shell interfaces. @@ -110,12 +111,12 @@ The developer can create multiple AFIs at no extra cost, up to a defined limited AWS FPGA generation and EC2 F1 instances are supported in us-east-1 (N. Virginia), us-west-2 (Oregon), eu-west-1 (Ireland) and us-gov-west-1 (GovCloud US). - **Q: What is the process for creating an AFI?** -The AFI process starts by creating Custom Logic (CL) code that conforms to the [Shell Specification](./hdk/docs/AWS_Shell_Interface_Specification.md). Then, the CL must be compiled using the HDK scripts which leverages Vivado tools to create a Design Checkpoint (DCP). That DCP is submitted to AWS for generating an AFI using the `aws ec2 create-fpga-image` API. - -Use the AWS CLI `describe-fpga-images` API to get information about the created AFIs using the AFI ID provided by `create-fpga-image`, or to list available AFIs for your account. See [describe-fpga-images](./hdk/docs/describe_fpga_images.md) document for details on how to use this API. +* The AFI process starts by creating Custom Logic (CL) code that conforms to the [Shell Specification](./hdk/docs/AWS_Shell_Interface_Specification.md). +* Then, the CL must be compiled using the HDK scripts which leverages Vivado tools to create a Design Checkpoint (DCP). +* That DCP is submitted to AWS for generating an AFI using the `aws ec2 create-fpga-image` API. + * Use the AWS CLI `describe-fpga-images` API to get information about the created AFIs using the AFI ID provided by `create-fpga-image`, or to list available AFIs for your account. See [describe-fpga-images](./hdk/docs/describe_fpga_images.md) document for details on how to use this API. **Q: Can I load an AFI on every region AWS FPGA is supported?** @@ -152,6 +153,15 @@ Yes, use [delete-fpga-image](./hdk/docs/delete_fpga_image.md) to delete an AFI i Use [delete-fpga-image](./hdk/docs/delete_fpga_image.md) carefully. Once all AFIs of the same global AFI ID are deleted, the AFIs cannot be recovered from deletion. Review [IAM policy best practices](http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) to resrict access to this API. + +**Q: How do I increase my AFI limit?** + +AFI limit increases may be requested by opening up a Support Case from your [EC2 Support Console](https://console.aws.amazon.com/support/cases#/create) + +Select a `Service limit increase` of the Limit Type - `EC2 FPGA` for the region where a limit increase is needed. + +You will hear back from our support team once the limit is increased. + **Q: Can I bring my own bitstream for loading on an F1 FPGA?** No. There is no mechanism for loading a bitstream directly onto the FPGAs of an F1 instance. All Custom Logic is loaded onto the FPGA by calling `$ fpga-local-load-image` tool at [AWS FPGA SDK](./sdk). @@ -185,20 +195,25 @@ No. AWS supports a cloud-only development model and provides the necessary eleme **Q: Do I need to design for a specific power envelope?** -Yes, the Xilinx UltraScale+ FPGA devices used on the F1 instances have a maximum power limit that must be maintained. If a loaded AFI consumes maximum power, the F1 instance will automatically gate the input clocks provided to the AFI in order to prevent errors within the FPGA. Developers are provided warnings when power (Vccint) is greater than 85 watts. Above that level, the CL is in danger of being clock gated. [Additional details on AFI power](hdk/docs/afi_power.md) - +Yes, the Xilinx UltraScale+ FPGA devices used on the F1 instances have a maximum power limit that must be maintained. +If a loaded AFI consumes maximum power, the F1 instance will automatically gate the input clocks provided to the AFI in order to prevent errors within the FPGA. +Developers are provided warnings when power (Vccint) is greater than 85 watts. Above that level, the CL is in danger of being clock gated. -**Q: What IP blocks are provided in the HDK?** +[Additional details on AFI power](hdk/docs/afi_power.md) -The HDK includes IP for AWS Shell and DRAM interface controllers. Inside the Shell, there is a PCIe interface, DMA Engine, and one DRAM interface controller. These blocks are only accessible via the AXI interfaces defined by the Shell-Custom Logic interface. The HDK provides additional IP blocks for the other DRAM interfaces, enabling up to 3 additional DRAM interfaces instantiated by the developer in the Custom Logic region. - **Note** * future versions of the HDK will include IP for the FPGA Link interface.* +**Q: What IP blocks are provided in the HDK?** +The HDK includes IP for AWS Shell and DRAM interface controllers. +Inside the Shell, there is a PCIe interface, DMA Engine, and one DRAM interface controller. +These blocks are only accessible via the AXI interfaces defined by the Shell-Custom Logic interface. +The HDK provides additional IP blocks for the other DRAM interfaces, enabling up to 3 additional DRAM interfaces instantiated by the developer in the Custom Logic region. **Q: Can I use other IP blocks from Xilinx or other 3rd parties?** -Yes. Developers are free to use any IP blocks within the Custom Logic region. Those can be 3rd party IPs or IP available in the Vivado IP catalog. +Yes. Developers are free to use any IP blocks within the Custom Logic region. +Those can be 3rd party IPs or IP available in the Vivado IP catalog. **Note** * AWS supports only the IP blocks contained in the HDK.* @@ -207,19 +222,23 @@ Yes. Developers are free to use any IP blocks within the Custom Logic region. Th ## Getting Started FAQs **Q: What AWS knowledge do I need to learn before I can develop accelerators and run on AWS F1 instances?** -[AWS Getting Started Resource Center](https://aws.amazon.com/getting-started/) has lots of resources to help developers get started. For F1 development, launching linux virtual machines (EC2) and storing and retrieving files from S3 are required skills. +[AWS Getting Started Resource Center](https://aws.amazon.com/getting-started/) has lots of resources to help developers get started. +For F1 development, launching EC2 instances and storing and retrieving files from S3 are required skills. **Q: What do I need to get started on building accelerators for FPGA instances?** -Getting started requires downloading the latest HDK and SDK from the AWS FPGA GitHub repository. The HDK and SDK provide the needed code and information for building FPGA code. The HDK provides all the information needed for developing an FPGA image from source code, while the SDK provides all the runtime software for managing the Amazon FPGA Image (AFI) loaded into the F1 instance FPGA. +Getting started requires downloading the latest HDK and SDK from the [AWS FPGA GitHub repository](https://github.com/aws/aws-fpga). +The HDK and SDK provide the needed code and information for building FPGA code. The HDK provides all the information needed for developing an FPGA image from source code, while the SDK provides all the runtime software for managing the Amazon FPGA Image (AFI) loaded into the F1 instance FPGA. -Typically, FPGA development process requires a simulator to perform functional test on the source code, and a Vivado tool set for synthesis of source code into compiled FPGA code. The FPGA Developer AMI provided by AWS includes the complete Xilinx Vivado tools for simulation (XSIM) and synthesis of FPGA. +Typically, FPGA development process requires a simulator to perform functional test on the source code, and a Vivado tool set for synthesis of source code into compiled FPGA code. +The FPGA Developer AMI provided by AWS includes the complete Xilinx Vivado tools for simulation (XSIM) and synthesis of FPGA. **Q: How do I develop accelerator code for an FPGA in an F1 instance?** -Start with the [Shell interface specification](./hdk/docs/AWS_Shell_Interface_Specification.md). This document describes the interface between Custom Logic and the AWS Shell. All Custom Logic for an accelerator resides within the Custom Logic region of the F1 FPGA. +Start with the [Shell interface specification](./hdk/docs/AWS_Shell_Interface_Specification.md). +This document describes the interface between Custom Logic and the AWS Shell. All Custom Logic for an accelerator resides within the Custom Logic region of the F1 FPGA. The [HDK README](./hdk/README.md) walks the developer through the steps to build an FPGA image from one of the provided examples as well as starting a new code. @@ -265,12 +284,19 @@ We recommend using the latest available version to be able to use the expanding ## Marketplace FAQs **Q: What does publishing my AFI/AMI to AWS Marketplace enables?** -FPGA Developers can share or sell their AFI/AMI using the AWS Marketplace to other AWS users. Once in Marketplace, AWS users can launch an F1 instance with that AFI/AMI combination with the 1-click deployment feature. Marketplace Sellers can take advantage of the Management Portal to better build and analyze their business, using it to drive marketing activities and customer adoption. The metering, billing, collections, and disbursement of payments are managed by AWS, allowing developers to focus on marketing their solution. Please check out [AWS Marketplace Tour](https://aws.amazon.com/marketplace/management/tour/) for more details on how to become an AWS Marketplace seller, how to set pricing and collect metrics. +FPGA Developers can share or sell their AFI/AMI using the AWS Marketplace to other AWS users. +Once in Marketplace, AWS users can launch an F1 instance with that AFI/AMI combination with the 1-click deployment feature. +Marketplace Sellers can take advantage of the Management Portal to better build and analyze their business, using it to drive marketing activities and customer adoption. +The metering, billing, collections, and disbursement of payments are managed by AWS, allowing developers to focus on marketing their solution. + +Please check out [AWS Marketplace Tour](https://aws.amazon.com/marketplace/management/tour/) for more details on how to become an AWS Marketplace seller, how to set pricing and collect metrics. **Q: How can I publish my AFI to AWS Marketplace?** -First, you need to [register as a Marketplace Seller](https://aws.amazon.com/marketplace/management/register/). In parallel you should create an AMI that includes the drivers and runtime libraries needed to use your AFI. Finally, follow the [standard flow](https://aws.amazon.com/marketplace/help/200940360) to publish your AMI on AWS marketplace, providing the associated AFI IDs. In other words, AFIs are not published directly on AWS marketplace, rather AFI(s) should be associated with an AMI that gets published. +* First, you need to [register as a Marketplace Seller](https://aws.amazon.com/marketplace/management/register/). +* In parallel you should create an AMI that includes the drivers and runtime libraries needed to use your AFI. +* Finally, follow the [standard flow](https://aws.amazon.com/marketplace/help/200940360) to publish your AMI on AWS marketplace, providing the associated AFI IDs. In other words, AFIs are not published directly on AWS marketplace, rather AFI(s) should be associated with an AMI that gets published. **Q: Do AWS Marketplace customers see FPGA source code or a bitstream?** @@ -281,7 +307,11 @@ Neither, no FPGA internal design code is exposed. AWS Marketplace customers that ## F1 Instance and Runtime Tools FAQs **Q: What OS can run on the F1 instance?** -CentOS 7.x is supported and tested on AWS EC2 F1 instance. Please see [release notes](./RELEASE_NOTES.md) for a description of compatible kernel & OS versions supported by a specific Developer kit version. Developers can utilize the source code in the SDK directory to compile other variants of Linux for use on F1. Windows OSs are not supported on F1. +CentOS 7.x is supported and tested on AWS EC2 F1 instance. +Please see [release notes](./RELEASE_NOTES.md) for a description of compatible Kernel & OS versions supported by a specific Developer kit version. +Developers can utilize the source code in the SDK directory to compile other variants of Linux for use on F1. + +NOTE: Windows OSs are not supported on F1. **Q: What are the interfaces between the F1 instance host CPU and the FPGAs?** @@ -293,7 +323,6 @@ The first is the FPGA Image Management Tools. These APIs are detailed in the [SD The second type of interface is direct address access to the Application PCIe Physical Functions (PF) of the FPGA. There is no API for this access. Rather, there is direct access to resources in the Custom Logic (CL) region or Shell that can be accessed by software written on the instance. For example, the ChipScope software (Virtual JTAG) uses address space in a PF to provide FPGA debug support. Developers can create any API to the resources in their CL. See the [Shell Interface Specification](./hdk/docs/AWS_Shell_Interface_Specification.md) for more details on the address space mapping as seen from the instance. - **Q: Can I integrate the FPGA Image Management Tools in my application?** Yes, In addition to providing the [FPGA Management Tools](./sdk/userspace/fpga_mgmt_tools) as linux shell commands, the [SDK Userspace](./sdk/userspace) directory includes files in the `include` and `hal` to integrate the FPGA Management Tools into the developer's application(a) and avoid calling linux shell commands. @@ -326,8 +355,8 @@ The AWS infrastructure scrubs FPGA state on termination of an F1 instance and an **Q: How do the FPGAs connect to the x86 CPU?** -Each FPGA in F1 is connected to the instance CPU via a x16 PCIe Gen3 interface. Physical Functions (PF) within the FPGA are directly mapped into the F1 instance. Software on the instance can directly access the address in the PF to take advantage of the high performance PCIe interface. - +Each FPGA in F1 is connected to the instance CPU via a x16 PCIe Gen3 interface. +Physical Functions (PF) within the FPGA are directly mapped into the F1 instance. Software on the instance can directly access the address in the PF to take advantage of the high performance PCIe interface. **Q: Can the FPGAs on F1 directly access Amazon’s network?** @@ -346,8 +375,10 @@ No. The FPGAs do not have direct access to the SSDs on F1. The SSDs on F1 are hi ## Development Languages FAQs **Q: Which HDL languages are supported?** -For RTL level development: Verilog and VHDL are both supported in the FPGA Developer AMI and in generating a Design Checkpoint. The Xilinx Vivado tools and simulator support mixed mode simulation of Verilog and VHDL. The AWS Shell is written in Verilog. Support for mixed mode simulation may vary if developers use other simulators. Check your simulator documentation for Verilog/VHDL/System Verilog support. - +For RTL level development: Verilog and VHDL are both supported in the FPGA Developer AMI and in generating a Design Checkpoint. +The Xilinx Vivado tools and simulator support mixed mode simulation of Verilog and VHDL. +The AWS Shell is written in Verilog. Support for mixed mode simulation may vary if developers use other simulators. +Check your simulator documentation for Verilog/VHDL/System Verilog support. **Q: Is OpenCL and/or SDAccel Supported?** @@ -355,41 +386,44 @@ For RTL level development: Verilog and VHDL are both supported in the FPGA Devel Yes. Please review the [SDAccel README to get started](SDAccel/README.md) - **Q: Can I use High Level Synthesis(HLS) Tools to generate an AFI?** -Yes. Vivado HLS and SDAccel are directly supported through the FPGA Developer AMI. Any other HLS tool that generates compatible Verilog or VHDL for Vivado input can also be used for writing in HLS. - +Yes. Vivado HLS and SDAccel are directly supported through the FPGA Developer AMI. +Any other HLS tool that generates compatible Verilog or VHDL for Vivado input can also be used for writing in HLS. **Q: What RTL simulators are supported?** The FPGA Developer AMI has built-in support for the Xilinx XSIM simulator. All licensing and software for XSIM is included in the FPGA Developer AMI when launched. -Support for other simulators is included through the bring-your-own license in the FPGA Developer AMI. AWS tests the HDK with Synopsys VCS, Mentor Questa/ModelSim, and Cadence Incisive. Licenses for these simulators must be acquired by the developer and are not available with AWS FPGA Developer AMI. +AWS tests the HDK with Synopsys VCS, Mentor Questa/ModelSim, and Cadence Incisive. Licenses for these simulators must be acquired by the developer and are not available with AWS FPGA Developer AMI. ## FPGA Specific FAQs **Q: What FPGA is used in AWS EC2 F1 instance?** -The FPGA for F1 is the Xilinx Ultrascale+ VU9P device with the -2 speed grade. The HDK scripts have the compile scripts needed for the VU9P device. +The FPGA for F1 is the Xilinx Ultrascale+ VU9P device with the -2 speed grade. +The HDK scripts have the compile scripts needed for the VU9P device. **Q: What is FPGA Direct and how fast is it?** -FPGA Direct is FPGA to FPGA low latency high throughput peer communication through the PCIe links on each FPGA, where all FPGAs shared the same memory space. The PCIe BAR space in the Application PF (see [Shell Interface specification](./hdk/docs/AWS_Shell_Interface_Specification.md) for more details) allows the developer to map regions of the Custom Logic, such as external DRAM space, to other FPGAs. The implementation of communication protocol and data transfer engine across the PCIe interface using FPGA direct is left to the developer. +FPGA Direct is FPGA to FPGA low latency high throughput peer communication through the PCIe links on each FPGA, where all FPGAs shared the same memory space. +The PCIe BAR space in the Application PF (see [Shell Interface specification](./hdk/docs/AWS_Shell_Interface_Specification.md) for more details) allows the developer to map regions of the Custom Logic, such as external DRAM space, to other FPGAs. +The implementation of communication protocol and data transfer engine across the PCIe interface using FPGA direct is left to the developer. **Q: What is FPGA Link and how fast is it?** -FPGA Link is based on 4 x 100Gbps links on each FPGA card. The FPGA Link is organized as a ring, with 2 x 100Gbps links to each adjacent card. This enables each FPGA card to send/receive data from an adjacent card at 200Gbps speeds. This is a unsupported feature planned for future release. Details on the FPGA Link interface will be provided in the Shell Interface specification when available. +FPGA Link is based on 4 x 100Gbps links on each FPGA card. The FPGA Link is organized as a ring, with 2 x 100Gbps links to each adjacent card. This enables each FPGA card to send/receive data from an adjacent card at 200Gbps speeds. +This is an unsupported feature planned for future release. Details on the FPGA Link interface will be provided in the Shell Interface specification when available. **Q: What protocol is used for FPGA link?** The FPGA link is a generic raw streaming interface, no transport protocol is provided for it by AWS. It is expected that developers would take advantage of standard PCIe protocol, Ethernet protocol, or Xilinx's (reliable) Aurora protocol layer for this interface. -This is a unsupported feature planned for future release. Details on the Shell Interface to the FPGA Link IP blocks are provided in the [Shell Interface specification](./hdk/docs/AWS_Shell_Interface_Specification.md) when available. +This is an unsupported feature planned for future release. Details on the Shell Interface to the FPGA Link IP blocks are provided in the [Shell Interface specification](./hdk/docs/AWS_Shell_Interface_Specification.md) when available. **Q: What clock speed does the FPGA utilize?** @@ -463,7 +497,6 @@ You would need a valid [on premise license](./hdk/docs/on_premise_licensing_help *For runs using the FPGA Developer AMI:* Please contact us through [AWS FPGA Developers forum](https://forums.aws.amazon.com/forum.jspa?forumID=243) - **Q: Why does Vivado in GUI mode show up blank ? or Why does Vivado in GUI mode show up as an empty window?** We have seen this issue when running RDP in 32 bit color mode where Vivado shows up as a blank window. diff --git a/Jenkinsfile b/Jenkinsfile index 3df7ee08..71a1d172 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -122,7 +122,7 @@ task_label = [ ] // Put the latest version last -def xilinx_versions = [ '2017.4', '2018.2', '2018.3' ] +def xilinx_versions = [ '2017.4', '2018.2', '2018.3', '2019.1' ] // We want the default to be the latest. def default_xilinx_version = xilinx_versions.last() @@ -130,7 +130,8 @@ def default_xilinx_version = xilinx_versions.last() def dsa_map = [ '2017.4' : [ 'DYNAMIC_5_0' : 'dyn'], '2018.2' : [ 'DYNAMIC_5_0' : 'dyn'], - '2018.3' : [ 'DYNAMIC_5_0' : 'dyn'] + '2018.3' : [ 'DYNAMIC_5_0' : 'dyn'], + '2019.1' : [ 'DYNAMIC_5_0' : 'dyn'] ] def sdaccel_example_default_map = [ @@ -153,6 +154,12 @@ def sdaccel_example_default_map = [ 'Gmem_2Banks_2ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/gmem_2banks_ocl', 'Kernel_Global_Bw_4ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/kernel_global_bandwidth', 'RTL_Vadd_Debug': 'SDAccel/examples/xilinx/getting_started/rtl_kernel/rtl_vadd_hw_debug' + ], + '2019.1' : [ + 'Hello_World_1ddr': 'SDAccel/examples/xilinx/getting_started/hello_world/helloworld_ocl', + 'Gmem_2Banks_2ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/gmem_2banks_ocl_5.0_shell', + 'Kernel_Global_Bw_4ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/kernel_global_bandwidth_5.0_shell', + 'RTL_Vadd_Debug': 'SDAccel/examples/xilinx/getting_started/rtl_kernel/rtl_vadd_hw_debug' ] ] @@ -174,6 +181,12 @@ def simulator_tool_default_map = [ 'vcs': 'synopsys/vcs-mx/N-2017.12-SP2', 'questa': 'questa/10.6c_1', 'ies': 'incisive/15.20.063' + ], + '2019.1' : [ + 'vivado': 'xilinx/SDx/2019.1.op2552052', + 'vcs': 'synopsys/vcs-mx/N-2017.12-SP2', + 'questa': 'questa/10.6c_1', + 'ies': 'incisive/15.20.063' ] ] @@ -270,7 +283,7 @@ def test_run_py_bindings() { try { sh """ set -e - source $WORKSPACE/shared/tests/bin/setup_test_sdk_env_al2.sh "py_bindings" + source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh "py_bindings" python2.7 -m pytest -v $WORKSPACE/${test} --junit-xml $WORKSPACE/${report_file} """ } catch (exc) { @@ -368,7 +381,7 @@ def test_fpga_all_slots() { } catch (exception) { echo "Test FPGA Tools All Slots failed" - input message: "1 slot FPGA Tools test failed. Click Proceed or Abort when you are done debugging on the instance." + input message: "All slot FPGA Tools test failed. Click Proceed or Abort when you are done debugging on the instance." throw exception } finally { @@ -396,7 +409,6 @@ def test_run_non_root_access() { source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh newgrp fpgauser export SDK_DIR="${WORKSPACE}/sdk" - source $WORKSPACE/shared/tests/bin/setup_test_env.sh python2.7 -m pytest -v $WORKSPACE/${test} --junit-xml $WORKSPACE/${report_file} """ } catch (exc) { @@ -599,15 +611,15 @@ if (test_xdma) { //============================================================================= // Python Binding Test //============================================================================= -if (test_py_bindings) { - all_tests['Test Python Bindings'] = { - stage('Test Python Bindings') { - node('f1.2xl_runtime_test_al2') { - test_run_py_bindings() - } - } - } -} +// if (test_py_bindings) { +// all_tests['Test Python Bindings'] = { +// stage('Test Python Bindings') { +// node('f1.2xl_runtime_test_al2') { +// test_run_py_bindings() +// } +// } +// } +// } //============================================================================= // Precompiled Runtime Tests @@ -873,34 +885,34 @@ if (test_hdk_fdf) { // SDAccel Tests //============================================================================= -if (test_sdaccel_scripts) { - all_tests['Test SDAccel Scripts'] = { - stage('Test SDAccel Scripts') { - def nodes = [:] - for (def xilinx_version in xilinx_versions) { - - String node_label = get_task_label(task: 'source_scripts', xilinx_version: xilinx_version) - String node_name = "Test SDAccel Scripts ${xilinx_version}" - nodes[node_name] = { - node(node_label) { - String report_file = "test_sdaccel_scripts_${xilinx_version}.xml" - checkout scm - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_env.sh - python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_sdaccel_scripts.py --junit-xml $WORKSPACE/${report_file} - """ - } finally { - run_junit(report_file) - } - } - } - } - parallel nodes - } - } -} +// if (test_sdaccel_scripts) { +// all_tests['Test SDAccel Scripts'] = { +// stage('Test SDAccel Scripts') { +// def nodes = [:] +// for (def xilinx_version in xilinx_versions) { +// +// String node_label = get_task_label(task: 'source_scripts', xilinx_version: xilinx_version) +// String node_name = "Test SDAccel Scripts ${xilinx_version}" +// nodes[node_name] = { +// node(node_label) { +// String report_file = "test_sdaccel_scripts_${xilinx_version}.xml" +// checkout scm +// try { +// sh """ +// set -e +// source $WORKSPACE/shared/tests/bin/setup_test_env.sh +// python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_sdaccel_scripts.py --junit-xml $WORKSPACE/${report_file} +// """ +// } finally { +// run_junit(report_file) +// } +// } +// } +// } +// parallel nodes +// } +// } +// } if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { all_tests['Run SDAccel Tests'] = { @@ -995,6 +1007,7 @@ if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { } boolean test_sw_emu_supported = true + boolean test_hw_emu_supported = true if(description_json["targets"]) { if(description_json["targets"].contains("sw_emu")) { @@ -1004,6 +1017,13 @@ if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { test_sw_emu_supported = false echo "Description file ${description_file} does not have target sw_emu" } + if(description_json["targets"].contains("hw_emu")) { + test_hw_emu_supported = true + echo "Description file ${description_file} has target sw_emu" + } else { + test_hw_emu_supported = false + echo "Description file ${description_file} does not have target sw_emu" + } } else { echo "Description json did not have a 'target' key" } @@ -1032,23 +1052,25 @@ if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { } } - stage(hw_emu_stage_name) { - node(get_task_label(task: 'sdaccel_builds', xilinx_version: xilinx_version)) { - checkout scm - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh - export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} - python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_hw_emu --examplePath ${example_path} --junit-xml $WORKSPACE/${hw_emu_report_file} --timeout=21600 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} - """ - } catch (error) { - echo "${hw_emu_stage_name} HW EMU Build generation failed" - archiveArtifacts artifacts: "${example_path}/**", fingerprint: true - throw error - } finally { - run_junit(hw_emu_report_file) - git_cleanup() + if(test_hw_emu_supported) { + stage(hw_emu_stage_name) { + node(get_task_label(task: 'sdaccel_builds', xilinx_version: xilinx_version)) { + checkout scm + try { + sh """ + set -e + source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh + export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} + python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_hw_emu --examplePath ${example_path} --junit-xml $WORKSPACE/${hw_emu_report_file} --timeout=21600 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} + """ + } catch (error) { + echo "${hw_emu_stage_name} HW EMU Build generation failed" + archiveArtifacts artifacts: "${example_path}/**", fingerprint: true + throw error + } finally { + run_junit(hw_emu_report_file) + git_cleanup() + } } } } diff --git a/Jenkinsfile_int_sims b/Jenkinsfile_int_sims index 093164a7..76523548 100644 --- a/Jenkinsfile_int_sims +++ b/Jenkinsfile_int_sims @@ -121,7 +121,7 @@ task_label = [ ] // Put the latest version last -def xilinx_versions = [ '2017.4', '2018.2', '2018.3' ] +def xilinx_versions = [ '2019.1' ] // We want the default to be the latest. def default_xilinx_version = xilinx_versions.last() @@ -173,6 +173,12 @@ def simulator_tool_default_map = [ 'vcs': 'synopsys/vcs-mx/N-2017.12-SP2', 'questa': 'questa/10.6c_1', 'ies': 'incisive/15.20.063' + ], + '2019.1' : [ + 'vivado': 'xilinx/SDx/2019.1.op2552052', + 'vcs': 'synopsys/vcs-mx/O-2018.09-SP1', + 'questa': 'questa/10.6c_1', + 'ies': 'incisive/15.20.063' ] ] @@ -253,239 +259,6 @@ def git_cleanup() { """ } -////////////////////////////////////////////////////// -////////////////////////////////////////////////////// -// Test Functions///////////////////////////////////// -////////////////////////////////////////////////////// -////////////////////////////////////////////////////// - -def test_run_py_bindings() { - echo "Test Python Bindings" - checkout scm - - String test = "sdk/tests/test_py_bindings.py" - String report_file = "test_py_bindings.xml" - - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_sdk_env_al2.sh "py_bindings" - python2.7 -m pytest -v $WORKSPACE/${test} --junit-xml $WORKSPACE/${report_file} - """ - } catch (exc) { - echo "${test} failed." - input message: "Python bindings test failed. Click Proceed or Abort when you are done debugging on the instance." - throw exc - } finally { - run_junit(report_file) - } -} - -def test_doc_markdown_links() { - String report_file = 'test_md_links.xml' - checkout scm - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_env.sh - python2.7 -m pytest -v $WORKSPACE/shared/tests/test_md_links.py --junit-xml $WORKSPACE/${report_file} - """ - } finally { - run_junit(report_file) - } -} - -def test_doc_src_headers() { - String report_file = 'test_check_src_headers.xml' - checkout scm - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_env.sh - python2.7 -m pytest -v $WORKSPACE/shared/tests/test_check_src_headers.py --junit-xml $WORKSPACE/${report_file} - """ - } finally { - run_junit(report_file) - } -} - -def test_run_hdk_scripts() { - checkout scm - String report_file = 'test_hdk_scripts.xml' - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_env.sh - python2.7 -m pytest -v $WORKSPACE/hdk/tests/test_hdk_scripts.py --junit-xml $WORKSPACE/${report_file} - """ - } finally { - run_junit(report_file) - } -} - -def test_fpga_1_slot() { - String report_file_tools = 'test_fpga_tools.xml' - String report_file_sdk = 'test_fpga_sdk.xml' - String report_file_combined = 'test_fpga_*.xml' - checkout scm - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh - python2.7 -m pytest -v $WORKSPACE/sdk/tests/test_fpga_tools.py --junit-xml $WORKSPACE/${report_file_tools} - sudo -E sh -c 'source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh && python2.7 -m pytest -v $WORKSPACE/sdk/tests/test_sdk.py --junit-xml $WORKSPACE/${report_file_sdk}' - sudo -E chmod 666 $WORKSPACE/${report_file_sdk} - """ - } - catch (exception) { - echo "Test FPGA Tools 1 Slot failed" - input message: "1 slot FPGA Tools test failed. Click Proceed or Abort when you are done debugging on the instance." - throw exception - } - finally { - if (fileExists(report_file_tools)) { - junit healthScaleFactor: 10.0, testResults: report_file_combined - } else { - echo "Pytest wasn't run for stage. Report file not generated: ${report_file_combined}" - } - } -} - -def test_fpga_all_slots() { - String report_file_tools = 'test_fpga_tools_all_slots.xml' - String report_file_sdk = 'test_fpga_sdk_all_slots.xml' - String report_file_combined = 'test_fpga_*_all_slots.xml' - checkout scm - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh - python2.7 -m pytest -v $WORKSPACE/sdk/tests/test_fpga_tools.py --junit-xml $WORKSPACE/${report_file_tools} - sudo -E sh -c 'source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh && python2.7 -m pytest -v $WORKSPACE/sdk/tests/test_sdk.py --junit-xml $WORKSPACE/${report_file_sdk}' - sudo -E chmod 666 $WORKSPACE/${report_file_sdk} - """ - } - catch (exception) { - echo "Test FPGA Tools All Slots failed" - input message: "1 slot FPGA Tools test failed. Click Proceed or Abort when you are done debugging on the instance." - throw exception - } - finally { - if (fileExists(report_file_tools)) { - junit healthScaleFactor: 10.0, testResults: report_file_combined - } else { - echo "Pytest wasn't run for stage. Report file not generated: ${report_file_combined}" - } - } -} - - -def test_run_non_root_access() { - echo "Test non-root access to FPGA tools" - checkout scm - - String test = "sdk/tests/test_non_root_access.py" - String report_file = "test_non_root_access.xml" - - try { - sh """ - set -e - export AWS_FPGA_ALLOW_NON_ROOT=y - export AWS_FPGA_SDK_OVERRIDE_GROUP=y - source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh - newgrp fpgauser - export SDK_DIR="${WORKSPACE}/sdk" - source $WORKSPACE/shared/tests/bin/setup_test_env.sh - python2.7 -m pytest -v $WORKSPACE/${test} --junit-xml $WORKSPACE/${report_file} - """ - } catch (exc) { - input message: "Non-root access test failed. Click Proceed or Abort when you are done debugging on the instance." - throw exc - } finally { - run_junit(report_file) - } -} - -def test_xdma_driver() { - echo "Test XDMA Driver" - checkout scm - - String test = "sdk/tests/test_xdma.py" - String report_file = "test_xdma.xml" - - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh - python2.7 -m pytest -v ${test} --junit-xml $WORKSPACE/${report_file} - """ - } catch (exc) { - echo "${test} failed." - junit healthScaleFactor: 10.0, testResults: report_file - input message: "XDMA driver test failed. Click Proceed or Abort when you are done debugging on the instance." - throw exc - } finally { - run_junit(report_file) - } -} - -//============================================================================= -// Shared Tests -//============================================================================= - - -if (test_markdown_links || test_src_headers) { - all_tests['Documentation Tests'] = { - node(get_task_label(task: 'md_links', xilinx_version: default_xilinx_version)) { - if (test_markdown_links) { - stage('Test Markdown Links') { - test_doc_markdown_links() - } - } - - if (test_src_headers) { - stage('Test Source Headers') { - test_doc_src_headers() - } - } - } - } -} - -//============================================================================= -// HDK Tests -//============================================================================= - -if (test_hdk_scripts) { - all_tests['Test HDK Scripts'] = { - stage('Test HDK Scripts') { - node(get_task_label(task: 'source_scripts', xilinx_version: default_xilinx_version)) { - test_run_hdk_scripts() - } - } - } -} - -//============================================================================= -// FPGA Tool Tests -//============================================================================= -if (test_fpga_tools) { - all_tests['Test FPGA Tools 1 Slot'] = { - stage('Test FPGA Tools 1 Slot') { - node(get_task_label(task: 'runtime', xilinx_version: default_xilinx_version)) { - test_fpga_1_slot() - } - } - } - all_tests['Test FPGA Tools All Slots'] = { - stage('Test FPGA Tools All Slots') { - node(get_task_label(task: 'runtime_all_slots', xilinx_version: default_xilinx_version)) { - test_fpga_all_slots() - } - } - } -} - //============================================================================= // Simulations //============================================================================= @@ -568,578 +341,6 @@ if (test_sims) { } } -//============================================================================= -// Non root access Test -//============================================================================= -if (test_non_root_access) { - all_tests['Test non-root access to FPGA tools'] = { - stage('Test non-root access to FPGA tools') { - node(get_task_label(task: 'runtime', xilinx_version: default_xilinx_version)) { - test_run_non_root_access() - } - } - } -} - -//============================================================================= -// Driver Tests -//============================================================================= -if (test_xdma) { - all_tests['Test XDMA Driver'] = { - stage('Test XDMA Driver') { - node(get_task_label(task: 'runtime', xilinx_version: default_xilinx_version)) { - test_xdma_driver() - } - } - } -} - -//============================================================================= -// Python Binding Test -//============================================================================= -if (test_py_bindings) { - all_tests['Test Python Bindings'] = { - stage('Test Python Bindings') { - node('f1.2xl_runtime_test_al2') { - test_run_py_bindings() - } - } - } -} - -//============================================================================= -// Precompiled Runtime Tests -//============================================================================= -if(disable_runtime_tests) { - echo "Runtime tests disabled. Not running Test Runtime Software stages" -} else { - if (test_runtime_software) { - all_tests['Test Runtime Software'] = { - stage('Test Runtime Software') { - def nodes = [:] - def node_types = ['runtime', 'runtime_all_slots'] - for (n in node_types) { - node_type = n - for (x in runtime_sw_cl_names) { - String cl_name = x - String node_name = "Undefined" - switch (node_type) { - case "runtime": - node_name = "Test Runtime Software ${default_xilinx_version} f1.2xl ${cl_name}" - break; - case "runtime_all_slots": - node_name = "Test Runtime Software ${default_xilinx_version} f1.16xl ${cl_name}" - break; - } - String node_label = get_task_label(task: node_type, xilinx_version: default_xilinx_version) - nodes[node_name] = { - node(node_label) { - String test = "hdk/tests/test_load_afi.py::TestLoadAfi::test_precompiled_${cl_name}" - String report_file = "test_runtime_software_${cl_name}.xml" - checkout scm - - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh - python2.7 -m pytest -v ${test} --junit-xml $WORKSPACE/${report_file} - """ - } finally { - run_junit(report_file) - } - } - } - } - } - parallel nodes - } - } - } -} - -//============================================================================= -// DCP Recipe Tests -//============================================================================= -if (test_dcp_recipes) { - all_tests['Test DCP Recipes'] = { - stage('Test DCP Recipes') { - def nodes = [:] - for (version in xilinx_versions) { - String xilinx_version = version - - for (cl in dcp_recipe_cl_names) { - String cl_name = cl - for (s in dcp_recipe_scenarios) { - String recipe_scenario = s - String node_name = "Test DCP Recipe ${cl_name}[${xilinx_version}-${recipe_scenario}]" - nodes[node_name] = { - node(get_task_label(task: 'dcp_gen', xilinx_version: xilinx_version)) { - String test_name = "test_${cl_name}[${xilinx_version}-${recipe_scenario}]" - String report_file = "test_dcp_recipe_${cl_name}[${xilinx_version}-${recipe_scenario}].xml" - String build_dir = "hdk/cl/examples/${cl_name}/build" - checkout scm - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_hdk_env.sh - python2.7 -m pytest -s -v hdk/tests/test_gen_dcp.py::TestGenDcp::${test_name} --junit-xml $WORKSPACE/${report_file} --xilinxVersion ${xilinx_version} - """ - } catch(exc) { - echo "${test_name} DCP generation failed: archiving results" - archiveArtifacts artifacts: "${build_dir}/**", fingerprint: true - throw exc - } finally { - run_junit(report_file) - } - } - } - } - } - } - - parallel nodes - } - } -} - -//============================================================================= -// HDK Full Developer Flow Tests -//============================================================================= -if (test_hdk_fdf) { - // Top level stage for FDF - // Each CL will have its own parallel FDF stage under this one. - all_tests['HDK_FDF'] = { - stage('HDK FDF') { - def fdf_stages = [:] - for (version in xilinx_versions) { - String xilinx_version = version - - for (x in fdf_test_names) { - String fdf_test_name = x - String cl_name = "" - - if (fdf_test_name.contains('[')) { - def split_test = fdf_test_name.split(/\[/) - def test_base_name = split_test[0] - def test_args = split_test[1] - - fdf_test_name = "$test_base_name[$xilinx_version-$test_args" - cl_name = test_base_name - } - - String fdf_stage_name = "FDF ${xilinx_version} ${fdf_test_name}" - fdf_stages[fdf_stage_name] = { - stage(fdf_stage_name) { - echo "Generate DCP for ${xilinx_version} ${fdf_test_name}" - String build_dir = "hdk/cl/examples/${cl_name}/build" - String dcp_stash_name = "dcp_tarball_${fdf_test_name}_${xilinx_version}".replaceAll(/[\[\]]/, "_") - String dcp_stash_dir = "${build_dir}/checkpoints/to_aws" - String afi_stash_name = "afi_${fdf_test_name}_${xilinx_version}".replaceAll(/[\[\]]/, "_") - String afi_stash_dir = "${build_dir}/create_afi" - echo "dcp_stash_name=${dcp_stash_name}" - echo "afi_stash_name=$afi_stash_name}" - node(get_task_label(task: 'dcp_gen', xilinx_version: xilinx_version)) { - String test = "hdk/tests/test_gen_dcp.py::TestGenDcp::test_${fdf_test_name}" - String report_file = "test_dcp_${fdf_test_name}_${xilinx_version}.xml" - checkout scm - // Clean out the to_aws directory to make sure there are no artifacts left over from a previous build - try { - sh """ - rm -rf ${dcp_stash_dir} - """ - } catch(exc) { - // Ignore any errors - echo "Failed to clean ${dcp_stash_dir}" - } - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_hdk_env.sh - python2.7 -m pytest -v ${test} --junit-xml $WORKSPACE/${report_file} --xilinxVersion ${xilinx_version} - """ - } catch (exc) { - echo "${fdf_test_name} DCP generation failed: archiving results" - archiveArtifacts artifacts: "${build_dir}/**", fingerprint: true - throw exc - } finally { - run_junit(report_file) - } - try { - stash name: dcp_stash_name, includes: "${dcp_stash_dir}/**" - } catch (exc) { - echo "stash ${dcp_stash_name} failed:\n${exc}" - } - } - node(get_task_label(task: 'create_afi', xilinx_version: xilinx_version)) { - echo "Generate AFI for ${xilinx_version} ${fdf_test_name}" - checkout scm - String test = "hdk/tests/test_create_afi.py::TestCreateAfi::test_${fdf_test_name}" - String report_file = "test_create_afi_${fdf_test_name}_${xilinx_version}.xml" - // Clean out the stash directories to make sure there are no artifacts left over from a previous build - try { - sh """ - rm -rf ${dcp_stash_dir} - """ - } catch(exc) { - // Ignore any errors - echo "Failed to clean ${dcp_stash_dir}" - } - try { - sh """ - rm -rf ${afi_stash_dir} - """ - } catch(exc) { - // Ignore any errors - echo "Failed to clean ${afi_stash_dir}" - } - try { - unstash name: dcp_stash_name - } catch (exc) { - echo "unstash ${dcp_stash_name} failed:\n${exc}" - //throw exc - } - try { - // There is a Xilinx bug that causes the following error during hdk_setup.sh if multiple - // processes are doing it at the same time: - // WARNING: [Common 17-1221] Tcl app 'xsim' is out of date for this release. Please run tclapp::reset_tclstore and reinstall the app. - // ERROR: [Common 17-685] Unable to load Tcl app xilinx::xsim - // ERROR: [Common 17-69] Command failed: ERROR: [Common 17-685] Unable to load Tcl app xilinx::xsim - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_env.sh - python2.7 -m pytest -v ${test} --junit-xml $WORKSPACE/${report_file} --xilinxVersion ${xilinx_version} - """ - } catch (exc) { - echo "${fdf_test_name} AFI generation failed: archiving results" - archiveArtifacts artifacts: "${build_dir}/to_aws/**", fingerprint: true - throw exc - } finally { - run_junit(report_file) - } - try { - stash name: afi_stash_name, includes: "${afi_stash_dir}/**" - } catch (exc) { - echo "stash ${afi_stash_name} failed:\n${exc}" - } - } - - if(disable_runtime_tests) { - echo "Runtime tests disabled. Not running runtime ${fdf_test_name}" - } else { - node(get_task_label(task: 'runtime', xilinx_version: xilinx_version)) { - String test = "hdk/tests/test_load_afi.py::TestLoadAfi::test_${fdf_test_name}" - String report_file = "test_load_afi_${fdf_test_name}_${xilinx_version}.xml" - checkout scm - echo "Test AFI for ${xilinx_version} ${fdf_test_name} on F1 instance" - // Clean out the stash directories to make sure there are no artifacts left over from a previous build - try { - sh """ - rm -rf ${afi_stash_dir} - """ - } catch(exc) { - // Ignore any errors - echo "Failed to clean ${afi_stash_dir}" - } - try { - unstash name: afi_stash_name - } catch (exc) { - echo "unstash ${afi_stash_name} failed:\n${exc}" - } - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_sdk_env.sh - python2.7 -m pytest -v ${test} --junit-xml $WORKSPACE/${report_file} --xilinxVersion ${xilinx_version} - """ - } finally { - run_junit(report_file) - } - } - } //else - } // stage( - } - } // for (x in fdf_test_names) - - } // for (xilinx_version in xilinx_versions) { - - parallel fdf_stages - } - } -} - -//============================================================================= -// SDAccel Tests -//============================================================================= - -if (test_sdaccel_scripts) { - all_tests['Test SDAccel Scripts'] = { - stage('Test SDAccel Scripts') { - def nodes = [:] - for (def xilinx_version in xilinx_versions) { - - String node_label = get_task_label(task: 'source_scripts', xilinx_version: xilinx_version) - String node_name = "Test SDAccel Scripts ${xilinx_version}" - nodes[node_name] = { - node(node_label) { - String report_file = "test_sdaccel_scripts_${xilinx_version}.xml" - checkout scm - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_env.sh - python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_sdaccel_scripts.py --junit-xml $WORKSPACE/${report_file} - """ - } finally { - run_junit(report_file) - } - } - } - } - parallel nodes - } - } -} - -if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { - all_tests['Run SDAccel Tests'] = { - String sdaccel_examples_list = 'sdaccel_examples_list.json' - - def sdaccel_all_version_stages = [:] - - for (def version in xilinx_versions) { - - String xilinx_version = version - String sdaccel_base_stage_name = "SDx FDF $xilinx_version" - String sdaccel_find_stage_name = "SDx Find tests $xilinx_version" - - sdaccel_all_version_stages[sdaccel_base_stage_name] = { - stage (sdaccel_find_stage_name) { - - node(get_task_label(task: 'find_tests', xilinx_version: xilinx_version)) { - - checkout scm - String report_file = "test_find_sdaccel_examples_${xilinx_version}.xml" - - try { - sh """ - rm -rf ${sdaccel_examples_list} - """ - } catch(error) { - // Ignore any errors - echo "Failed to clean ${sdaccel_examples_list}" - } - - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh - python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_find_sdaccel_examples.py --junit-xml $WORKSPACE/${report_file} - """ - } catch (exc) { - echo "Could not find tests. Please check the repository." - throw exc - } finally { - run_junit(report_file) - } - - // Only run the hello world test by default - //def example_map = [ 'Hello_World': 'SDAccel/examples/xilinx/getting_started/host/helloworld_ocl' ] - def example_map = sdaccel_example_default_map.get(xilinx_version) - - // Run all examples when parameter set - if (test_all_sdaccel_examples_fdf) { - example_map = readJSON file: sdaccel_examples_list - } - - def sdaccel_build_stages = [:] - - for ( def e in entrySet(example_map) ) { - - String test_key = e.key - def dsa_map_for_version = dsa_map.get(xilinx_version) - - // dsa = [ 4DDR: 4ddr ] - for ( def dsa in entrySet(dsa_map_for_version) ) { - - String build_name = "SDx ${e.key}_${dsa.value}_${xilinx_version}" - String example_path = e.value - - String dsa_name = dsa.key - String dsa_rte_name = dsa.value - - String sw_emu_stage_name = "SDx SW_EMU ${build_name}" - String hw_emu_stage_name = "SDx HW_EMU ${build_name}" - String hw_stage_name = "SDx HW ${build_name}" - String create_afi_stage_name = "SDx AFI ${build_name}" - String run_example_stage_name = "SDx RUN ${build_name}" - - String sw_emu_report_file = "sdaccel_sw_emu_${e.key}_${dsa.value}_${xilinx_version}.xml" - String hw_emu_report_file = "sdaccel_hw_emu_${e.key}_${dsa.value}_${xilinx_version}.xml" - String hw_report_file = "sdaccel_hw_${e.key}_${dsa.value}_${xilinx_version}.xml" - String create_afi_report_file = "sdaccel_create_afi_${e.key}_${dsa.value}_${xilinx_version}.xml" - String run_example_report_file = "sdaccel_run_${e.key}_${dsa.value}_${xilinx_version}.xml" - - String description_file = "${example_path}/description.json" - def description_json = ["targets":["hw","hw_emu","sw_emu"]] - - try { - description_json = readJSON file: description_file - } - catch (exc) { - echo "Could not read the file: ${description_file}" - throw exc - } - - boolean test_sw_emu_supported = true - - if(description_json["targets"]) { - if(description_json["targets"].contains("sw_emu")) { - test_sw_emu_supported = true - echo "Description file ${description_file} has target sw_emu" - } else { - test_sw_emu_supported = false - echo "Description file ${description_file} does not have target sw_emu" - } - } else { - echo "Description json did not have a 'target' key" - } - - sdaccel_build_stages[build_name] = { - if(test_sw_emu_supported) { - stage(sw_emu_stage_name) { - node(get_task_label(task: 'sdaccel_builds', xilinx_version: xilinx_version)) { - checkout scm - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh - export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} - python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_sw_emu --examplePath ${example_path} --junit-xml $WORKSPACE/${sw_emu_report_file} --timeout=14400 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} - """ - } catch (error) { - echo "${sw_emu_stage_name} SW EMU Build generation failed" - archiveArtifacts artifacts: "${example_path}/**", fingerprint: true - throw error - } finally { - run_junit(sw_emu_report_file) - git_cleanup() - } - } - } - } - - stage(hw_emu_stage_name) { - node(get_task_label(task: 'sdaccel_builds', xilinx_version: xilinx_version)) { - checkout scm - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh - export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} - python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_hw_emu --examplePath ${example_path} --junit-xml $WORKSPACE/${hw_emu_report_file} --timeout=21600 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} - """ - } catch (error) { - echo "${hw_emu_stage_name} HW EMU Build generation failed" - archiveArtifacts artifacts: "${example_path}/**", fingerprint: true - throw error - } finally { - run_junit(hw_emu_report_file) - git_cleanup() - } - } - } - - stage(hw_stage_name) { - node(get_task_label(task: 'sdaccel_builds', xilinx_version: xilinx_version)) { - checkout scm - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh - export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} - python2.7 -m pytest -s -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_hw_build --examplePath ${example_path} --junit-xml $WORKSPACE/${hw_report_file} --timeout=36000 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} - """ - } catch (error) { - echo "${hw_stage_name} HW Build generation failed" - archiveArtifacts artifacts: "${example_path}/**", fingerprint: true - throw error - } finally { - run_junit(hw_report_file) - git_cleanup() - } - } - } - - stage(create_afi_stage_name) { - node(get_task_label(task: 'create_afi', xilinx_version: xilinx_version)) { - - checkout scm - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh - export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} - python2.7 -m pytest -s -v $WORKSPACE/SDAccel/tests/test_create_sdaccel_afi.py::TestCreateSDAccelAfi::test_create_sdaccel_afi --examplePath ${example_path} --junit-xml $WORKSPACE/${create_afi_report_file} --timeout=18000 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} - """ - } catch (error) { - echo "${create_afi_stage_name} Create AFI failed" - archiveArtifacts artifacts: "${example_path}/**", fingerprint: true - throw error - } finally { - - String to_aws_dir = "${example_path}/to_aws" - - if (fileExists(to_aws_dir)) { - sh "rm -rf ${to_aws_dir}" - } - run_junit(create_afi_report_file) - git_cleanup() - } - } - } - - stage(run_example_stage_name) { - - if(disable_runtime_tests) { - echo "Runtime tests disabled. Not running ${run_example_stage_name}" - } else { - node(get_task_label(task: 'runtime', xilinx_version: xilinx_version)) { - - checkout scm - try { - sh """ - set -e - source $WORKSPACE/shared/tests/bin/setup_test_runtime_sdaccel_env.sh - export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} - python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_run_sdaccel_example.py::TestRunSDAccelExample::test_run_sdaccel_example --examplePath ${example_path} --junit-xml $WORKSPACE/${run_example_report_file} --timeout=14400 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} - """ - } catch (error) { - echo "${run_example_stage_name} Runtime example failed" - archiveArtifacts artifacts: "${example_path}/**", fingerprint: true - input message: "SDAccel Runtime test failed. Click Proceed or Abort when you are done debugging on the instance." - throw error - } finally { - run_junit(run_example_report_file) - git_cleanup() - } - } - } //else - - } - - } // sdaccel_build_stages[ e.key ] - - } //for ( def dsa in entrySet(dsa_map_for_version) ) { - } // for ( e in list_map ) - - parallel sdaccel_build_stages - } - } - } - } //for (def xilinx_version in xilinx_versions) { - parallel sdaccel_all_version_stages - } -} //============================================================================= // SDK Tests diff --git a/README.md b/README.md index f1cc5c25..91447488 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ # Overview of AWS EC2 FPGA Development Kit -The AWS EC2 FPGA Development Kit is provided by AWS to support development and runtime on [AWS FPGA instances](https://aws.amazon.com/ec2/instance-types/f1/). Amazon EC2 FPGA instances are high-performance compute instances with field programmable gate arrays (FPGAs) that are programmed to create custom hardware accelerations in EC2. F1 instances are easy to program and AWS provides everything needed to develop, simulate, debug, compile and run hardware accelerated applications. Using the [FPGA developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ), developers create an FPGA design. Once the FPGA design (also called CL - Custom logic) is complete, developers create the Amazon FPGA Image (AFI), and easily deploy it to the F1 instance. AFIs are reusable, shareable and can be deployed in a scalable and secure way. +The AWS EC2 FPGA Development Kit is provided by AWS to support development and runtime on [AWS FPGA instances](https://aws.amazon.com/ec2/instance-types/f1/). Amazon EC2 FPGA instances are high-performance compute instances with field programmable gate arrays (FPGAs) that are programmed to create custom hardware accelerations in EC2. F1 instances are easy to program and AWS provides everything needed to develop, simulate, debug, compile and run hardware accelerated applications. Using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ), developers create an FPGA design. Once the FPGA design (also called CL - Custom logic) is complete, developers create the Amazon FPGA Image (AFI), and easily deploy it to the F1 instance. AFIs are reusable, shareable and can be deployed in a scalable and secure way. ![Alt text](hdk/docs/images/f1-Instance-How-it-Works-flowchart.jpg) @@ -46,10 +46,10 @@ The AWS EC2 FPGA Development Kit is provided by AWS to support development and r | Tool | Development/Runtime | Tool location | Description | | --------|---------|---------|---------| -| SDx 2017.4, 2018.2 & 2018.3 | Development | [FPGA developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Software Defined Accelerator Development](SDAccel/README.md) | -| Vivado 2017.4, 2018.2 & 2018.3 | Development | [FPGA developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Hardware Accelerator Development](hdk/README.md) | +| SDx 2017.4, 2018.2, 2018.3 & 2019.1| Development | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Software Defined Accelerator Development](SDAccel/README.md) | +| Vivado 2017.4, 2018.2, 2018.3 & 2019.1 | Development | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Hardware Accelerator Development](hdk/README.md) | | FPGA AFI Management Tools | Runtime | [SDK - fpga\_mgmt\_tools](sdk/userspace/fpga_mgmt_tools) | Command-line tools used for FPGA management while running on the F1 instance | -| Virtual JTAG | Development (Debug) | [FPGA developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Runtime debug waveform | +| Virtual JTAG | Development (Debug) | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Runtime debug waveform | | wait\_for\_afi | Development | [wait\_for\_afi.py](shared/bin/scripts/wait_for_afi.py) | Helper script that notifies via email on AFI generation completion | | notify\_via\_sns | Development | [notify\_via\_sns.py](shared/bin/scripts/notify_via_sns.py) | Notifies developer when design build process completes | | AFI Administration | Development | [Copy](hdk/docs/copy_fpga_image.md), [Delete](hdk/docs/delete_fpga_image.md), [Describe](hdk/docs/describe_fpga_images.md), [Attributes](hdk/docs/fpga_image_attributes.md) | AWS CLI EC2 commands for managing your AFIs | @@ -85,7 +85,10 @@ AWS FPGA generation and EC2 F1 instances are supported in the us-east-1 (N. Virg ### New to AWS FPGAs and setting up a development environment? -The developer kit is supported for Linux operating systems only. You have the choice to develop on AWS EC2 using the [FPGA developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) or on-premises. Within a linux environment, you can execute `git clone https://github.com/aws/aws-fpga.git` to download the latest release to your EC2 Instance or local server. Help on cloning from github is available [here](https://help.github.com/articles/which-remote-url-should-i-use/). When using a SSH connection, execute `git clone git@github.com:aws/aws-fpga.git`. [To get help with connecting to Github via SSH](https://help.github.com/articles/connecting-to-github-with-ssh/). +The developer kit is supported for Linux operating systems only. +You have the choice to develop on AWS EC2 using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) or on-premises. Within a linux environment, you can execute `git clone https://github.com/aws/aws-fpga.git` to download the latest release to your EC2 Instance or local server. Help on cloning from github is available [here](https://help.github.com/articles/which-remote-url-should-i-use/). When using a SSH connection, execute `git clone git@github.com:aws/aws-fpga.git`. [To get help with connecting to Github via SSH](https://help.github.com/articles/connecting-to-github-with-ssh/). + +To setup your instance for development, checkout our [Developer Resources](./developer_resources/README.md) where we provide Step-By-Step guides to setting up a GUI Desktop or a compute cluster. Before you start your first AWS FPGA design, we recommend that you go through one of the step-by-step guides. The guides will walk through development steps for hello world examples. Based on the tables above, pick the development environment that best fits your needs and use the guide to get started: * For fastest way to get started on FPGA accelerator development, start with the software defined development environment. The guide starts with the [SW Hello World example](SDAccel/README.md). @@ -106,20 +109,21 @@ Once you have completed your hello world examples, we recommend diving deeper in # FPGA Developer AMI -The [FPGA developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) is available on the AWS marketplace without a software charge and includes free tools and drivers needed for FPGA development on EC2 instances. FPGA development runs on several [EC2 instance types](https://aws.amazon.com/ec2/instance-types/). Given the large size of the FPGA used inside the AWS FPGA instances, the implementation tools require 32GiB Memory (ex: z1d.xlarge, z1d.2xlarge, c5.4xlarge, m5.2xlarge, r5.xlarge, t2.2xlarge). z1d.xlarge/c5.4xlarge and z1d.2xlarge/c5.8xlarge would provide the fastest execution time with 30GiB+ and 60GiB+ of memory respectively. Developers who want to save on cost, could start coding and run simulations on low-cost instances, like t2.2xlarge, and move to the aforementioned larger instances to run the synthesis of their acceleration code. +The [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) is available on the AWS marketplace without a software charge and includes free tools and drivers needed for FPGA development on EC2 instances. FPGA development runs on several [EC2 instance types](https://aws.amazon.com/ec2/instance-types/). Given the large size of the FPGA used inside the AWS FPGA instances, the implementation tools require 32GiB Memory (ex: z1d.xlarge, z1d.2xlarge, c5.4xlarge, m5.2xlarge, r5.xlarge, t2.2xlarge). z1d.xlarge/c5.4xlarge and z1d.2xlarge/c5.8xlarge would provide the fastest execution time with 30GiB+ and 60GiB+ of memory respectively. Developers who want to save on cost, could start coding and run simulations on low-cost instances, like t2.2xlarge, and move to the aforementioned larger instances to run the synthesis of their acceleration code. -Currently, AWS marketplace includes multiple versions of the FPGA developer AMI, supporting Xilinx SDx 2017.4, 2018.2 and 2018.3 toolchain versions. The following compatibility table describes the mapping of currently supported developer kit versions to AMI versions: +Currently, AWS marketplace includes multiple versions of the FPGA Developer AMI, supporting Xilinx SDx 2017.4, 2018.2, 2018.3 and 2019.1 toolchain versions. The following compatibility table describes the mapping of currently supported developer kit versions to AMI versions: -| Developer Kit Version | Tool Version Supported | Compatible FPGA developer AMI Version | +| Developer Kit Version | Tool Version Supported | Compatible FPGA Developer AMI Version | |-----------|-----------|------| | 1.3.7-1.3.X | 2017.4 | v1.4.0-v1.4.X (Xilinx Vivado/SDx 2017.4) | | 1.4.X | 2017.4 | v1.4.0-v1.4.X (Xilinx Vivado/SDx 2017.4) | | 1.4.3+ | 2018.2 | v1.5.0-v1.5.X (Xilinx Vivado/SDx 2018.2) | | 1.4.8+ | 2018.3 | v1.6.0-v1.6.X (Xilinx Vivado/SDx 2018.3) | +| 1.4.11+ | 2019.1 | v1.7.0-v1.7.X (Xilinx Vivado/SDx 2019.1) | Developer kit versions prior to v1.3.7 and Developer AMI prior to v1.4 (2017.1) reached end-of-life. See [AWS forum announcement](https://forums.aws.amazon.com/ann.jspa?annID=6068) for additional details. - If developing using SDAccel environment please refer to this [Runtime Compatibility Table](SDAccel/docs/Create_Runtime_AMI.md#runtime-ami-compatability-table) +If developing using SDAccel environment please refer to this [Runtime Compatibility Table](SDAccel/docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table) # Hardware Development Kit (HDK) @@ -178,7 +182,7 @@ The documentation is located throughout this developer kit, therefore, to help d | AFI Management | [README](sdk/userspace/fpga_mgmt_tools/README.md) | CLI documentation for managing AFI on the F1 instance | | AFI Administration | [copy\_fpga\_image](hdk/docs/copy_fpga_image.md), [delete\_fpga\_image](hdk/docs/delete_fpga_image.md), [describe\_fpga\_images](hdk/docs/describe_fpga_images.md), [fpga\_image\_attributes](hdk/docs/fpga_image_attributes.md) | CLI documentation for administering AFIs | | AFI Creation Error Codes | [create\_fpga\_image\_error\_codes](hdk/docs/create_fpga_image_error_codes.md) | CLI documentation for managing AFIs | -| Developing on-premises | [HDK: on\_premise\_licensing\_help](hdk/docs/on_premise_licensing_help.md), [SDAccel: On\_Premises\_Development\_Steps](SDAccel/docs/On_Premises_Development_Steps.md) | Guidance for developer wanting to develop AFIs from on-premises instead of using the [FPGA developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) running on AWS EC2 | +| Developing on-premises | [HDK: on\_premise\_licensing\_help](hdk/docs/on_premise_licensing_help.md), [SDAccel: On\_Premises\_Development\_Steps](SDAccel/docs/On_Premises_Development_Steps.md) | Guidance for developer wanting to develop AFIs from on-premises instead of using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) running on AWS EC2 | diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 0fdff1a3..f500d1c6 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,7 +1,5 @@ - # AWS EC2 FPGA HDK+SDK Release Notes - ## AWS EC2 F1 Platform Features: * 1-8 Xilinx UltraScale+ VU9P based FPGA slots * Per FPGA Slot, Interfaces available for Custom Logic(CL): @@ -26,6 +24,34 @@ * 1 DDR controller implemented in the SH (always available) * 3 DDR controllers implemented in the CL (configurable number of implemented controllers allowed) +## Release 1.4.11 (See [ERRATA](./ERRATA.md) for unsupported features) +* FPGA developer kit now supports Xilinx SDx/Vivado 2019.1 + * We recommend developers upgrade to v1.4.11 to benefit from the new features, bug fixes, and optimizations. + * To upgrade, use [Developer AMI v1.7.0](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) on the AWS Marketplace. The Developer Kit scripts (hdk_setup.sh or sdaccel_setup.sh) will detect the tool version and update the environment based on requirements needed for Xilinx 2019.1 tools. +* New functionality: + * Added a [developer resources section](./developer_resources/README.md) that provides guides on how to setup your own GUI Desktop and compute cluster environment. + * Developers can now ask for AFI limit increases via the [AWS Support Center Console](https://console.aws.amazon.com/support/cases#/create). + * Create a case to increase your `EC2 FPGA` service limit from the console. + * HLx IPI flow updates + * HLx support for AXI Fast Memory mode. + * HLx support for 3rd party simulations. + * HLx support for changes in shell and AWS IP updates(e.g. sh_ddr). +* Bug Fixes: + * Documentation fixes in the [Shell Interface Specification](./hdk/docs/AWS_Shell_Interface_Specification.md) + * Fixes for forum questions + * [Unable to compile aws_v1_0_vl_rfs.sv in Synopsys VCS](https://forums.aws.amazon.com/thread.jspa?threadID=308829&tstart=0) + * [Use fpga_mgmt init in HLx runtime](https://forums.aws.amazon.com/thread.jspa?messageID=912063) + * New XRT versions added to the [XRT Installation Instructions](./SDAccel/docs/XRT_installation_instructions.md) to fix segmentation faults when using xclbin instead of awsxclbin files. +* Deprecations: + * Removed GUI Setup scripts from AMI v1.7.0 onwards. See the [developer resources section](./developer_resources/README.md) that provides guides on how to setup your own GUI Desktop and compute cluster environment. +* Package versions used for validation + + | Package | AMI 1.7.0 [2019.1] | AMI 1.6.0 [2018.3] |AMI 1.5.0 [2018.2] | AMI 1.4.0 [2017.4] | + |---------|---|------------------------|------------------------|-----------------------| + | OS | Centos 7.6 | Centos 7.6 | Centos 7.5, 7.6 | Centos 7.4 | + | kernel | 3.10.0-957.27.2.el7.x86_64 | 3.10.0-957.5.1.el7.x86_64 | 3.10.0-862.11.6.el7.x86_64, 3.10.0-957.1.3.el7.x86_64 | 3.10.0-693.21.1.el7.x86_64 | + | kernel-devel | 3.10.0-957.27.2.el7.x86_64 | 3.10.0-957.5.1.el7.x86_64 | 3.10.0-862.11.6.el7.x86_64, 3.10.0-957.1.3.el7.x86_64 | 3.10.0-693.21.1.el7.x86_64 | + | LIBSTDC++ | libstdc++-4.8.5-36.el7_6.2.x86_64 | libstdc++-4.8.5-36.el7.x86_64 | libstdc++-4.8.5-36.el7.x86_64 | libstdc++-4.8.5-16.el7_4.2.x86_64 | ## Release 1.4.10 (See [ERRATA](./ERRATA.md) for unsupported features) * New functionality: @@ -148,7 +174,7 @@ ## Release 1.4.5 (See [ERRATA](./ERRATA.md) for unsupported features) -* [Documents SDAccel Runtime compatibility](SDAccel/docs/Create_Runtime_AMI.md#runtime-ami-compatability-table) +* [Documents SDAccel Runtime compatibility](SDAccel/docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table) * [Enables SDK FPGA Mgmt tool access to Non-root users](sdk/README.md#using-fpga-as-non-root-user) * Fixed issues * [HLX simulation failure](https://forums.aws.amazon.com/thread.jspa?threadID=293313&tstart=0) @@ -161,7 +187,7 @@ ## Release 1.4.3 (See [ERRATA](./ERRATA.md) for unsupported features) * [DRAM Data Retention](hdk/docs/data_retention.md) - With DRAM data retention, developers can simply load a new AFI and continue using the data that is persistently kept in the DRAM attached to the FPGA, eliminating unnecessary data movements and greatly improving the overall application performance. * [Virtual Ethernet](./sdk/apps/virtual-ethernet/README.md) - Provides a low latency network interface for EC2 F1, that enables high performance hardware acceleration to ethernet based applications on AWS like firewalls, routers and advanced security virtual appliances. With Virtual Ethernet, developers are able to create F1 accelerators that process ethernet packets directly from user-space on the FPGA with high throughput and low-latency. -* [Developer AMI v1.5](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) with Vivado/SDx 2018.2 tools - New FPGA developer AMI supporting Vivado 2018.2 for faster compile times, higher frequencies and improved timing closure +* [Developer AMI v1.5](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) with Vivado/SDx 2018.2 tools - New FPGA Developer AMI supporting Vivado 2018.2 for faster compile times, higher frequencies and improved timing closure ## Release 1.4.2 (See [ERRATA](./ERRATA.md) for unsupported features) * Fixed SDAccel XOCL driver compile fails that occur on linux kernels greater than 3.10.0-862.3.3.el7.x86_64 @@ -265,7 +291,7 @@ The following major features are included in this HDK release: * Restrictions on URAM have been updated to enable 100% of the URAM with a CL to be utilized. See documentation on enabling URAM utilization: [URAM_options](./hdk/docs/URAM_Options.md) ### 5. Vivado IP Integrator (IPI) and GUI Workflow -* Vivado graphical design canvas and project-based flow is now supported. This flow allows developers to create CL logic as either RTL or complex subsystems based on an IP centric block diagram. Prior experience in RTL or system block designs is recommended. The [IP Integrator and GUI Vivado workflow](hdk/docs/IPI_GUI_Vivado_Setup.md) enables a unified graphical environment to guide the developer through the common steps to design, implement, and verify FGPAs. To get started, start with the [README that will take you through getting started steps and documents on IPI](hdk/docs/IPI_GUI_Vivado_Setup.md) +* Vivado graphical design canvas and project-based flow is now supported. This flow allows developers to create CL logic as either RTL or complex subsystems based on an IP centric block diagram. Prior experience in RTL or system block designs is recommended. The [IP Integrator and GUI Vivado workflow](hdk/docs/IPI_GUI_Vivado_Setup.md) enables a unified graphical environment to guide the developer through the common steps to design, implement, and verify FPGAs. To get started, start with the [README that will take you through getting started steps and documents on IPI](hdk/docs/IPI_GUI_Vivado_Setup.md) ### 6. Build Flow improvments * See [Build_Scripts](./hdk/common/shell_v04261818/build/scripts) diff --git a/SDAccel/FAQ.md b/SDAccel/FAQ.md index 9786c55d..6e3ff871 100644 --- a/SDAccel/FAQ.md +++ b/SDAccel/FAQ.md @@ -1,51 +1,59 @@ # Frequently Asked Questions (FAQ) -## Q: When I run my application on F1, I see these errors: ERROR: Failed to load xclbin ERROR: No program executable for device ERROR: buffer (2) is not resident in device (0)", how to debug these errors? -A: First double check that your AFI has been generated successfully by reviewing the SDAccel README. Second, check that you are running your application on F1 using sudo. Lastly, check that your AWS CLI (configure) was configured using output format as json. +## Q: When I run my application on F1, I see these errors: ERROR: Failed to load xclbin ERROR: No program executable for device ERROR: buffer (2) is not resident in device (0)", how to debug these errors? +A: +* Check that your AFI has been generated successfully by reviewing the SDAccel README. +* Check that you are running your application on F1 as super user(sudo). +* Lastly, check that your AWS CLI (configure) was configured using output format as json. ## Q: During AFI generation (create_sdaccel_afi.sh), how do I resolve this error: "An error occurred (AuthFailure) when calling the CreateFpgaImage operation: AWS was not able to validate the provided access credentials"? -A: For an AFI generation to complete all errors must be resolved. This error ("An error occurred (AuthFailure) when calling the CreateFpgaImage operation: AWS was not able to validate the provided access credentials") message means your AWS credentials were not setup properly or your IAM does not have access to the API (CreateFpgaImage). Here is some additional info on how to setup IAM privileges. -http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ec2-api-permissions.html +A: + +This error message means your AWS credentials or IAM role were not setup correctly to have access to the API (CreateFpgaImage). +AWS Accounts require IAM permissions to access API functions. To test your IAM permissions use [DescribeFpgaImage API](https://github.com/aws/aws-fpga/blob/master/hdk/docs/describe_fpga_images.md) + +To setup IAM privileges please check the [EC2 API Permissions documentation](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ec2-api-permissions.html) -AWS Accounts require IAM permisions to access API functions. To test your IAM permissions use DescribeFpgaImage API: -https://github.com/aws/aws-fpga/blob/master/hdk/docs/describe_fpga_images.md ## Q: During AFI generation (create_sdaccel_afi.sh), my AFI failed to generate and I see this error message in the log: "Provided clocks configuration is illegal. See AWS FPGA HDK documentation for supported clocks configuration. Frequency 0 is lower than minimal supported frequency of 80", how do I debug this message? -A: Please confirm that you successfully compiled your kernel for HW. For the quick start examples, you will need to have completed the quick start and successfully passed this command: make TARGETS=hw DEVICES=$AWS_PLATFORM all +A: +* Please confirm that you successfully compiled your kernel for HW. +* For the quick start examples, you will need to have completed the quick start and successfully passed this command: `make TARGETS=hw DEVICES=$AWS_PLATFORM all` -## Q: What is a xclbin or binary container on SDAccel? +## Q: What is a xclbin or binary container on SDAccel? What is an awsxclbin? A: The [xclbin](https://www.xilinx.com/html_docs/xilinx2017_2/sdaccel_doc/topics/design-flows/concept-create-compute-unit-binary.html) file or the "Binary Container" is a binary library of kernel compute units that will be loaded together into an OpenCL context for a specific device. -AWS uses a modified version of the xclbin called awsxclbin. The awsxclbin contains the xclbin metadata and AFI ID. +AWS uses a modified version of the xclbin called awsxclbin. The awsxclbin contains the xclbin metadata and AFI ID. ## Q: What can we investigate when xocc fails with a path not meeting timing? A: An example is WARNING: [XOCC 60-732] Link warning: One or more timing paths failed timing targeting MHz for . The frequency is being automatically changed to MHz to enable proper functionality. 1. Generally speaking, lowering the clock will make the design functionally operational in terms of operations (since there will not be timing failures) but the design might not operate at the performance needed due this clock frequency change. We can review what can be done. -1. If CLOCK_NAME is `kernel clock 'DATA_CLK'` then this is the clock that drives the kernels. Try reducing the kernel clock frequency see --kernel_frequency option to xocc in [latest SDAccel Environment User Guide] +1. If CLOCK_NAME is `kernel clock 'DATA_CLK'` then this is the clock that drives the kernels. Try reducing the kernel clock frequency see --kernel_frequency option to xocc in the [latest SDAccel Environment User Guide](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_1/ug1023-sdaccel-user-guide.pdf). 1. If CLOCK_NAME is `system clock 'clk_main_a0'` then this is the clock clk_main_a0 which drives the AXI interconnect between the AWS Shell and the rest of the platform (SDAccel peripherals and user kernels). Using --kernel_frequency as above does not have any direct effect but might have side effect in changing the topology/placement of the design and improve this issue. 1. If OCL/C/C++ kernels were also used, investigate VHLS reports / correlate with kernel source code to see if there are functions with large number of statements in basic block, examples: might have unrolled loops with large loop-count, might have a 100++ latency; the VHLS runs and log files are located in the directory named `_xocc*compile*` 1. Try `xocc -O3` to run bitstream creation process with higher efforts. -1. Open a Vivado implementation project using ```vivado `find -name ipiimpl.xpr` ``` to analyze the design; needs Vivado knowledge; see [UltraFast Design Methodology Guide for the Vivado][latest UG949] +1. Open a Vivado implementation project using ```vivado `find -name ipiimpl.xpr` ``` to analyze the design; needs Vivado knowledge; see [UltraFast Design Methodology Guide for the Vivado](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_1/ug949-vivado-design-methodology.pdf) ## Q: xocc issues message WARNING: [XOCC 204-69] Unable to schedule ...due to limited memory ports. A: This may lower the performance of the implementation. -Details on this are provided in [Debug HLS Performance: Limited memory ports] +Details on this are provided in [the SDAccel HLS Debug document](docs/SDAccel_HLS_Debug.md) ## Q: xocc fails due to routing/resource overflow -A: Examine utilization reports. If OCL/C/C++ kernels were also used, look into the source code for excessive unroll happening. +A: Examine utilization reports. If OCL/C/C++ kernels were also used, look into the source code for excessive unroll happening. ## Q: How do I open the design as a Vivado project (.xpr)? A: There are 2 Vivado project files: 1. CL Design - from command line: ```vivado `find -name ipiprj.xpr\` ``` to see the connectivity of the created design -1. Implementation project - from command line: ```vivado `find -name ipiimpl.xpr\` ``` to analyze the design in the place and routing design phases. For an additional Vivado Design reference, see [UltraFast Design Methodology Guide for the Vivado][latest UG949] +1. Implementation project - from command line: ```vivado `find -name ipiimpl.xpr\` ``` to analyze the design in the place and routing design phases. + 1. For an additional Vivado Design reference, see the [UltraFast Design Methodology Guide for the Vivado](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_1/ug949-vivado-design-methodology.pdf) ## Q: What should I do if FPGA instance execution gets the wrong results or gets stuck? A: 1. Verify hw_emu works as expected -1. See "Chapter 4 - Debugging Applications in the SDAccel Environment" in [latest SDAccel Environment User Guide] +1. See the "Debugging Applications in the SDAccel Environment" chapter in the [latest SDAccel Environment User Guide](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_1/ug1023-sdaccel-user-guide.pdf). ## Q: Bitstream creation fails to create design less that 60 MHz? A: SDAccel flow does not allow clocks running less than 60 MHz kernel clock, therefore, you will need to debug further using [HLS Debug suggestions](./docs/SDAccel_HLS_Debug.md) @@ -66,19 +74,14 @@ A: You may have run the previous [HDK IPI examples](../hdk/docs/IPI_GUI_Vivado_S ## Q: I am getting an error: `symbol lookup error: /opt/xilinx/xrt/lib/libxrt_aws.so: undefined symbol: uuid_parse` What should I do? A: This error occured because the XRT RPM was built without linking in a library needed for the uuid symbols. To fix it, use the latest XRT RPM's documented in the [XRT installation document](docs/XRT_installation_instructions.md) -# Additional Resources -The [AWS SDAccel README]. - -Xilinx web portal for [Xilinx SDAccel documentation] and for [Xilinx SDAccel GitHub repository] +# Additional Resources -Links pointing to **latest** version of the user guides - * [UG1023: SDAccel Environment User Guide][latest SDAccel Environment User Guide] - * [UG1021: SDAccel Environment Tutorial: Getting Started Guide (including emulation/build/running on H/W flow)][latest UG1021] - * [UG1207: SDAccel Environment Optimization Guide][latest SDAccel Environment Optimization Guide] - * [UG949: UltraFast Design Methodology Guide for the Vivado Design Suite][latest UG949] +* The [AWS SDAccel README](README.md). +* Xilinx web portal for [Xilinx SDAccel documentation](https://www.xilinx.com/products/design-tools/software-zone/sdaccel.html?resultsTablePreSelect=xlnxdocumenttypes:SeeAll#documentation) +* [Xilinx SDAccel GitHub repository](https://github.com/Xilinx/SDAccel_Examples) -Links pointing to **2017.4** version of the user guides +* Links pointing to **2017.4** version of the user guides * [UG1023: SDAccel Environment User Guide][UG1023 2017.4] * [UG1021: SDAccel Environment Tutorial: Getting Started Guide (including emulation/build/running on H/W flow)][UG1021 2017.4] * [UG1207: SDAccel Environment Optimization Guide][UG1207 2017.4] diff --git a/SDAccel/README.md b/SDAccel/README.md index 2bfdfa23..e89c4fb4 100644 --- a/SDAccel/README.md +++ b/SDAccel/README.md @@ -63,9 +63,7 @@ It is highly recommended you read the documentation and utilize software and har $ cd $AWS_FPGA_REPO_DIR $ source sdaccel_setup.sh ``` - * This section describes the valid platforms for shell_v04261818 - * Xilinx Tool 2017.4 Platform: - * AWS_PLATFORM_DYNAMIC_5_0 - (Default) AWS F1 platform dynamically optimized for multi DDR use cases. + * Valid platforms for shell_v04261818: `AWS_PLATFORM_DYNAMIC_5_0` (Default) AWS F1 platform dynamically optimized for multi DDR use cases. * Changing to a different platform can be accomplished by setting AWS_PLATFORM environment variable. Only one platform is supported for this example:   ``` @@ -139,7 +137,7 @@ This assumes you have: The [create_sdaccel_afi.sh](./tools/create_sdaccel_afi.sh) script is provided to facilitate AFI creation from a Xilinx FPGA Binary, it: * Takes in your Xilinx FPGA Binary \*.xclbin file -* Calls *aws ec2 create_fgpa_image* to generate an AFI under the hood +* Calls *aws ec2 create_fpga_image* to generate an AFI under the hood * Generates a \_afi_id.txt which contains the identifiers for your AFI * Creates an AWS FPGA Binary file with an \*.awsxclbin extension that is composed of: Metadata and AGFI-ID. * **This \*.awsxclbin is the AWS FPGA Binary file that will need to be loaded by your host application to the FPGA** @@ -193,12 +191,11 @@ For help with AFI creation issues, see [create-fpga-image error codes](../hdk/do # 3. Run the FPGA accelerated application on Amazon FPGA instances -Here are the steps: -* Start an FPGA instance using [FPGA Developer AMI on AWS Marketplace](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) and check the AMI [compatiability table](../README.md#devAmi) and [runtime compatilibility table](docs/Create_Runtime_AMI.md#runtime-ami-compatability-table). Alternatively, you can [create your own Runtime AMI](docs/Create_Runtime_AMI.md) for running your SDAccel applications on Amazon FPGA instances. +* Start an FPGA instance using [FPGA Developer AMI on AWS Marketplace](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) and check the AMI [compatibility table](../README.md#devAmi) and [runtime compatibility table](docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table). Alternatively, you can [create your own Runtime AMI](docs/Create_Runtime_AMI.md) for running your SDAccel applications on Amazon FPGA instances. * *Assuming the developer flow (compilation) was done on a separate instance you will need to:* * Copy the compiled host executable (exe) to the new instance * Copy the \*.awsxclbin AWS FPGA binary file to the new instance - * Depending on the host code, the \*.awsxclbin may need to named .hw..awsxclbin . Ex: ```vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin``` + * Depending on the host code, the \*.awsxclbin may need to named \.hw.\.awsxclbin .For Example: ```vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin``` * Copy any data files required for execution to the new instance * [Clone the github repository to the new F1 instance and install runtime drivers](#gitsetenv) * Clone the github repository to the new F1 instance and install runtime drivers @@ -212,7 +209,7 @@ Here are the steps: * Source the Runtime Environment & Execute your Host Application: ``` - $ sudo sh + $ sudo -E /bin/bash # source $AWS_FPGA_REPO_DIR/sdaccel_runtime_setup.sh # Other runtime env settings needed by the host app should be setup after this step # ./helloworld ``` diff --git a/SDAccel/docs/Create_Runtime_AMI.md b/SDAccel/docs/Create_Runtime_AMI.md index 1bd05c22..eadaf4ec 100644 --- a/SDAccel/docs/Create_Runtime_AMI.md +++ b/SDAccel/docs/Create_Runtime_AMI.md @@ -1,19 +1,20 @@ # Create a Runtime AMI Starting with an Amazon Linux AMI or Ubuntu -## Runtime AMI Compatability Table +## Runtime AMI Compatibility Table | SDx Version used for AFI Development | Compatible SDAccel Runtime | |--------------------------------------|-----------------------------| | 2017.4 | Runtime installed by sourcing "sdaccel_setup.sh" while using HDK Ver 1.4.X when environment variable RELEASE_VER=2017.4 | - | 2018.2 | AWS FPGA Developer AMI 1.5.0 ( XRT is pre-installed) or [Runtime installed with XRT Version 2.1.0](https://www.xilinx.com/html_docs/xilinx2018_2_xdf/sdaccel_doc/ejy1538090924727.html) | - | 2018.3 | AWS FPGA Developer AMI 1.6.0 ( XRT is pre-installed) or [Runtime installed with XRT Version 2.1.0](https://xilinx.github.io/XRT/2018.3/html/build.html) | + | 2018.2 | AWS FPGA Developer AMI 1.5.0 (XRT is pre-installed) or [Runtime installed with XRT Version 2.1.0](https://www.xilinx.com/html_docs/xilinx2018_2_xdf/sdaccel_doc/ejy1538090924727.html) | + | 2018.3 | AWS FPGA Developer AMI 1.6.0 (XRT is pre-installed) or [Runtime installed with XRT Version 2.1.0](https://xilinx.github.io/XRT/2018.3/html/build.html) | + | 2019.1 | AWS FPGA Developer AMI 1.7.0 (XRT is pre-installed) or [Runtime installed with XRT Version 2.1.0](https://xilinx.github.io/XRT/2019.1/html/build.html) | ## 1. Launch a Runtime Instance & Install Required Packages * Please note Amazon Linux 2 or Amazon Linux are not supported by Xilinx XRT at this time. Please use Centos/RHEL or Ubuntu when using Xilinx XRT Runtimes for the AFIs generated using Xilinx SDx 2018.2 and 2018.3 toolsets. -* Launch an F1 instance using an [Amazon Linux AMI](https://aws.amazon.com/marketplace/pp/B00635Y2IW) or [Centos 7](https://aws.amazon.com/marketplace/pp/B00O7WM7QW) -* Install the required updates +* Launch an F1 instance using [Centos 7](https://aws.amazon.com/marketplace/pp/B00O7WM7QW) or Amazon Linux AMI's +* Update to get the latest packages. ```` $ sudo yum update @@ -54,11 +55,11 @@ * Using an instance running [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) or an on-premises machine with access to a Xilinx SDAccel Tools Installation, first source $AWS_FPGA_REPO_DIR/sdaccel_setup.sh and then run following commands: -* if using Ubuntu or debian distribution set GLIBPATH env variable to Ubuntu. If using any other OS distribution set GLIBPATH to default. +* If using Ubuntu or Debian distributions set GLIBPATH env variable to Ubuntu. If using any other OS distribution set GLIBPATH to default. -* set env variable 'XLNXRTE' to intended runtime install directory path. +* Set env variable 'XLNXRTE' to intended runtime install directory path. -### **For Vivado SDX 2017.4** +### **Xilinx SDX 2017.4: ** ```` $ export GLIBPATH= @@ -79,14 +80,12 @@ * You may need to update path in $XLNXRTE/setup.sh and $XLNXRTE/setup.csh script to match your runtime instance. * Copy $XLNXRTE directory created to $HOME on your Runtime Instance. -### **For Vivado SDX 2018.2** - - Please refer [installing Xilinx SDx 2018.2 XRT](https://www.xilinx.com/html_docs/xilinx2018_2_xdf/sdaccel_doc/ejy1538090924727.html) for instructions on how to install XRT on your AMI. +### **Xilinx SDx 2018.2:** [Install 2018.2 XRT](https://www.xilinx.com/html_docs/xilinx2018_2_xdf/sdaccel_doc/ejy1538090924727.html). -### **For Vivado SDX 2018.3** - - Please refer [installing Xilinx SDx 2018.3 XRT](https://xilinx.github.io/XRT/2018.3/html/build.html) for instructions on how to install runtime on your AMI. +### **Xilinx SDx 2018.3:** [Install 2018.3 XRT](https://xilinx.github.io/XRT/2018.3/html/build.html). +### **Xilinx SDx 2019.1:** [Install 2019.1 XRT](https://xilinx.github.io/XRT/2019.1/html/build.html). + ## 3. Install Runtime Drivers and run your FPGA accelerated application on your Runtime Instance. * Log back on to the Runtime Instance: diff --git a/SDAccel/docs/README_GUI.md b/SDAccel/docs/README_GUI.md index 0818eaac..4ca59dcd 100644 --- a/SDAccel/docs/README_GUI.md +++ b/SDAccel/docs/README_GUI.md @@ -7,7 +7,7 @@ The guide explains how to: 1. Verify the application 1. Build the application to execute on FPGA hardware -**Note**: It is highly recommended to review the [SDAccel Guide][SDAccel_Guide] to fully understand the SDAccel flow before using the GUI. +**Note**: It is highly recommended to review the [AWS F1 SDAccel Guide](SDAccel_Guide_AWS_F1.md) to fully understand the SDAccel flow before using the GUI. ## Cloning the aws-fpga Git repository The AWS Github repository contains the example used in this tutorial. diff --git a/SDAccel/docs/SDAccel_Guide_AWS_F1.md b/SDAccel/docs/SDAccel_Guide_AWS_F1.md index 98cffd63..66bf0a73 100644 --- a/SDAccel/docs/SDAccel_Guide_AWS_F1.md +++ b/SDAccel/docs/SDAccel_Guide_AWS_F1.md @@ -164,42 +164,19 @@ Conversely, code which is simply a few lines of basic operations, and has no tas # Additional Resources -The [AWS SDAccel README]. - -Xilinx web portal for [Xilinx SDAccel documentation] and for [Xilinx SDAccel GitHub repository] - - -Links pointing to **2017.4** version of the user guides -1. [UG1023: SDAccel Environment User Guide][UG1023 2017.4] -1. [UG1021: SDAccel Environment Tutorial: Getting Started Guide (including emulation/build/running on H/W flow)][UG1021 2017.4] -1. [UG1207: SDAccel Environment Optimization Guide][UG1207 2017.4] -1. [UG949: UltraFast Design Methodology Guide for the Vivado Design Suite][UG949 2017.4] -1. [UG1238: SDx Development Environment Release Notes, Installation, and Licensing Guide][UG1238 2017.4] - - - -[SDAccel_landing_page]: https://www.xilinx.com/products/design-tools/software-zone/sdaccel.html -[VHLS_landing_page]: https://www.xilinx.com/products/design-tools/vivado/integration/esl-design.html -[Vivado_landing_page]: https://www.xilinx.com/products/design-tools/vivado.html - -[SDAccel Environment User Guide]: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug1023-sdaccel-user-guide.pdf -[UG1021]: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug1021-sdaccel-intro-tutorial.pdf -[SDAccel Environment Optimization Guide]: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug1207-sdaccel-optimization-guide.pdf -[UG949]: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug949-vivado-design-methodology.pdf -[UG902]: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug902-vivado-high-level-synthesis.pdf - -[UG1023 2017.4]: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug1023-sdaccel-user-guide.pdf -[UG1021 2017.4]: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug1021-sdaccel-intro-tutorial.pdf -[UG1207 2017.4]: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug1207-sdaccel-optimization-guide.pdf -[UG1238 2017.4]:http://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug1238-sdx-rnil.pdf -[Xilinx SDAccel documentation]: https://www.xilinx.com/products/design-tools/software-zone/sdaccel.html#documentation -[Xilinx SDAccel GitHub repository]: https://github.com/Xilinx/SDAccel_Examples -[UG949 2017.4]: https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug949-vivado-design-methodology.pdf - -[AWS SDAccel Readme]: ../README.md -[OnPremiseDev]: ./On_Premises_Development_Steps.md -[Power_Analysis]: ./SDAccel_Power_Analysis.md -[GUI_README]: ./README_GUI.md -[FAQ]:../FAQ.md +* The [AWS SDAccel README](../README.md). +* Xilinx web portal for [Xilinx SDAccel documentation](https://www.xilinx.com/products/design-tools/software-zone/sdaccel.html?resultsTablePreSelect=xlnxdocumenttypes:SeeAll#documentation) +* [Xilinx SDAccel GitHub repository](https://github.com/Xilinx/SDAccel_Examples) +* [Xilinx SDAccel landing page](https://www.xilinx.com/products/design-tools/software-zone/sdaccel.html) +* [Vivado HLS landing page](https://www.xilinx.com/products/design-tools/vivado/integration/esl-design.html) +* [Vivado landing page](https://www.xilinx.com/products/design-tools/vivado.html) +* [SDAccel Environment User Guide](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug1023-sdaccel-user-guide.pdf) +* [SDAccel Intro Tutorial](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug1021-sdaccel-intro-tutorial.pdf) +* [SDAccel Environment Optimization Guide](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug1207-sdaccel-optimization-guide.pdf) +* [UltraFast Design Methodology Guide](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug949-vivado-design-methodology.pdf) +* [Vivado High Level Synthesis User Guide](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2017_4/ug902-vivado-high-level-synthesis.pdf) +* [On Premise Development steps](On_Premises_Development_Steps.md) +* [SDAccel Power Analysis](SDAccel_Power_Analysis.md) +* [FAQ](../FAQ.md) diff --git a/SDAccel/docs/SDAccel_HLS_Debug.md b/SDAccel/docs/SDAccel_HLS_Debug.md index dffbba14..6b0d4901 100755 --- a/SDAccel/docs/SDAccel_HLS_Debug.md +++ b/SDAccel/docs/SDAccel_HLS_Debug.md @@ -1,4 +1,4 @@ -# Debug HLS Performance: Limited memory ports. +# Debug HLS Performance: Limited memory ports In an ideal FPGA implementation, the kernel will process 1 data sample per clock cycle. In the High-Level Synthesis (HLS) technology used in SDAccel, this is referred to an II=1 implementation, where II is the Initiation Interval of design, or the number of clock cycles before the design can read new data inputs. diff --git a/SDAccel/docs/SDAccel_Migrate_dynamic_DSA.md b/SDAccel/docs/SDAccel_Migrate_dynamic_DSA.md index 7dac1ee4..b48b9afe 100644 --- a/SDAccel/docs/SDAccel_Migrate_dynamic_DSA.md +++ b/SDAccel/docs/SDAccel_Migrate_dynamic_DSA.md @@ -47,7 +47,7 @@ set_property sdx_kernel_type rtl [ipx::current_core] * Profiling hardware no longer pre-built in the platform. Instead, it is added compile time to the design. * This requires an update to the xocc command options. * (2017.4) Add the -profile_kernel option the xocc command to enable profile instrumentation when compiling the kernel; set profile=true in the sdaccel.ini file to collect profile data when running the application. - + * (2019.1) Add the -profile_kernel option the xocc command to enable profile instrumentation when compiling the kernel; set profile=true in the xrt.ini file to collect profile data when running the application. ## Additional resources * [SDAccel Development Enviroment - Changes for 2017.4](https://www.xilinx.com/html_docs/xilinx2017_4/sdaccel_doc/jdl1512623841682.html) * [SDAccel Development Enviroment - Whats new for 2017.4](https://www.xilinx.com/html_docs/xilinx2017_4/sdaccel_doc/rke1512623904797.html) diff --git a/SDAccel/docs/Setup_AWS_CLI_and_S3_Bucket.md b/SDAccel/docs/Setup_AWS_CLI_and_S3_Bucket.md index 2b1bdeb4..288e6527 100644 --- a/SDAccel/docs/Setup_AWS_CLI_and_S3_Bucket.md +++ b/SDAccel/docs/Setup_AWS_CLI_and_S3_Bucket.md @@ -1,7 +1,7 @@ ## Setup CLI and Create S3 Bucket -The developer is required to create a S3 bucket for the AFI generation. The bucket will contain a tar file and logs which are generated from the AFI creation service. +The developer is required to create an S3 bucket for the AFI generation. The bucket will contain a tar file and logs which are generated from the AFI creation service. -To install the AWS CLI, please follow the instructions here: (http://docs.aws.amazon.com/cli/latest/userguide/installing.html). +To install the AWS CLI, please follow the [instructions here](http://docs.aws.amazon.com/cli/latest/userguide/installing.html). The AWS SDAccel scripts require JSON output format and the scripts will not work properly if you use any other output format types (ex: text, table). JSON is the default output format of the AWS CLI. diff --git a/SDAccel/docs/XRT_installation_instructions.md b/SDAccel/docs/XRT_installation_instructions.md index 00f1a5ab..16bec5d5 100644 --- a/SDAccel/docs/XRT_installation_instructions.md +++ b/SDAccel/docs/XRT_installation_instructions.md @@ -1,123 +1,61 @@ -# XRT Installation Instructions - -# Installing Xilinx Runtime (XRT) 2018.3 RC3 Patch 2 - - * Applicable SDx Tool Version: 2018.3 - - * XRT Release Tag: 2018.3.3.2 (SHA: f96913247f94f4bc3b5134c92a0decc138351038) - - * [Xilinx Runtime (XRT) 2018.3 RC3 Patch 2 release](https://github.com/Xilinx/XRT/releases/tag/2018.3.3.2) - - ### Instructions to build & install XRT - - Pre-requisite commands used to build XRT for AWS F1 platform for this release - - ``` - git clone http://www.github.com/aws/aws-fpga.git - cd aws-fpga - source sdaccel_setup.sh - mkdir $SDACCEL_DIR/Runtime - cd $SDACCEL_DIR/Runtime - export XRT_PATH="${SDACCEL_DIR}/Runtime/XRT_2018.3.3.2" - git clone http://www.github.com/Xilinx/XRT.git -b 2018.3.3.2 ${XRT_PATH} - cd ${XRT_PATH} - sudo ./src/runtime_src/tools/scripts/xrtdeps.sh - cd build - - ``` - - Follow [Xilinx's instructions to build & install XRT on Centos/Redhat & Ubuntu/Debian](https://xilinx.github.io/XRT/master/html/build.html#xrt-for-pcie-platforms) to build XRT for a supported OS. - - ### Install on Centos/RHEL using prebuilt RPM - - ``` - - curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.6.0/Patches/XRT_2018_3_RC3_Patch2/xrt_201830.2.1.0_7.6.1810-xrt.rpm -o xrt_201830.2.1.0_7.6.1810-xrt.rpm - curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.6.0/Patches/XRT_2018_3_RC3_Patch2/xrt_201830.2.1.0_7.6.1810-aws.rpm -o xrt_201830.2.1.0_7.6.1810-aws.rpm - sudo yum remove -y xrt-aws - sudo yum remove -y xrt - sudo yum install -y xrt_201830.2.1.0_7.6.1810-xrt.rpm - sudo yum install -y xrt_201830.2.1.0_7.6.1810-aws.rpm - - ``` - -# Installing Xilinx Runtime (XRT) 2018.2_XDF.RC4 - - * Applicable SDx Tool Version: 2018.2 - - * XRT Release Tag: 2018.2_XDF.RC4 (SHA: 343186f76f59edd01bc48d84cf67fe22a0a3f338) - - * [Xilinx Runtime (XRT) 2018.2_XDF.RC4 release](https://github.com/Xilinx/XRT/tree/2018.2_XDF.RC4) - - ### Instructions to build & install XRT - - Pre-requisite commands used to build XRT for AWS F1 platform for this release - - ``` - git clone http://www.github.com/aws/aws-fpga.git - cd aws-fpga - source sdaccel_setup.sh - mkdir $SDACCEL_DIR/Runtime - cd $SDACCEL_DIR/Runtime - export XRT_PATH="${SDACCEL_DIR}/Runtime/XRT_20182rc4" - git clone http://www.github.com/Xilinx/XRT.git -b 2018.2_XDF.RC4 ${XRT_PATH} - cd ${XRT_PATH} - sudo ./src/runtime_src/tools/scripts/xrtdeps.sh - cd build - - ``` - Follow [ Xilinx's instructions to build & install XRT on Centos/RedHat & Ubuntu/Debian](https://www.xilinx.com/html_docs/xilinx2018_2_xdf/sdaccel_doc/ejy1538090924727.html) to build XRT for supported OS. - - ### Install on Centos/RedHat Linux using prebuilt RPMs - - Run following commands to download and install XRT 2018.2_XDF.RC4 for 'Centos/RHEL' - - ``` - curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.5.0/Patches/xrt_201802.2.1.0_7.5.1804-xrt.rpm -o xrt_201802.2.1.0_7.5.1804-xrt.rpm - curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.5.0/Patches/xrt_201802.2.1.0_7.5.1804-aws.rpm -o xrt_201802.2.1.0_7.5.1804-aws.rpm - sudo yum remove -y xrt - sudo yum install -y xrt_201802.2.1.0_7.5.1804-xrt.rpm - sudo yum install -y xrt_201802.2.1.0_7.5.1804-aws.rpm - - ``` - -# Installing Xilinx Runtime (XRT) 2018.2_XDF.RC5 - - * Applicable SDx Tool Version: 2018.2 - - * XRT Release Tag: 2018.2_XDF.RC5 (SHA: 65ffad62f427c0bd1bc65b6ea555a810295468b7) - - * [Xilinx Runtime (XRT) 2018.2_XDF.RC5 release](https://github.com/Xilinx/XRT/releases/tag/2018.2_XDF.RC5) - - ### Instructions to build & install XRT - - Pre-requisite commands used to build XRT for AWS F1 platform for this release - - ``` - git clone http://www.github.com/aws/aws-fpga.git - cd aws-fpga - source sdaccel_setup.sh - mkdir $SDACCEL_DIR/Runtime - cd $SDACCEL_DIR/Runtime - export XRT_PATH="${SDACCEL_DIR}/Runtime/XRT_20182rc5 " - git clone http://www.github.com/Xilinx/XRT.git -b 2018.2_XDF.RC5 ${XRT_PATH} - cd ${XRT_PATH} - sudo ./src/runtime_src/tools/scripts/xrtdeps.sh - cd build - - ``` - Follow [ Xilinx's instructions to build & install XRT on Centos/RedHat & Ubuntu/Debian](https://www.xilinx.com/html_docs/xilinx2018_2_xdf/sdaccel_doc/ejy1538090924727.html) to build XRT for supported OS. - - ### Install on Centos/RedHat Linux using prebuilt RPMs - - Run following commands to download and install XRT 2018.2_XDF.RC5 for 'Centos/RHEL' - - ``` - curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.5.0/Patches/XRT_2018_2_XDF_RC5/xrt_201802.2.1.0_7.5.1804-xrt.rpm -o xrt_201802.2.1.0_7.5.1804-xrt.rpm - curl -s https://s3.amazonaws.com/aws-fpga-developer-ami/1.5.0/Patches/XRT_2018_2_XDF_RC5/xrt_201802.2.1.0_7.5.1804-aws.rpm -o xrt_201802.2.1.0_7.5.1804-aws.rpm - sudo yum remove -y xrt-aws - sudo yum remove -y xrt - sudo yum install -y xrt_201802.2.1.0_7.5.1804-xrt.rpm - sudo yum install -y xrt_201802.2.1.0_7.5.1804-aws.rpm - - ``` +# Xilinx Runtime (XRT) and SDx Tool versions + +* Xilinx Runtime versions match with the tool that you created your SDAccel AFI with. +* We provide pre-built RPM's for Centos/RHEL and instructions for building XRT +* Use the below table as reference to install and use the correct XRT version for your applications. + +| Xilinx SDx Tool Version | XRT Release Tag | SHA | `xrt` and `xrt-aws` pre-built RPM's (Centos/RHEL) | +|---|---|---|---| +|2019.1| [2019.1_RC2](https://github.com/Xilinx/XRT/releases/tag/2019.1_RC2) | dd210161e204e882027d22132725d8ffdf285149 | [xrt_201910.2.2.0_7.6.1810-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.7.0/Patches/XRT_2019_1_RC2/xrt_201910.2.2.0_7.6.1810-xrt.rpm) [xrt_201910.2.2.0_7.6.1810-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.7.0/Patches/XRT_2019_1_RC2/xrt_201910.2.2.0_7.6.1810-aws.rpm) | +|2018.3| [2018.3_RC5](https://github.com/Xilinx/XRT/releases/tag/2018.3_RC5) | 8654da1f0d2bd196c9887bdcfe1479103a93e90a | [xrt_201830.2.1.0_7.6.1810-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.6.0/Patches/XRT_2018_3_RC5/xrt_201830.2.1.0_7.6.1810-xrt.rpm) [xrt_201830.2.1.0_7.6.1810-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.6.0/Patches/XRT_2018_3_RC5/xrt_201830.2.1.0_7.6.1810-aws.rpm) | +|2018.2| [2018.2_XDF.RC5](https://github.com/Xilinx/XRT/releases/tag/2018.2_XDF.RC5) | 65ffad62f427c0bd1bc65b6ea555a810295468b7 | [xrt_201802.2.1.0_7.5.1804-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.5.0/Patches/XRT_2018_2_XDF_RC5/xrt_201802.2.1.0_7.5.1804-xrt.rpm) [xrt_201802.2.1.0_7.5.1804-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.5.0/Patches/XRT_2018_2_XDF_RC5/xrt_201802.2.1.0_7.5.1804-aws.rpm) | +|2017.4| N/A** | N/A** | N/A** | +** Use XOCL for 2017.4 + +# Centos/RHEL build and install steps + +```bash +XRT_RELEASE_TAG=2019.1_RC2 # Substitute XRT_RELEASE_TAG= + +git clone https://github.com/aws/aws-fpga.git + +cd aws-fpga +source sdaccel_setup.sh +cd $SDACCEL_DIR/Runtime +export XRT_PATH="${SDACCEL_DIR}/Runtime/${XRT_RELEASE_TAG}" +git clone http://www.github.com/Xilinx/XRT.git -b ${XRT_RELEASE_TAG} ${XRT_PATH} + +cd ${XRT_PATH} +sudo ./src/runtime_src/tools/scripts/xrtdeps.sh + +cd build +scl enable devtoolset-6 bash +./build.sh + +cd Release +sudo yum reinstall xrt_*.rpm -y +``` + +# Centos/RHEL pre-built RPM install steps + +### 2019.1 + +```bash +curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.7.0/Patches/XRT_2019_1_RC2/xrt_201910.2.2.0_7.6.1810-xrt.rpm -o xrt.rpm +curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.7.0/Patches/XRT_2019_1_RC2/xrt_201910.2.2.0_7.6.1810-aws.rpm-o xrt-aws.rpm +sudo yum reinstall xrt*.rpm -y +``` +### 2018.3 + +```bash +curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.6.0/Patches/XRT_2018_3_RC5/xrt_201830.2.1.0_7.6.1810-xrt.rpm -o xrt.rpm +curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.6.0/Patches/XRT_2018_3_RC5/xrt_201830.2.1.0_7.6.1810-aws.rpm -o xrt-aws.rpm +sudo yum reinstall xrt*.rpm -y +``` +### 2018.2 + +```bash +curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.5.0/Patches/XRT_2018_2_XDF_RC5/xrt_201802.2.1.0_7.5.1804-xrt.rpm -o xrt.rpm +curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.5.0/Patches/XRT_2018_2_XDF_RC5/xrt_201802.2.1.0_7.5.1804-aws.rpm -o xrt-aws.rpm +sudo yum reinstall xrt*.rpm -y +``` \ No newline at end of file diff --git a/SDAccel/examples/3rd_party/vector_addition/vector_addition_main.cpp.diff b/SDAccel/examples/3rd_party/vector_addition/vector_addition_main.cpp.diff index 9d850916..94075d89 100644 --- a/SDAccel/examples/3rd_party/vector_addition/vector_addition_main.cpp.diff +++ b/SDAccel/examples/3rd_party/vector_addition/vector_addition_main.cpp.diff @@ -1,22 +1,45 @@ ---- third_party/vector_add/host/src/main.cpp 2017-05-09 22:47:50.000000000 +0000 -+++ sdaccel/vector_add/host/src/main.cpp 2017-09-12 18:55:22.172000000 +0000 -@@ -70,0 +71,2 @@ +--- third_party/vector_add/host/src/main.cpp 2018-02-12 17:55:18.000000000 +0000 ++++ aws/vector_add/host/src/main.cpp 2019-09-15 22:53:15.593553611 +0000 +@@ -67,6 +67,7 @@ + #endif /* USE_SVM_API == 0 */ + scoped_array > ref_output; // num_devices elements + scoped_array n_per_device; // num_devices elements +std::string hwtype = "hw"; -+ -@@ -85,0 +88,3 @@ + + // Function prototypes + float rand_float(); +@@ -84,6 +85,9 @@ + N = options.get("n"); + } + + if(options.has("hw")) { + hwtype = options.get("hw"); + } -@@ -123 +128 @@ -- platform = findPlatform("Intel"); -+ platform = findPlatform("Xilinx"); -@@ -125 +130 @@ -- printf("ERROR: Unable to find Intel FPGA OpenCL platform.\n"); + // Initialize OpenCL. + if(!init_opencl()) { + return -1; +@@ -120,9 +124,9 @@ + } + + // Get the OpenCL platform. +- platform = findPlatform("Intel(R) FPGA SDK for OpenCL(TM)"); ++ platform = findPlatform("Xilinx); + if(platform == NULL) { +- printf("ERROR: Unable to find Intel(R) FPGA OpenCL platform.\n"); + printf("ERROR: Unable to find Xilinx FPGA OpenCL platform.\n"); -@@ -143,2 +148,4 @@ + return false; + } + +@@ -140,8 +144,10 @@ + + // Create the program for all device. Use the first device as the + // representative device (assuming all device are of the same type). - std::string binary_file = getBoardBinaryFile("vector_add", device[0]); - printf("Using AOCX: %s\n", binary_file.c_str()); + std::string fname = "xclbin/vector_add."+ hwtype + "." + VERSION_STR; + printf("Looking for %s.\n",fname.c_str()); + std::string binary_file = getBoardBinaryFile(fname.c_str(), device[0]); + printf("Using XCLBIN: %s\n", binary_file.c_str()); + program = createProgramFromBinary(context, binary_file.c_str(), device, num_devices); + + // Build the program that was just created. diff --git a/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/helloworld b/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3_2019.1/helloworld similarity index 100% rename from SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/helloworld rename to SDAccel/examples/aws/helloworld_ocl_runtime/2018.3_2019.1/helloworld diff --git a/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/helloworld_ocl_afi-ids.txt b/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3_2019.1/helloworld_ocl_afi-ids.txt similarity index 100% rename from SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/helloworld_ocl_afi-ids.txt rename to SDAccel/examples/aws/helloworld_ocl_runtime/2018.3_2019.1/helloworld_ocl_afi-ids.txt diff --git a/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/helloworld_ocl_agfi-ids.txt b/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3_2019.1/helloworld_ocl_agfi-ids.txt similarity index 100% rename from SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/helloworld_ocl_agfi-ids.txt rename to SDAccel/examples/aws/helloworld_ocl_runtime/2018.3_2019.1/helloworld_ocl_agfi-ids.txt diff --git a/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/sdaccel.ini b/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3_2019.1/sdaccel.ini similarity index 100% rename from SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/sdaccel.ini rename to SDAccel/examples/aws/helloworld_ocl_runtime/2018.3_2019.1/sdaccel.ini diff --git a/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin b/SDAccel/examples/aws/helloworld_ocl_runtime/2018.3_2019.1/vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin similarity index 100% rename from SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin rename to SDAccel/examples/aws/helloworld_ocl_runtime/2018.3_2019.1/vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin diff --git a/SDAccel/examples/aws/helloworld_ocl_runtime/README.md b/SDAccel/examples/aws/helloworld_ocl_runtime/README.md index 1782662b..a8c9ad2a 100644 --- a/SDAccel/examples/aws/helloworld_ocl_runtime/README.md +++ b/SDAccel/examples/aws/helloworld_ocl_runtime/README.md @@ -31,23 +31,19 @@ vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin --awsxclbin ## Execution - -#### :exclamation: PLEASE NOTE: xclbin & awsxclbin file formats have changed for SDx 2018.3. xclbin & awsxclbin files generated using earlier SDx versions are not compatible with 2018.3 based XRTs. If you are using a 2018.3 based XRT, please copy over awsxclbin & helloworld executable files provided in the 2018.3 subdirectory to this folder. - -Command sequence +#### :exclamation: PLEASE NOTE: xclbin & awsxclbin file formats have changed from SDx 2018.3 onwards. xclbin & awsxclbin files generated using earlier SDx versions are not compatible with 2018.3/2019.1 based XRTs. If you are using a 2018.3/2019.1 based XRT, please copy over awsxclbin & helloworld executable files provided in the 2018.3_2019.1 subdirectory to this folder. ``` sudo fpga-clear-local-image -S 0 - >>$sudo sh -sh-4.2# source $AWS_FPGA_REPO_DIR/sdaccel_runtime_setup.sh -sh-4.2# ./helloworld - +sudo -E /bin/bash +source $AWS_FPGA_REPO_DIR/sdaccel_runtime_setup.sh +./helloworld ``` ## Hello World Example Metadata -| Key | Region | Value for 2017.4 or 2018.2 | Value for 2018.3 | +| Key | Region | SDx 2017.4 or 2018.2 | SDx 2018.3 or 2019.1 | |--------|---------|-----------------------------|------------------| |afi id | us-east-1(N. Virginia) | afi-0532379b26ea13f26 | afi-0c8210915ce9bab5c | |afi id | us-west-2(oregon) | afi-0ab098d3fbfc43c7e | afi-01e237aa978aa74de | diff --git a/SDAccel/examples/xilinx_2019.1 b/SDAccel/examples/xilinx_2019.1 new file mode 160000 index 00000000..0ec1aef5 --- /dev/null +++ b/SDAccel/examples/xilinx_2019.1 @@ -0,0 +1 @@ +Subproject commit 0ec1aef54f3bf17c78581630d687b13fadae9616 diff --git a/SDAccel/kernel_version.txt b/SDAccel/kernel_version.txt index 2ecfd922..79db7d8b 100644 --- a/SDAccel/kernel_version.txt +++ b/SDAccel/kernel_version.txt @@ -2,3 +2,4 @@ 3.10.0-693.21.1.el7.x86_64 3.10.0-957.1.3.el7.x86_64 3.10.0-957.5.1.el7.x86_64 +3.10.0-957.27.2.el7.x86_64 \ No newline at end of file diff --git a/SDAccel/sdaccel_xrt_version.txt b/SDAccel/sdaccel_xrt_version.txt index cff9b8f5..89feedc2 100644 --- a/SDAccel/sdaccel_xrt_version.txt +++ b/SDAccel/sdaccel_xrt_version.txt @@ -1,5 +1,5 @@ 2018.2:343186f76f59edd01bc48d84cf67fe22a0a3f338 2018.2:65ffad62f427c0bd1bc65b6ea555a810295468b7 -2018.3:f96913247f94f4bc3b5134c92a0decc138351038 -2018.3:3636217b633930ed4815abd598324691ca25c2f3 -2018.3:48cafdc100b29843fd013d371ffba0141db06b7a \ No newline at end of file +2018.3:8654da1f0d2bd196c9887bdcfe1479103a93e90a +2019.1:e21b8a5b208618834760593bbb15063f7e399642 +2019.1:dd210161e204e882027d22132725d8ffdf285149 \ No newline at end of file diff --git a/SDAccel/tests/test_find_sdaccel_examples.py b/SDAccel/tests/test_find_sdaccel_examples.py index ce443cc9..4d9f1c94 100644 --- a/SDAccel/tests/test_find_sdaccel_examples.py +++ b/SDAccel/tests/test_find_sdaccel_examples.py @@ -63,11 +63,34 @@ def test_find_example_makefiles(self, xilinxVersion): xilinx_sdaccel_example_map = {} for root, dirs, files in os.walk(self.xilinx_sdaccel_examples_dir): + ignore = False + if os.path.exists(root + "/description.json") and os.path.exists(root + "/Makefile"): + with open(root + "/description.json", "r") as description_file: + description = json.load(description_file) + + if "containers" in description: + if len(description["containers"]) > 1: + ignore = True + logger.info("Ignoring {} as >1 containers found in description.json.".format(root)) + + else: + ignore = True + logger.info("Ignoring {} as no containers found in description.json.".format(root)) + continue + + if "nboard" in description: + if "xilinx_aws-vu9p-f1-04261818" in description["nboard"]: + ignore = True + logger.info("Ignoring {} as F1 device found in nboard.".format(root)) + continue + else: + ignore = True + logger.warn("Ignoring: {} as no Makefile/description.json exist".format(root)) + + if not ignore: xilinx_examples_makefiles.append(root) logger.info("Adding: " + root) - else: - logger.info("Ignoring: " + root) assert len(xilinx_examples_makefiles) != 0, "Could not find any Xilinx SDAccel example in %s" % self.xilinx_sdaccel_examples_dir diff --git a/SDAccel/tests/test_run_sdaccel_example.py b/SDAccel/tests/test_run_sdaccel_example.py index 4bf1ecaf..201fb5c1 100644 --- a/SDAccel/tests/test_run_sdaccel_example.py +++ b/SDAccel/tests/test_run_sdaccel_example.py @@ -68,13 +68,14 @@ def setup_class(cls): return + @pytest.mark.flaky(reruns=2, reruns_delay=2) def test_run_sdaccel_example(self, examplePath, rteName, xilinxVersion): os.chdir(self.get_sdaccel_example_fullpath(examplePath)) (rc, stdout_lines, stderr_lines) = self.run_cmd("make exe") assert rc == 0 - em_run_cmd = self.get_sdaccel_example_run_cmd(examplePath) + em_run_cmd = self.get_sdaccel_example_run_cmd(examplePath, xilinxVersion) check_runtime_script = os.path.join(AwsFpgaTestBase.WORKSPACE,'sdaccel_runtime_setup.sh') self.get_sdaccel_aws_xclbin_file(examplePath, rteName, xilinxVersion) diff --git a/developer_resources/DCV.md b/developer_resources/DCV.md new file mode 100644 index 00000000..fe749823 --- /dev/null +++ b/developer_resources/DCV.md @@ -0,0 +1,126 @@ +# GUI FPGA Development Environment with NICE DCV +This guide shows steps to setup a GUI FPGA Development Environment using the FPGA Developer AMI using NICE DCV + +## Overview + +[NICE DCV](https://docs.aws.amazon.com/dcv/latest/adminguide/what-is-dcv.html) can be used create a virtual desktop on your FPGA Developer AMI instance. + +[NICE DCV](https://docs.aws.amazon.com/dcv/latest/adminguide/what-is-dcv.html) is a high-performance remote +display protocol that provides customers with a secure way to deliver remote desktops and application streaming +from any cloud or data center to any device, over varying network conditions. + +With NICE DCV and Amazon EC2, customers can run graphics-intensive applications remotely on EC2 instances +and stream the results to simpler client machines, eliminating the need for expensive dedicated workstations. +Customers across a broad range of HPC workloads use NICE DCV for their remote visualization requirements. +The NICE DCV streaming protocol is also utilized by popular services like Amazon AppStream 2.0 and AWS RoboMaker. + +The [DCV Administrator guide](https://docs.aws.amazon.com/dcv/latest/adminguide/what-is-dcv.html) +and the [User guide](https://docs.aws.amazon.com/dcv/latest/userguide/getting-started.html) +are the official resources on how to configure and use DCV. + +The installation process is summarized below for your convenience. + +**NOTE**: +These steps may change when new versions of the DCV Server and Clients are released. +If you experience issues please refer to the [Official DCV documentation](https://docs.aws.amazon.com/dcv/latest/adminguide/what-is-dcv.html). + +## Installation Process + +1. [Setup your FPGA Developer AMI Instance with an IAM Role](https://docs.aws.amazon.com/dcv/latest/adminguide/setting-up-license.html#setting-up-license-ec2) that grants your instance access to NICE DCV endpoints. + + NICE DCV is available for free to use on EC2. + + The NICE DCV server automatically detects that it is running on an Amazon EC2 instance and periodically connects to an Amazon S3 bucket to determine whether a valid license is available. The IAM role enables this functionality. + + Please follow the steps mentioned in the above guide to attach an IAM role to your instance with the following policy: + ``` + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "s3:GetObject", + "Resource": "arn:aws:s3:::dcv-license.region/*" + } + ] + } + ``` + **NOTE:** Without access to the DCV bucket mentioned in the [NICE DCV licensing setup guide](https://docs.aws.amazon.com/dcv/latest/adminguide/setting-up-license.html#setting-up-license-ec2), your server license is only valid of 15 days. + +1. On your FPGA Developer AMI Instance [update the Instance Security Group](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html#adding-security-group-rule) to allow TCP Port **8443** Ingress + +1. [Install NICE DCV pre-requisites](https://docs.aws.amazon.com/dcv/latest/adminguide/setting-up-installing-linux-prereq.html) + + ``` + sudo yum -y groupinstall "GNOME Desktop" + sudo yum -y install glx-utils + ``` + +1. [Install NICE DCV Server](https://docs.aws.amazon.com/dcv/latest/adminguide/setting-up-installing-linux-server.html) + + ``` + sudo rpm --import https://s3-eu-west-1.amazonaws.com/nice-dcv-publish/NICE-GPG-KEY + wget https://d1uj6qtbmh3dt5.cloudfront.net/2019.0/Servers/nice-dcv-2019.0-7318-el7.tgz + tar xvf nice-dcv-2019.0-7318-el7.tgz + cd nice-dcv-2019.0-7318-el7 + sudo yum -y install nice-dcv-server-2019.0.7318-1.el7.x86_64.rpm + sudo yum -y install nice-xdcv-2019.0.224-1.el7.x86_64.rpm + + sudo systemctl enable dcvserver + sudo systemctl start dcvserver + ``` + +1. Setup Password + + ``` + sudo passwd centos + ``` + +1. Change firewall settings + + Options: + + * Disable firewalld to allow all connections + ``` + sudo systemctl stop firewalld + ``` + + * Open up the firewall only for tcp port 8443 + + ``` + sudo systemctl start firewalld + sudo firewall-cmd --zone=public --add-port=8443/tcp --permanent + sudo firewall-cmd --reload + ``` + +1. Create a virtual session to connect to + + **NOTE: that you will have to create a new session if you restart your instance.** + + ``` + dcv create-session --type virtual --user centos centos + ``` + +1. Connect to the DCV Remote Desktop session + + 1. **Using a web browser** + + * Make sure that you are using a [supported web browser](https://docs.aws.amazon.com/dcv/latest/adminguide/what-is-dcv.html#what-is-dcv-requirements). + + * Use the secure URL, Public IP address, and correct port (8443) to connect. For example: `https://111.222.333.444:8443` + + **NOTE:** When you connect make sure you use the `https` protocol to ensure a secure connection. + + 1. **Using the NICE DCV Client** + + * Download and install the [DCV Client](https://download.nice-dcv.com/) + + * Use the Public IP address, and correct port (8443) to connect + + An example login screen (for the DCV Client you will need to connect first using the IP:Port, for example `111.222.333.444:8443`): + + ![DCV Login](images/dcv_login.png) + +1. Logging in should show you your new GUI Desktop: + + ![DCV Desktop](images/dcv_desktop.png) \ No newline at end of file diff --git a/developer_resources/DCV_with_ParallelCluster.md b/developer_resources/DCV_with_ParallelCluster.md new file mode 100644 index 00000000..e5132719 --- /dev/null +++ b/developer_resources/DCV_with_ParallelCluster.md @@ -0,0 +1,457 @@ + + +# GUI FPGA Development Environment with NICE DCV and ParallelCluster + +Deploy a CloudFormation template to Launch an EC2 instance with the FPGA Developer AMI that has DCV Remote Desktop and ParallelCluster. + +## Table of Contents + + * [Overview](#overview) + * [Requirements](#requirements) + * [Architecture](#architecture) + * [Cost](#cost) + * [Duration](#duration) + * [Step-by-step Guide](#step-by-step-guide) + * [Subscribe to AWS FPGA Developer AMI](#subscribe-to-aws-fpga-developer-ami) + * [Launch with CloudFormation](#launch-with-cloudformation) + * [Connect to the DCV Remote Desktop session](#connect-to-the-dcv-remote-desktop-session) + * [Launch Vivado](#launch-vivado) + * [ParallelCluster Configuration](#pcluster-config) + * [Building a DCP On ParallelCluster Using SGE](#building-a-dcp-on-parallelcluster-using-sge) + * [Building a DCP On ParallelCluster Using Slurm](#building-a-dcp-on-parallelcluster-using-slurm) + * [Building a DCP On ParallelCluster Using Torque](#building-a-dcp-on-parallelcluster-using-torque) + * [FAQ](#faq) + * [References](#references) + + +## Overview + +This tutorial shows how to launch an EC2 instance using the FPGA Developer AMI that has +[NICE DCV](https://docs.aws.amazon.com/dcv/latest/adminguide/what-is-dcv.html) and +[AWS ParallelCluster](https://docs.aws.amazon.com/parallelcluster/latest/ug/what-is-aws-parallelcluster.html) +installed and configured to enable FPGA development in a GUI environment that is high performance +and cost effective. + +[NICE DCV](https://docs.aws.amazon.com/dcv/latest/adminguide/what-is-dcv.html) is a high-performance remote +display protocol that provides customers with a secure way to deliver remote desktops and application streaming +from any cloud or data center to any device, over varying network conditions. + +With NICE DCV and Amazon EC2, customers can run graphics-intensive applications remotely on EC2 instances +and stream the results to simpler client machines, eliminating the need for expensive dedicated workstations. +Customers across a broad range of HPC workloads use NICE DCV for their remote visualization requirements. +The NICE DCV streaming protocol is also utilized by popular services like Amazon AppStream 2.0 and AWS RoboMaker. + +[AWS ParallelCluster](https://docs.aws.amazon.com/parallelcluster/latest/ug/what-is-aws-parallelcluster.html) +provides a scalable compute environment for running compute or resource intensive jobs such as DCP generation or +F1 runtime applications. +ParallelCluster can help manage costs by automatically starting and terminating instances as needed by jobs. + + + +## Requirements +- You will need to subscribe to the [AWS FPGA Developer AMI on the AWS Marketplace](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) +- You will need a VPC that has access to the internet, either using a public subnet or NAT gateway. + - This is required to download all of the packages (for both DCV and OS packages) and to be able to connect to the instances. + - ParallelCluster instances can run in either private or public subnets that have access to the internet. + + +## Architecture + +![Architecture](images/vivado_dcv_diagram.png) + + +## Cost + +There is no additional charge to use NICE DCV or ParallelCluster on Amazon EC2. + +You only pay for the EC2 resources you use to run and store your workloads. + + +## Duration + +The following table shows the estimated time for the different steps in this tutorial. +The time it takes to complete each step will vary based on the instance types the instance types that use. + +| **Step** | **t3-2xlarge Duration** | **c5.4xlarge Duration** | **z1d.xlarge Duration** | **m5.2xlarge Duration** | **r5.xlarge Duration** | +|-------------------------------------------------------------|-------------------------|-------------------------|-------------------------|-------------------------|------------------------| +| [Subscribe to AWS FPGA Developer AMI](#subscribe) | 1 min | 1 min | 1 min | 1 min | 1 min | +| [Launch with CloudFormation](#launch) | 23 min | 18 min | 17 min | 18 min | 20 min | +| [Connect to the DCV Remote Desktop session](#connect) | 1 min | 1 min | 1 min | 1 min | 1 min | +| cl_hello_world DCP on Desktop | 91m40s | 75m44s | 77m9s | 83m42s | 83m20s | + +It will take ~20 minutes for CloudFormation to automatically create your GUI Desktop environment. + + +## Step-by-step Guide + + +### Subscribe to AWS FPGA Developer AMI + +Before you can launch the CloudFormation stack, you will need to subscribe to the AWS FPGA Developer AMI. +There is no charge to subscribe to the AWS FPGA Developer AMI; you will only be charged for the underlying resources. + +* Sign into your AWS account +* Go to the [AWS FPGA Developer AMI on the AWS Marketplace](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) +* Click on **Continue to Subscribe** button on upper right + +![Continue to Subscribe](images/Continue_to_Subscribe.png) + + +### Launch with CloudFormation + +The resources used in this workshop will be launched with AWS CloudFormation. For additional information about CloudFormation please visit +[AWS CloudFormation](https://aws.amazon.com/cloudformation/). + +IMPORTANT: Read through all steps below before *_clicking_* the *Launch on AWS* button. + +1. Click on the *Launch on AWS* button and follow the CloudFormation prompts to begin. + + Currently available in these regions. + + TIP *_Context-click (right-click)_* the *Launch on AWS* button and open the link in a new tab or +window to make it easy to navigate between this guide and the AWS Console. + + | *Region* | *Launch template* | + |----------|-------------------| + | *N. Virginia* (us-east-1) | | + | *Ohio* (us-east-21) | | + | *N. California* (us-west-1) | | + | *Oregon* (us-west-2) | | + | *Ireland* (eu-west-1) | | + | *Sydney* (ap-southeast-2) | | + | *Hong Kong\** (ap-east-1) | | + + \**May require additional request for access* +1. Accept the defaults on the *Prerequisite - Prepare template* page and *_click_* *Next*. +1. You should see the *Stack Details* page: + ![Stack Details](images/stack_details.png) +1. *_Enter_* values for parameters. + + | *Parameter* | *Variable Name* | *Description* + |-------------|-----------------|--------------| + | *VPC ID* | VPCId | VPC ID for where the remote desktop instance should be launched. + | *VPC CIDR Block* | VPCCidrBlock | We use this to create a security group that allows NFS access to and from the remote desktop instance. Pick the CIDR from the VPC ID Parameter above(For eg: `vpc-123abc(10.0.0.0/16)`). + | *FPGA Developer AMI Version* | FpgaDevAmiVersion | Select the FPGA Developer AMI Version you want to launch your instances with. Picks the latest version by default. + | *User name for DCV login* | UserName | User name for DCV remote desktop login, default is *_simuser_* + | *Password for DCV login* | UserPass | Password for DCV remote desktop login. + | *Subnet ID* | Subnet | Select a Subnet ID in the Availability Zone where you want the instance launched. Pick a subnet from the VPC selected above. + | *EC2 Key Name* | EC2KeyName | Name of an existing EC2 KeyPair to enable SSH access to the instance. + | *Remote Desktop Instance Type* | remoteDesktopInstanceType | Select an instance type for your remote desktop. + | *CIDR block for remote access (ports 22 and 8443)* | AccessCidr | Put the IP ranges from where you allow remote access to your remote desktop. This opens up ports 22 and 8443 for the CIDR range. We recommend setting it to the output of [Check My IP](http://checkip.amazonaws.com/). For eg: `12.34.56.78/32` so that only you can access the instance. + | *Project Data Size* | ProjectDataSize | Enter the size in GB for your project_data EBS volume. You can always [increase your volume size later](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/requesting-ebs-volume-modifications.html). Default is 5GB. + | _OPTIONAL_: *Existing Security Group (e.g. sg-abcd1234efgh)* | ExistingSecurityGroup | *OPTIONAL:* Needs to be a SG ID, for example sg-abcd1234efgh. This is an [already existing Security Group ID that is in the same VPC](https://console.aws.amazon.com/vpc/home?#SecurityGroups), this is an addition to the security groups that are automatically created to enable access to the remote desktop, leave as NO_VALUE if you choose not use this. + | _OPTIONAL_: *Static Private IP Address* | StaticPrivateIpAddress | *OPTIONAL:* If you already have a private VPC address range, you can specify the private IP address to use, leave as *NO_VALUE* if you choose not use this + | *Assign a Public IP address* | UsePublicIp | Should a public IP address be given to the instance, this is overridden by `*CreateElasticIP = True*` + | *Create an Elastic IP address* | CreateElasticIP | Should an Elastic IP address be created and assigned, this allows for persistent IP address assignment + | _OPTIONAL_: *S3 bucket for read access* | S3BucketName | *OPTIONAL:* S3 bucket to allow this instance read access (List and Get), leave as *NO_VALUE* if you choose not use this + | _OPTIONAL_: *ParallelCluster Scheduler* | Scheduler | *OPTIONAL:* Select a scheduler to setup with ParallelCluster. Only necessary if you want to deploy a compute cluster. + | _OPTIONAL_: *ParallelCluster Subnet ID* | PclusterSubnet | *OPTIONAL:* Select a Subnet ID in the Availability Zone where you want the cluster instances launched. Pick a subnet from the VPC selected above. + | _OPTIONAL_: *Scheduler instance type* | MasterInstanceType | *OPTIONAL:* Select an instance type you want the scheduler master to run on. This can be a small/free tier instance. + | _OPTIONAL_: *DCP Build instance type* | DcpInstanceType | *OPTIONAL:* Select an instance type for building DCP's. z1d.xlarge, c5.4xlarge, m5.2xlarge, r5.xlarge, t3.2xlarge, t2.2xlarge are recommended. + | _OPTIONAL_: *F1 instance type* | F1InstanceType | *OPTIONAL:* Select a runtime instance type for your Runtime queue. + +1. After you have entered values for the parameters, *_click_* *Next*. + +1. *_Accept_* the default values of the *Configure stack options* and *Advanced options* sections and *_click_* *Next*. + +1. *_Review_* the CloudFormation stack settings. + +1. *_Click_* all checkboxes in the blue *Capabilities* box at the bottom of the page. + ![Capabilities](images/capabilities_checkbox.png) + +1. *_Click_* *Create stack*. + + This will start the deployment process. + AWS CloudFormation will create all of the resources specified in the template and set them up. + +1. Verify stack was created successfully + + In the *Events* tab, you should see `*CREATE_COMPLETE*` for the `AWS::CloudFormation::Stack` event Type. + In the *Stack Info* tab, you should see `*CREATE_COMPLETE*` in the Status field. + It will take ~20 minutes for the stack creation to complete. This is due to the large number of packages that need to be installed. Upon completion you should see the connection information (IP address) in the *Outputs* section of the stack. + + +### Connect to the DCV Remote Desktop session + +You can either use your web browser to connect to the DCV Remote Desktop session or you can use the DCV Client. + +1. **Using a web browser** + i. Make sure that you are using a [supported web browser](https://docs.aws.amazon.com/dcv/latest/adminguide/what-is-dcv.html#what-is-dcv-requirements). + i. Use the secure URL, Public IP address, and correct port (8443) to connect + + When you connect make sure you use the https protocol, to ensure you are using a connecting connection. + + For example: `https://111.222.333.444:8443` + +1. **Use the NICE DCV Client** + + * Download and install the [DCV Client](https://download.nice-dcv.com/) + + * Use the Public IP address, and correct port (8443) to connect + + For example: `111.222.333.444:8443` + + An example login screen (for the DCV Client you will need to connect first using the IP:Port, for example 111.222.333.444:8443): + + ![DCV Login](images/dcv_login.png) + + * After you login with the credentials you specified when creating the stack, you will see the Desktop: + + ![DCV Desktop](images/dcv_desktop.png) + + + +### Launch Vivado + +Now that your remote desktop is setup, you can launch the Vivado Design Suite (included in the AWS FPGA Developer AMI). + + i. Start a terminal session, go to *_Applications -> Favorites -> Terminal_*. + + i. Type `vivado` at the command prompt and hit enter: + + ![Vivado Launch](images/vivado_launch.png) + + Vivado will launch in a GUI session: + + ![Vivado Startup](images/vivado_startup.png) + + + +### ParallelCluster Configuration + +The template creates a ParallelCluster configuration and an AMI for the cluster instances. +If you selected a scheduler, then it will also create two ParallelCluster clusters. +If you didn't select a scheduler in the template you can still manually start a cluster. + +The configuration file for ParallelCluster is found in `~/.parallelcluster/config` and the +configuration parameters are documented [here](https://docs.aws.amazon.com/parallelcluster/latest/ug/configuration.html). +It supports the following schedulers: +* sge +* slurm +* torque + +The template creates a custom ParallelCluster AMI based on the FPGA Developer AMI so that they have +the Xilinx tools installed. +They also mount `~/src/project_data` from your DCV instance so that your project data is accessible +on the ParallelCluster compute nodes. + +If you selected a scheduler then the template will create two ParallelCluster clusters, where +${Scheduler} is the scheduler you selected when you launched the template. + +* The fpgadev-${Scheduler} cluster is for running compute intense jobs such as DCP generation. +* The fpgarun-${Scheduler} cluster is for testing your AFI on F1 instances. + +If you didn't select a scheduler then you can start the clusters manually using the following commands +replacing ${Scheduler} with the scheduler you want to use. + +``` +pcluster create -t fpgadev-${Scheduler} fpgadev-${Scheduler} +pcluster create -t fpgarun-${Scheduler} fpgarun-${Scheduler} +``` + +All the clusters are configured to terminate the compute nodes if they are idle for more than one minute. +When jobs are queued the cluster will automatically launch enough compute nodes to run the jobs. +The configuration file limits the max number of compute nodes in the cluster to two nodes. +You can modify the `max_queue_size` parameter in the configuration file if you need to increase that limit. + +You can check the status of the clusters using the `pcluster list` command. + +``` +$ pcluster list +fpgadev-sge CREATE_IN_PROGRESS 2.4.1 +fpgarun-sge CREATE_IN_PROGRESS 2.4.1 +``` + +If no clusters are listed then it is possible that the custom AMI isn't complete. +You can check the status of the custom AMI generation by looking in the log file +at `~/.parallelcluster/create-ami.log`. + +Wait until the cluster status is *CREATE_COMPLETE*. + +``` +$ pcluster list +fpgadev-sge CREATE_COMPLETE 2.4.1 +fpgarun-sge CREATE_COMPLETE 2.4.1 +``` + +You can get information about the cluster by running the `pcluster status` command. + +``` +$ pcluster status fpgadev-sge +Status: CREATE_COMPLETE +MasterServer: RUNNING +MasterPublicIP: 3.95.42.219 +ClusterUser: centos +MasterPrivateIP: 172.31.15.131 +``` + +**NOTE:** All of the scheduler commands have to be executed on the scheduler's master instance. +You will use ssh to connect to the instance. + +The CloudFormation template created an EC2 KeyPair, saved the private key at `~/pcluster.pem`, and added it to your ssh agent. +ParallelCluster is configured to use this key. +You can connect to the master using the following command. + +``` +pcluster ssh fpgadev-sge +``` + +Any additional arguments are passed to the ssh command. +This allows you to run commands on the master from your desktop. +For example you can check that your project data is mounted +in the cluster. + +``` +$ pcluster ssh fpgadev-sge ls ~/src/project_data +aws-fpga +build_cl_hello_world.sh +``` + +Note that the master in this tutorial is configured as a t3.micro instance so it lacks the +compute resources required for running jobs. +It's role is to manage jobs running in the cluster. + +The following sections show how to run a the cl_hello_world example's DCP generation job +on ParallelCluster using the different schedulers. +The script to do the DCP generation is at `~/src/project_data/build_cl_hello_world.sh`. + + + +### Building a DCP On ParallelCluster Using SGE + +Use the `qsub` command to submit the job on an SGE cluster. + +``` +$ pcluster ssh fpgadev-sge qsub ~/src/project_data/build_cl_hello_world.sh +Unable to run job: warning: ${UserName}'s job is not allowed to run in any queue +Your job 1 ("build_cl_hello_world.sh") has been submitted +Exiting. +``` + +The warning is because a compute node isn't available to run the job. +You can verify that the job was actually submitted using the `qstat` command. + +``` +$ qstat +job-ID prior name user state submit/start at queue slots ja-task-ID +----------------------------------------------------------------------------------------------------------------- + 1 0.55500 build_cl_h ${UserName} qw 09/17/2019 18:06:38 1 +``` + +ParallelCluster will detect that the job is queued and start a new compute node to run it. +You can verify this by going to the EC2 console. + +When the compute node starts, the job will transition to running state. + +``` +$ pcluster ssh fpgadev-sge qstat +job-ID prior name user state submit/start at queue slots ja-task-ID +----------------------------------------------------------------------------------------------------------------- + 1 0.55500 build_cl_h ${UserName} r 09/17/2019 18:38:15 all.q@ip-172-31-12-135.ec2.int 1 +``` + +The output of the job is written to your home directory on the master. + +``` +$ pcluster ssh fpgadev-sge ls +build_cl_hello_world.sh.e1 +build_cl_hello_world.sh.o1 +src +``` + + + +### Building a DCP On ParallelCluster Using Slurm + +The process for using Slurm is similar, except the scheduler commands are different. +Use the `sbatch` command to submit a job. + +``` +$ pcluster ssh fpgadev-slurm sbatch src/project_data/build_cl_hello_world.sh +Submitted batch job 1 +``` + +Use the `squeue` command to check the status. + +``` +$ pcluster ssh fpgadev-slurm squeue + JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON) + 1 compute build_cl cartalla R 0:06 1 ip-172-31-13-182 +``` + + + +### Building a DCP On ParallelCluster Using Torque + +The process for using Torque is the same as sge except the output is different. +Use the `qsub` command to submit a job. + +``` +$ pcluster ssh fpgadev-torque qsub src/project_data/build_cl_hello_world.sh +1.ip-172-31-5-142.ec2.internal +``` + +Use the `qstat` command to check the status. + +``` +$ pcluster ssh fpgadev-torque qstat +Job ID Name User Time Use S Queue +------------------------- ---------------- --------------- -------- - ----- +1.ip-172-31-5-142.ec2.interna ...ello_world.sh cartalla 0 Q batch +``` + + + +## FAQ + +* How do I find out if my template deployment completed? + + * In the *Events* tab, you should see `*CREATE_COMPLETE*` for the `AWS::CloudFormation::Stack` event Type. + * In the *Stack Info* tab, you should see `*CREATE_COMPLETE*` in the Status field. + +* How do I update to a new template? + + You can update your deployed stack by going to the [CloudFormation console](https://console.aws.amazon.com/cloudformation) -> Stacks -> Your Stack and selecting the `Update` button at the top. + + You have three ways of updating: + + 1. Use current template + + This option lets you update parameters in the currently deployed stack. + Click next after selecting this option to see the parameters, change them and go through the deployment steps as before. + + 1. Replace current template + + This option lets you select an updated template. + + If you want to update your stack with a new template that we have released, select this option and point to our template URL: + `https://aws-fpga-hdk-resources.s3.amazonaws.com/developer_resources/cfn_templates/dcv_with_pcluster.yaml` + + This will let you get any fixes and updates that we publish to the template. + + 1. Modify the template in the CloudFormation Designer + + This option lets you graphically edit the template and add parts depending on your need. + Check the [Official CloudFormation Designer documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/working-with-templates-cfn-designer.html) for more details on how to get started! + +* How do I terminate my instance? + + To clean up resources created by a CloudFormation stack, we strongly suggest deleting the stack instead of deleting resources individually. + + CloudFormation will handle the instance termination for you. + + To delete a stack, please follow the [CloudFormation User Guide](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-delete-stack.html) + +* How do I troubleshoot CloudFormation stack deployment issues? + + To start off, please check the [CloudFormation Troubleshooting Guide](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/troubleshooting.html) + + Next, post a question on the [FPGA Development forum](https://forums.aws.amazon.com/forum.jspa?forumID=243&start=0) **OR** file a support ticket from the [Support Center](https://console.aws.amazon.com/support) and someone should be able to help you out! + + + +## References + +- [NICE DCV](https://docs.aws.amazon.com/dcv/latest/adminguide/what-is-dcv.html) +- [Xilinx Vivado Design Suite](https://www.xilinx.com/products/design-tools/vivado.html) +- [AWS ParallelCluster](https://docs.aws.amazon.com/parallelcluster/latest/ug/what-is-aws-parallelcluster.html) diff --git a/developer_resources/README.md b/developer_resources/README.md new file mode 100644 index 00000000..91f1165e --- /dev/null +++ b/developer_resources/README.md @@ -0,0 +1,15 @@ +# Developer Resources + +We provide the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) with Xilinx tools pre-installed and setup for development right away. + +However, setting up an instance for development might require a few extra steps like +* Setting up a GUI Desktop. +* Setting up a Runtime instance. +* Setting up a development environment that includes an elastic compute cluster. + +This document guides developers to setting up their development environment for development, +building/running/debugging designs and managing costs while doing so. + +We have provided the following two ways of setting up your development environment: +* [Guide for creating a GUI Desktop for FPGA Development using NICE DCV and the FPGA Developer AMI](DCV.md) +* [Automated Deployment of a GUI Desktop and HPC cluster for FPGA Development based on NICE DCV and AWS ParallelCluster](DCV_with_ParallelCluster.md) \ No newline at end of file diff --git a/developer_resources/images/Continue_to_Subscribe.png b/developer_resources/images/Continue_to_Subscribe.png new file mode 100644 index 0000000000000000000000000000000000000000..dd13b1480cc0393b9631e030b8f814eb5c4ec215 GIT binary patch literal 58123 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 literal 0 HcmV?d00001 diff --git a/developer_resources/images/Launch_on_AWS.png b/developer_resources/images/Launch_on_AWS.png new file mode 100644 index 0000000000000000000000000000000000000000..89fc87e094dcd310593c6072f6869096fffd5ae2 GIT binary patch literal 12864 zcmX9_1yqyo_oo>>MkzfQ-5rX+0NE&|q*D-(E~zg)T40PWsfmDqbV-MlG)PKGDKG>S zr2pgh-#LqO-uJ!tKKI_|#&bW5d#hpFn};NZcqzdrzou%EwDOQx`2 zBpxsmZyX$9&igm6|9izZI5_M$a8+dk|GdL|Dx~3d@Oda)DGpO-?STyCP{to!#)&5_ z0ar?9q58Z3iLk&1xn31#m-ps&<}~G4x~WV*%_XXl=+O!`;pu5&6zZ33s5LB`!lfph z&Wr-knP;ZkaDEP>zia3`RS0^wz2g0DH*fd4_55AX(Yb`T!|{suMCj3J$J$!Kt_s_K zzr&I21Gb)}v2TGX(&yTL8Ae|bJW&FG5nHJt)Qj7!4{y)PyP}{rWJlSoq-b0*f@6u9 z(_$PB1aO*{nLb5@qi%ps$BZ-zYE`m!6HN=NW;Z<`Ee;5$!;(OL*{Ko8`n|Le8&M7> z(5p3O-XP^@rzd>DjsQYo4?cs_%xfD2>^j*QXG4^qZJm6Jp3Bnu zH|vx=3O5j>2gfg^%BpDqSPm6105$;obuJJJDCZ$UOsj84oT|%4{A|y7^>A@IZHs(E zu&R1c)Z799nHPHP_q{kSoQ|B?Z(x#X@RHeKZ+7{^UjYyl0QRM1=9bk4YL}=drcISR z?U&mKnKv{w5vkVGCPUlS`cu0_Gif-JR2CL}{9x3U#O#frCZxuSZTqS>>y)Jj(Ip1; zHnS))m=Pj)t;ZgKm=X$?kz)R@O1&-VkA~4i?RqX&FMznM_6+Xq$DUfuwFWcL@=^jl zW*fwBlihG(b=q?DYpfgyG%>hkm_`IS%#c*O_(GfXeGU-jmNZ3rZcqLmJbc;s?q%JP z(!BNDLo9RX2>waNI)9_iJL@0(%Dj#98cBK>LaZ@d{3NziqI7qAga^fn%~Y{u4Om;? zKu!AL@6P7xeDj9xt#mLq*(%P;87ah6lENp^w@>f=f&j7hszE0nq;XT7+aUH^M`!50 z5 zW^n)=J-VdBx+Cv%)0pm!X4FFWdda+`q$Bv`dc5Pn;(vENfbF<-_(y0J$nza^dv9|a zTClg$y=EybR|e_?xjFCzJ)p*FMT#8M*KPW3d8*ysB)HVu^aU@iJf5ZiY>q(B_~MBLCzcMnvj@@Y>RlSc<*8`S zOS^=xDWGbIy`0YImDuF6tTG>qHIfq!vYQ2!+hC@;RFRTt;CV0mBQ5=?gT?a-{i1t4 zA-~`X;Z|p#!u5w-n{(SOrrOc*BoLX0K?&7}0YFc7Chy)9OWE% zd|J#ldL|HCZ;a% zRt*sTW%xS^A@Z$Dl43IS01kH^>uIZuWOj&uYbeO zw#yyfX-kFKu74?XwY^H%c7>Pp7bj`NMtWh`mOC~Q$n1NrTgx$Wn7?N%pYwvkuPlxb z2F>>JerDWw!-;pU$Il)oJW*E+y^QL<#A>deg;|lS!0F0hvHHufzWeZH!DDU~Ce{Rn zEEQ%Kf5*gz5U2={_Sxf$39s|!TaKE?6irvrvi~mQgT(#5vXh6lTs|tg8f@$c9w_)i zA6G9@z&F~}sa2gvhoR-d9sKjJbZq>l+JQk#6+%ZA)jQHXP4J)H_K45&u|Z|}kkuT) zN!Q(OC|&_p=}!sq?_8}+`1fCg8a=sNyf`^d5Ek4|m%Xa2&%?bSBU9wezp_ffJc!)+ z@adhXS{r z``@ZuU0q|QSxxETOR$l5dlq33el50M%0&dwE1GcrYkE~KTlyn+cadRm1p#2g<=?WD z*O7&v@exJDNQS*tCtrPi7&5lLWB=2Y!r<{RsSDZiS5Pc$<;trqD&%+GK_-(GC5F3W~Be$8+V+Nx@Pb~S?U7zoEjr{(ly(078yi!Y?#E~V*376DRYL?sW(gaRw67rbq_i~ z4;!#O=CF`}ZLx^)VY4PG5=lWo61Y@IQm9P`BGTCU+7Np2WfJAX^1vDl=sk=4hI7}p zZS8MQo&$@Q|*~^WAZk zG(x;Y+7~do?6>81Z6d~92r0fLkZLRYusaMB$%;CS^J&-l(#I_|Ra2>!keEMPKCHBu z--s;{{2g!4jNcE!ID-lxXEBbcUR(q{4bMH>_ukOBhviJI*OvO|}{Y4H|=(6W&zl?TWs#U~)8r=zba@-h& zA7!a4-4Kk?e5xB)7h+JYhI{U@+MCPyjl)yUc@Jn&Mq#ecOWU;ICagoZOlmR5cpuVL zBbAxPNiDZ21FWw;VuILfRuGA&pq(s#cxp@<`Yy$d30`{`iukFmwaGg!=5q}(Pea+U z&o%`WG!;KVa?nPnD|yk>% z^MTh)E>mj#J`1w2@KxM=;?E1G*zDz{^G%|4`ORE34b3*}LV3>6APCQJnpF)%JbEV4 zRGmjbwj=XqtyrT*-F>IB#xn&V_skl6CQZ2>=7zAg#Z*`3<_@Ce;IHqkb>_8!JB!Og%|(;uVD-g>4F*XL?c z7u@GTAeV4Y8|~v00JVFzz9UPUT2Ur5%{ zhhJS{94!Qb$->RiqTvQ7$~#!;0iLDRu>em#m;CH9VCsmX-a>4HtT5`Zt!Wcj`D~H^ z#Bm&>XuR#C+;v|4=t1Bpwl>L%=qKi`lQPW=f3hMDv{Z3)E%sYJ|&?I-Od?NA@$A&*3~JBXYJt9-`DL<)T-!Pe|J zn1OsNtDV@A25)5CGDK|5+_9;wdP#RYVMHa~%d$AhgkdSdQLk8;IBD$Fnn}j_RZnN; zO5lf7ME<}HA#hSdwNFidT#s{Xp@3*h&+2vs~H3+BC^K$rs7K1 zoBGa$GIUZEiTNpk!X^n2LIPe(|0IvMEQ%LSm2#(yDUmTj*Ld(v09xsVjOG=*#B;fh z>*PwtoFU+w--=1%*XUp?<*D*1#Et%t(yr4h&d5fXOx<`H(iI^m<&EYr8 zOj3$BmUhxn% zM+?b|Uex0mwcFRyT}u4rmNSxu74i&8Y|g#_=60B#OP}+EdyrVoTObQi-3HoCpwT9# z)Tbs!LdcW+>VQzZy>;=S$6)g3Zj%>rucc$(9l;v}UX2iH zdb3ck^LX7#k)4-%-w71qktk$*t0oi7kfX;?_h-VhUL}GwH{&f4cAu>N1ZBr^A;61{ zb!p*y#venEZ9gep)*K~*CJp%97t$;fm~1&AB;>Uzg35*|LI6IYn_phL^C9#BBJ#Ts zXBYlR{1mR z)i@lKju(%uLkB@6Ljp*Rcl7@Oy)(DsGB(D(bzusYJ0-AsW~zRtF#1}dEe%47(C%HK zP~;{2)Og}zX4ESZ?V@quy28Xn{XTc*EB75Q{QRIYTr)H&Z&SDMUHG@U}Ok7*FEJ|T8q&5Hmfe785&8TQw} z_rWFm_LsIhYL%9Lyfl;L>00pZ!BGINMPmt;vMx(Qvl?Q&z5fuKG|*cLR_Y{NTVac~ zkB-bstVJV;*fOZD7kI_Q} zhkz;lIyXet$!9~|)E`SO5>)Hi$|PN`LshJdX|KknR>Kk`|9Oxfi{LmGrZr!44j+FC z+NxA)r(j!U26{e#9qVZmGVw`9I&XAHulL8Lj^A7i=$nZ%JbWDrl(Q@NOh2OunHZAu~Buk>2CkpuQR^vG{XA<4SE2$83gG;$#&LEXGwGYafLHd+PnJABE z1`DK=U-lK34*<<&zba*0jdcTH8hPdYeoPyt0(4eDc$t5LE0pmYLj|?mYN+1RWX27J z(;gqrDy5MhUvE4?4Fc4*eYMt|)lp2X4Ek2wlAEa%1X6C^r z>cD7eb8b`g;Yz;x!h6{=tt<3;xI55OP4=wom)YG1j$K9ub1Glg-rF_Z!H`UWJx`0@ z;tHAEC)arfk!3(VuGn7^XUuG;gE=WuI*&w#c?zYkN*<{ky04uQ+`;*htt_0>Z?e$FYCkclK*XIRHJZg=; z61|M{OJ|AVa>UYu>n!V{h03$pL<%Ct4D;+HEtr3gG5D(1c~^x*mWnOS(#yKS>=>pq zD~z``UiI*d;@u;ME}P9Es&4}h(oaq}_g_C5KK7p8GZ5#S=Z3uZvM%E!K$o z^ZI?Dkg%s3*Fzji6wwFNVc&C&+jF1zilr^EGE*ca5oKy2JRUx2KUFjN!Z-&SN+Wos zqinpsw9Yu7EXVBGU5~W0vhfJ<8gBhUc#hkPU(6BbZ?wMH_r@hzCV2v0 zf}dFm`rbh2d4eqV3PT~nicxLp&i3h{wA6K@oMRamukyUmv?~2y17PdyiNCv22N$nC z<`*XRh#nTcgvuCe5=o5wFm_FnImlVmI@}~L-S2b{PQLDcC@2QA4NLqHzc<KoaJwCHKg}9{dgnPgyNNPC-kl+W`=wxzYQR-UA%=-Fdd{uC>Q5-S!%<}oE*}g z3Doq9t2#W2&FSuTIt`%9_==bB?7);%+28tQz%%JvuwtXf>~VLnfRv`@@Qk-!g5CFS zs!d)DEnStEDJZLkL|e_5K1K9qjR%XOQU&hI&mcI~QyP;fKhYU?f)D)Dc0Ft@3L zUOo@3`pi=!NCEFpsW7kapAX0di#M8z<4Kz?SjCyZD%WJwBs!fouP$dSJwH$?;YSPDHLQpL zR%adhNH;!^uO!HM3>kdIyy=G|KW?e8WfBK?>!WZq*IqF9v_jug@T2>+2}0IyZLJl) z@A}w@mHf95^Usn5nmNdWQY}W5s0nE2-<&d;DIu38y^D_0YSS z0y+CXo=E{4jq{ElZ_!^qS+w?8yYFvVBO|+EjH^9LB%Xh=o9yBifx=Fj-JS>1sq@h( zukMCaG*bQ22eukkNg`@H24!3`ctV<51#KSrPPkq%&Dov=a807=8e{#W?;h(X61X1d z8~sG%;}3SM-F`&*xtyA4MF>-oEO~}j5m)z}jW6#a> zPD}tXNU!^AswM@kx#qRju<xY&BlLPV#dmNCA;DrHO zF|V6(gQ#zEo^0`R;#a%R+T91iPE>-;1Erk)w3a-Sz1!o<%lQnZ#AOfv*2B`Gfht3j zXQnEZp3O&73$-^T3$xw< zhEhTL;tdDR7+z=Pf{3qCjnusV^yY&XHHj>`v?EgvcLmZ5g}{-Pd9GPRFiDVB5V`aM z>2%EvT4BCrVT&kEfPd0uih#LaGTlAEU*|+CPk4}YTb|uKO8M?DMkY@~#)0U%_NA@% z!*JKPY>&Q}D)q!gB&5?y1-O8EGNjds#phpYxJX5>TN+W%FC~? zC!Y`B+>1DZ6;W;;vJj09X}G06^vvg!o(-l{&Fgl{TpB326b}@m9{#U^gaL=_sv{nQAZ!RSHT!%*`PQL|~gb-{{C)XwucXS`FC*-_0Af+6 zCsp1M<2vfSw!M>fU(c&1roS+Y{-X(9g#x7pCmYub7%kPjQ;(Ddq z-|vgPNSLoSWuHA8Q@k3jI|@E*qcqv1Rwq4Btat`oo#0@O3|2h0YmZJaA)#GPTHRh~ zZmFW=_bliO3j*xM)}MVSaU;;9Ct3PeH(~p{`c14*g4LGEmgxIdKNGE4XU)b5DUv2( z`voz9>DWBe_BV3`9NTRo-(P=M5~l`+SEu-L`_$SYfkf<74^3FXR^0DO-2E>8W>iTV;BR=Cg^axC{SJt@P zL=WQaf55$p*oy~6`m^oZXY=6iqF?qs<1`aozo|U0>Xrt>z-b`x4kf&rjq5Ln1U1B*5oVk9sR}tjoke1}>;HxrN@*2)-cZ3ILI*VHQ z-r!})(rgR7r1RN-Tyde5TwjPTfRv9{d&*MZ5^X!~0oT6s~62_l<;vM$i+cu%MI6VO4)nWGBDVu-zG7eiWCW476}p= zpCx`La#T~3&agG;Pizn1jxDJ?fx7&r`cF1=8Ll~i)Gr=V*{nM3=nnC~$fpoc6X-#q?X7P6$9nJFpY`lA|oOp7hl%}x0=RN?EctO>4pVw+B5MV+iFZ^kO%U@iHc}sUHk|$ zeuazn2cMpmM#TOlbE*8nc5sT#IZA#mOv;u0$ebPg36gg#%e!1Ifkj%Qx=PI1 zNuM)5v49Z^z`e*>pK*0>&y7u4arklQ@vCDs7tXrg5DFuXd5#2vLoKKecwQOmWrd1R z{w~mRf^`Cbx8HPx^CvPh%6EQ=R#?O6vY#(KD|)_w7e2dd@h+2JdijYgd@A@SR1!@M ze^8?}{x-8F_%VZcp(^f%_o(YytnugpEBvWNV!fjwI|kCwc9lkSMDQsIkbH2Qv7r6QwM{Lg1cNKT6Pc3Q`cip$eR-#WHp%K`Q})use@ln zxp@-m72L6;=2Xx&wURiA#sLB3OhqN#>xsAn(ks-`*1VXOAbV?*2eJ&YoXg?;J{a4F z@+4$a@GlfkJas(B#|X|E{fFoA=3;aWPRvuoew-EiA_C`G9pOZSRgEI=eY5qt9du+Vpw&m?5PM(!8`G`Z?k-SJ0ig^9ME z#`lR=n-n}V5C%3mONRUOl%?FNMFtM>BA*s0qVVE?P^fXU$I&|bo13(f=~{=p%I{*j zI_;_Z0o`yNWw)sgBet|}y6%SCIJ$*zpXY{H z5sp1J^OMuA{jUDFEnX6f$adYv6x=)!p{sqh_|}c*tD%tRZ0rLcopPlU5!%5wwyYp9 z0^xZ+qn}s7E&_{)QVKlT$;^9B0@h_W2%4B9#!hfdBy0}Ky6JU0N^cKu6q(2v%I_Y? z`v6XnSoIL3!9^BjEm%$32dST00t2sBuWyo!p$nVG!6jo%9R0-nqc|hS)OAt7wdEkp zx<)?6iv=(jm#dE$k!jNll)O;?+;O+T0OQhn5cGubUY4-%*Q?2&(kK$%I1_V_a)Ain z6*aM0@r^lj9bG>X;-6v+J^tEL)aHI0a(MdF-ks>GnhuM>DIHZ@+Pg{a0p{k$_$*xQ zAjEcMz7Aj~^62%<>uGI?Ei0>=EKf2GUa)#xk<2DB9nvJ0lVt(3#KPdT$~UkDo8uG> zliVXjX~rcWZgI4gqtpOkRf(3B&WljFbQha{QJ~aTIF~=aYP-M)*W}627TMsx9g30S`b3`syw-ZZQIfEoTho35G|4et89Hp~DLO%gnkSL3QXQ#&4{d(`s?SkWs7DdONQw3W_r-egiaEKK6pDphT11u+v$0kJljA2iC=u4Ggm ze%z+EM#eW!74+nlx|aXvDrIJLIm0u6AWceAHz+a^{lc>P7QX}U`N`Uxx8S`fNJoPq zifSO#$@92PqYM^NKkG=7APu??6o1EEZq=)Js)BF&7sKu2oxqfOehPp)?cC#| zy3p&)-R;@sHyRm0XzWAs=smaVYVC3P0{Eq1A>QHH*v#7`4yaES zV4fgv?5Y2&>bnEOHq2rwX;g1f_XwC0)gr7HrWDCS8Z8BZzGSE~9mPqWy5FSTY4@9E;k95U+Prl?|@PA*c>cCtMV?D(%~eO_^-UTooe(BB>{ z2dfx~sL4dqwQeybxXjA?Lv>SVJ~4_pZEnI-#lh&Q0dipAim3SOyY~@p+Iu?yK z8&^_gvk4Om?9kIhw6P-1PtcFvcn>>5xZ#_3ULVf9O zmK^C{LfHyU6T^J`gB>b+1|&{qOAc8U@P-0M0xZI7I)8hl8^l%wmVOARx8Wo_s*C*e zck-U5xZZe;*#ms8HT+^Hky}PkDAU6habPxn@t(mBWlB=xBW`&b@E~1H>2JoBk^sfd zIt-!MN{REXdvC#;;Lnm zOn8#|>C6+?=`9sLO4WS*q5xtdh7*}X0BAP-C-^BEY0>~^J5*^Y!Z4hj9yiQ8Juj_t@51J^ojFS)Q)N=y5datWyxFqqfYKg><1mA$3LHQkiBIK zS@Qf(Ys*45XGrfs+#``(9cFNHIrYg1GOLPOJ=bL*rQZ|TKWP!P)+4-FyPMwKb`KGx zLQHr6q0Jj=qE{Ziy%dkl@FlymVt237g*r#~yYTL2+a!W-2(}CfJW?#rs>OXz2;}@* zVn~*;YbDG(xyDfIaENHMX^-O$Q+a%SUQr-I-2?_E%Z}pjZ8~f}VadiK|oM(SZ zzc13RTa8r9E~x!3EwyIsITIFk$guUT&`iRVU`wd0bV`|w5YaN3SDQy?*K+R9$DWko zlD7)fk7sX?4t`yDME&ZZi?_y$0FD8U{Gbn_X;N>Jlp`Mae>&vt55kW1He>+YZ5ngR zt!gc7=_5Bi3PzGBS*W8nXOdEobsS+W3*@0k%5#qMx1kpz1;LB(C2p+qv88?V>6?{# zEgjeTP05XVrz=vn!lw&t*g-T%T7NAQAq$;bV%V`N&qcn`E_!ZE{V$9#jsW!l>WT%d zc0N89nUI*prVTl+(d;caA1oro_KxsmHZ-KNB2m)N>ci7t5v$S;ZCVc`M!NphaVF}(>20nIWKj`wX&l^oBoHwz z6+F>wA?`*ltf_(u_y6R1-q`2ochZNk_g;JBAJXoDw&O~@qvZnBbE1*oX5tVjrtHIE zuq9rOgzM3}pFbHE*suZb7Y6$)iU9tUahe-Y>d?7rSHn7UG` z{8x+)P`AXZ69DrTspNe^lhIMKUchMKSkB9Zpb;~Q_d9ZZ1fTvT{8wr^@-jkVHu%J4 zaR*Su9dNU?NTGXZC}J+;L# z8hFHx)~J=z9ulu-?N=$$6_^V3>YO?LR1xNqNA>nm&?3$nNpLm^gap1+3d2H`iln-?eqC}-> z#B=`M=tiZroP86&djS+s)tNTwaq<2i#F7)d>Dc@zC1l4=7`gQp7P!!r$AMK90PGnH zRL|zJzv4?!LgA*&>ZJS+Fo`zMWQNOmA+Ko@)LP)p|1w{$N;l!$BcWs2vUoF}b)jEx z!uY{R2o$1Fe>i{NlB`Q$uL7JNLvxfg-uI^%Xt2lGoP`p8;KIrV1?;@&`+B|muEcfj zxtJ#;ofZa~#=}u!?`YYjYr?&!%LqiwRA+_6xw%Qzkkr31z;;;g2~l~}@Q*hv%>#$& z4fe~da(~|hj~}btBRbi^!wY)VPtQWZBWDOi3a(sZc(^?E3F zI6oKup01Gpe=Z65PS6}*{mwEVWY;o!<(`T>`tK%*_{(1qeOT2RMY$_^yFR#r8%bMA zD&zSbz5C|PJRyr{ZUu&>|1s-#UclZAz%vb_n)%hV$#_ zR;>R(VH6T2zNiK)hS@8zn~~bYWZ2GyrWJT^FJVwhVkweo1w9^VQTO?D?*C~Ii`;{> zKRPt#jGS{(fu$5%sbTT9wJjitbSz3aVE=F?31$nDxi_-AV6T&2A}EB(iwC)-m2MU@ ztc|B0bj4iMFT8Tkx-(1^TS@R$`dFRpF$N63SJJ~aPIR$qIbNv<=)J**DKdItE5ipy zTVqluDCcm9!xC<#v|$_Hq+Q*q5`&8SJ(Vcsq^Yeqh6O;$_iE84kUx*ZmL)siN(~cY zy1hG>)j<5br%wS}!eZ|oA>dBW7v1^qLxC==M18=fS-y%B3$reN7>?$pPjGcx5HjG6 zTV^fX9}@eJ3}Vu`ho=8jKHtZdfJm~zJhm6rpOoHB{lfNn;=gsq%jLq+v7Bk^{2kxC zwXi^Q`Bn{DO)QsK1)y3gPm(8d2~sauB<8#A$GL!U3DS~Rgs5IR4cLw)t^W*89v9$! z$zalG?#+ik0{38Hig?n3#3!MMDt&ZW>+_tr90nL^^ArT37i2t_%hsal{^v|C;^$bW zeq}UvDbpU^V8+Gi13)nrF6!zPf9>M+y?BMkYFSSPZ#dzR@9?H@{%Gm2gkBsE4Zts((pUW@0RFlGxy0J&_8pnJZpE_E)>Q}>PlVM zuV+_{5_04#9DOPO_bgOyGydMUB(X?$TtD8Yv4Zh^m|Yp+`rD+mEyy4u)y5Ie zUwhw~#%$bsEYYiv0`X0=pLtKFMe&A{myOEDPK&LvQ3FauKmn?Rl@9$yx#a*U5KY+{QD(zj%*%`9@Q9+ZG=bnALU0T2mY~5Mf(3VXX&e$P3GVJ5G{N27-Myi4hn~(pv-dye zJDF!LznkHrpPwzSs#R6*yZEf6AccuWj0OV(gDE5ZP6Y-A{trvpa?8T$!R6(83Gd_1^vXcf4f8$jEth=n0<6C%m zYUHo!X)0-H=q7tG3;Y9!?`cG@F(`E#n)6_~g<(x1Uc!>0n5@B8Pf>vYlx{dlBi(Qs zxH#JwCUP(fa5C8SNa5*NM!Np<14N(cMeC9KS;9%${inL#cPzK7%zg83l0o{(m(M03 zn%xtdLO_h+gp57J=E2s;M#q-KLCB`{cKI(#&iSj4pWD*{W6_Adnhjc=(6cNTF@G z5D27Y9|CEM2)Ksd0*PY5ymq%-kF>@CK-VF|QccT6Oa24DvAr#ek%|2$Qx*?f2k1J% zzzBNqLoaPjU5qF_Y;EkE`8|YQ{p$;U==JZ%tgk5l^@)qM&?_x@B}xf%eQdRYF` zlAZJa9u{fPD zRzi5yresge`hR%O2K(ZchWfu1`S*l+?tSgclTh-rkdb)SjX>?%M`{k2-EbMXWzcO2*$CI=a zTc|Mcon~l%G`*?gWJ#|*#&k$?Ji9CGn0!d+k6HX@m>UX|R$Aiz{%hrZnYB(mRuYDx zz@JXLSs6mVRPHYiIyZfbR#ux`V`t0PM9(&Rt`7UwsUYL+VnEg6?>)teU~(G@yYd3% z+=5!)J_W0_R%Z3592}8WuPfqoKIhQMJkR*eUSHDL^Bulmjd`P=@dM| zX*KPCYR^6HP{lEBlf-pl&?M!g_}|6!zsA$9N`=i3031#_E9=apRkX8O1xd|mgYXzN zCc0%*E#@j#Tpqh+G@My;Ibp4)%OsOIT6$T3y07^i&XltHUN027oNdyiaN8o4ju~5u zju5LC+boP>5VqbHGK+ZJe(jCUl#Zo+vcA>K^}=J&tca}dJUXZSkoJK__GRG@Q(>+X zUB#^HHrFF=tFqu{!in6eZD8RMzUZ>V#xN=z(KFYaDM z45i_F@jrAGItl9`qD2VLWCHHh4e<eB##OR4is!47nX%I`($>no_cJ*DK@aXK12{eN1E)q3 zx5PJT7-rW-es(K?3CwpfYn7(sAjo|6*4;wYM(!=I5lA{PQwzV!y6??>qcl}3tH}S? zT>eWAeQ2Ok2l;JKH z&yQzNsnZgAveMMIH|`%^k$@fkSBb#Jfy-7oP`t3R3jA{4BS+8@8e%^=md2MlYd`-E z78W*++m@K$4HT^DUWF~=JIYe3QrEW#nL501U#Kys0p7Xqg0u&}QKu@Np_Jy=Fq|y< z=+fTy0vmyl4qv~I+RWdQ_+9z04tV_EC_E>YXqJl4JHuq&;Qn>HpnQ!WPIGGB|1|^g zS+!8X8?#iRkA?G%v?&?G!_l1mHj#HFRuGe6D9J9=2K!t#06~_#kY%jZdQFbSVz)?lb_X6VZ^Dkykqn^m2K(fA(g9fG((WUpRwqFHNJNLYF@eK z#CZnm%D7KKDfK`-um9VzCK9QLUnlmpX1Ugff!MZAN6V#pA^YV$eD)^{fu*jz56OX# z$C+5v%`x;UdFzxaB_sD$5pAgfl3nWoPbjIVpH?832Q~W?b@h-K7P6JJ0gk^m-+?kO zci2%T=&4*TYpTH!rUL=%{hBCWYRIg*RPx0El-#m;UhJ|5`+hWNbA%709X72iZP9Ov z4ij)c*&RDDG9%3_x@Z6@zH4`qu*TD}BS~a8?%8zqksTj-EgSc>iUT562k6+9*Ih0n z9#bil%@>Bf6*Ac3@cZ-^<130194uO7c8mMwgQ)G&<2z>EC-JTs(8VxO4ZU|X=(1$7 z4g$KnsI^-`x-VZDQ~P1!NKV*Zczb_&7xDeIytwo3aG~oF&wTHTYuUKR$Q7}9asj(n zOAi$%JfJaM*&VV@p!5@?dI^FNOy^;y-s>F6sKLy$Acxg5PsYx5NnyN-^t-I}hvwZ@ z?-&u(%;P4vr(a%RZa0nMgP16kOoTGEe59GXYwN+U!ejtLklM*=e{3o-SDB)LTDeT| zOs}uDJ}|xABYHB&pI*11wmj2G^>15(KW=~$>fG{(?6+^}3Eeea1vZ;IdFQJp~Dq+)6Nz@?(R7 zZR_<+TmLt~FX(t`q^$bC-oYb3*&b2YNn$Os89WbJ@0RM1M1#T}jf3ME&9PSd zv3X9P(eatgxcojEJ8VS^;_V;la5>UT{&kFF2(Rd`?nN_g1+=Rz z=ArMg^4^=*#aR1bu6G25z2qn`pAr=ixL-Y9a-S{;1Za!S-K0gI5~Px?{&J0&EY^OW z7aM{bz8*^#P)wXDL@@vg)tsSgqlPDhvMIK3AiJw^LM4N__gO$!upu zc(;CoE_wFuZ#@(3enklf?3M+5j{2*M-G+@Fu*OQ*gZqE#H_GD+Mxoc-f8E9&#YGYP z+6-SR{?&TCV}g5i`u_&~-vXEa>q@`Fv~)28w<#Rsljc7W*o90N&;M0NC=oiP*MS3@ zN`*KF#q-u@AAQlP+t)nq#Zt6sDNH?SqD%YEmHs9W{@AA?0qN#&MTSB-v%ZADh3-;lv0C@E|-J0m9W8D>op-YHJ!BT&(*3RS^<-S^07x=zz`K9+>d$H* z&`=W$EZEHbn;Ha|D~KXIn`a>4{9S*aX({2_Ajw~1{;CH5Z_s~E^ncCo|8=Evgf9r^ z-x>BLlW=<9AnG{Yq8;=42H9?Zz>7gM`|vK)L{5@VwYSERrr{3}p!{RyxFYFMBtj`H2Cd>fvT<3% zmFCwGm3=W}g`Up4%_XzZe{_tfHggpc{)O}BJcay|EwR)JKf-sH1WTddRe zuowkC!}g&tCqT1OM?RI?CW}>V`FqQECQkiulJ{BeV;QyXW8@_&<;1?H6H@gbYSXP| ztd#-)B2{%4Wp=BL*@Fw=FD`WohD$JB0yQR1bsJmb_E5Kar$$m?)hT=tP zn~$aC@0UmzH24W|;Pc&lYp*ZYEj9oP$Gw)pIh<%}$Sw7;ZyCA1K3I9k4rafs`+w8C_-y26qIZ1i|U5 z-(!*ReLp@~YKXC0X_n!0-pMIa7Mj_gqLV06#D8vR_rDx<9s5q}3m+tpc{H~the2o5 zj*Ubr8AU2~w%MBtG#_2}ez*Y_PIO6~dafW{(Yqc_yWE`U-K$}`b#mISieoyx%>TUA zI}wP8Zn5)Y$43O5dbgj-?^UKg2y-+Bn9yF|8d>0W@R2NRRgR-!0P!zuotir znXK>ZV(#a#eM&V-a=>AB%5b{&)0b9@KVLez6BM6@{*U2XFMbh@4JR@Sa@Y4rGFW5+ ziTJ#f{tVRbzNvJ5PKv?4H`tz|j;=gpaSyPDZjVZL^vgTj(T?DL-WM)!|=BoyRFIYeiomk>0F(WAx#{v!X*4H4x zDSKBi4&od3{lq5=|uIl@wQ?3lA9E?kb>% z5`KnWix*c?rUJpD2u5$q)u@1rEc^aMISB-ys-s62`^-81o!Tx#Nw~5jS*{yn%!p@fqh)Mh|mo{<_c)Yt;ZyV*U zt%j_b8bvZY)lg?O(d2ode9YRGbG%f4Amwtr=xX)gOv3Q7ic-XWvWVUN853QM*4b>N zpiRx3Xm>c7<5HpvY(k=YBU_SVR(x(Uq>vwxm?Z|hDnteZf_2;R_57mA_+&8; zXLoohS!{Lca!NG?$qbjnAYSc8&&!@ZPg032psixn!dqgu3jG#ILYReWV*xT@5Rr%F zb63nG=~Q#~_suz?(EsR#1yRJpaLu=w$e6*dy6)^6fExBYUr&BR8i_74ko_2)sZC2u}t6(0sw_@UK=uCHx_=F_Psx+QE;RsFGx}l4pwLY*= zWm-@bNKfS05FC6m&l(A66qj#)pa41uQWpK}fqk~952rXUSHNWpowyU<+e5s7Y&r0| z@Ar=>mikoNE@=cxqGFsQZn8^`*eE7*ex5pL^SroA*8NqDI2D6CRcAdrt~pc6kvV)Y zsd_h=Ik6d%AtszIxgOdaD2NpebOYPP;jxK5w{tXeLbaE5^R-e)irBe-o-&-XF0 z53e-cSoEBmG91sA{@D7t=XiGOK31_(>pjP^SYdWc1**50oTdZ2wpEPyD7lrJ_Ur0I zk#T)lBXbldnli0ZeYj5R`>H7M343+>40j$CiBOSLBzy1@t9A6@S~pa)$^B&ef;p9& zwY(Fe6_kHFVNcT9HuH|L*)qhtsehTb%4mvX_u_$YacX=@GcCM(BuZt@cig zuiZaU{}sCg>f<;|6$eM5;$8rXV3W_?58~j{;m6ctovt1jxWUSwECEkE=R5hW@b@(d z5(jTh=h1`9qjb}Aj+0_q>k-X(oLK&l`a&5>@!``-UZ>lN=Ab54>S| zWqV;u8gUc%yu)+YjkVgXF7!Q-L_q>gjdNKFWGBnU^(aVWlNdyAmAWW^>();-UNf@B zZw?DoAR(eC@fxJo^i)zLE}%2u@jaJScCecPMsW69*{{KEY)Q6hY;L5-YU%qxby^{} zviZxk`@33(Jz0IYD(T|wS07PWwJw_EP~jR!ztf=8sHFhBXKbi~d(h$;s)6(NFmfcr zXSGfi*IO~QT+&MZZKr^OOY_XLiN}j|XbucZKxrpLCW(^Dx$L4&>X=X*jrVcB>V>ab zBOBr}$~r9Kd=E#kegm8xL%@Wv@Va(^ z8ofkTP*<*0v+Mf;p;w#+>{>xaI)ea1&>75ssYc&uSnT)3Q%noM-;YO ztopWg{3}H)gwOq&DGZlGgQ>OG*I~-@AtgnuhwHhnSZjepbUV(@aSLhglcVvMfDm;n zCDaWgd?InfCT@|^OIDM-Z&;cX4>!kBMAMP33+ForRfD-n??aY6&bF$*F3DqBiK!wU z-YpseFl`M*61>(%SDv$^0%9WFyKG!)_a|z(wmfz(>FZL5R>!PIILG{9Zr!w8e47>)Nl+ZLIyxAjJowr=RL6IJ4GWIXfn!paq}3i!bqXevfyxW>;1^El%;1Ij6y;<;Lr< z8;9D@FCZR=roIMCHK7qLB-r53R`k7v+*dCqj~;(Ig9POlYkl64yO*lEXzk`!+6F8{ z{kP565-0qT6W$rkdM_EqFOO$`>Kdn3NBZ7iZA!{kvuWn$$9SL z2`(sE8O2L0_NUJ=u}=>cLK9U(pA2w@^%1!Fv zO6oAI(&U45AHCrSv^HF13mgk0^NF`y5+w*B?r~L{5yj7@^7l3N6eT%GLeCl;p=|Tx zRwp?jOj=uBJLh;Vmqk)sL}j!k@>BIEtN97ro|Exw>w2Bj3jbmSlHw%>12SMOj$3AC7z`bfc#&ylx4UD=wGJJP|;*CZ**3M+` zD>CNi^e^vi2y>I$B$_(QP#ojXO(GI={s#KhRI94gV&%DNgFf)QoQ46D>M~^7WHc=~ z0V$rQ5z#!(`sf^a__iq@Z+5XOPA$l-<~ddIA)2%RJiX|Rva97D6VTZCUdS|w`Tmr{ zI@Fx|IVc8Axg$o{gaD$DGOR<@czfCvbGuqUqPstQz>zj~(FWGmhYKKkfVV*-p7(4M z6|2{kw^axegC)eU(O}TbsC&Vdg`}Ei!5)3Y<9c+e|8my4-sFPg%3v%@#;@+PWp+$N z73QrySH5iG?&%pu5FDY0Xu4*dSCpYf`NpeE%GLO3ayqjbNy}l*GR@2zbupo6pD0d$ zRLd69@Ad7Z$baVU+NWM)Us)pUzSQV%T8Z&Ri&*Mw74%HFyPBhyj3m7D+MNp$63j7+ zGOT)2TajWpi&P^suea9hM$)7$6-^pazW&kv1o6s{aQH`0428jnX#AU^v(7X@$H4Dz zGB0d zx?dV^nZb<*06{30n6chGVSa$sw@s`ov{%5Y1Nq34{mA`#+Ooc03iZY{9wr!zZ&Uv? z-MzSevg}rpS>6Av_bc<=t#LGf`zDb7b|WlKvD`W|z#n$T(U!j!5~axQ09RvxDn}4E z4v2kgDl5FXM@{1qaAPlP7{>OTOZ+%dlZ%Q=^A@D{%i&vD&E~z4UtPVHee*6e7INTu zcN4f(YC!e1IcwGRG6fPb8YZ!jegr7Njz%^f13z!}Q`OrLnzHOZ5cj#sWzhtkTiQHR zI1<8g*7l)dY90e7r5Y3?ie&R{^4Ji^H_1+S6346`&JYf&VB|@R8|1-AP)(BGd@Tco zA*3%I$5qfUY7M8lYY(PU%RPm{D3o&rE4Z^?WDV6VoN4FtWk>1x4M3hBnwO0$1~0th z+~k8Kql(IOBmlX{Fm>Jr(YL?aFSD9c<$Yyf?yyaf!9T^AH9c-xZf?=3PSFEv$jgS3 z8EL`IF;NNEM7yjaSqM;k*_gi7LGMgv3RFSZun(6YtMpph;U$Oi7{QOzWqdPg4{zG1Rj%wl$hFpo zq9>%#3ZUJKJ&r7rcS**mkkp!O7E+a~icjJvZBg$18J4CXyz0gPj>eJW8TxpQ*`!V1 z8A&b8*o~ZYUOYl$%+MS6Y4eg(fY`k+O_G@WJV8(gToSLNAecLNB)ZevEgphqRjby`SJgsAt#J@JPMUDPsWkyV9x3aK{oPGP#8+?LWLHY8|iZkLt z))00m_%klMA_k}7sY$3x50b9Sbag_j&iHruV-_Zioo9d$bxc9!gD9$7z`}v4LZ(foj_r311|!?PN`PG zh zGB2|_0KnL^bXH|PMq%AzE@w*$9@)I4B)cAli5MrgpbS98@Mum1%Wrv&4r}{BT-6Jd zc8%VYw0to9VK$`j^L%^vV#105NH}dy7(R`(gPkH=8vh2V6$dUT|J67ON>nn(5-tUX zWb;!miB+HP*xOgPbx^#Vw)yeh@ln=RR9JkenrCNpB@Y^-ZJ@394PgrF{SdrEz9h44enZ7*yS&OtnWBVNr{DM^3Vl$|->uZ%ESg&p_lB`4EUD{f(=qPQ3{7P5REt@t28d{p zU<6@K52w-q0>J*b~&M|(?RYQ z+IRj{!Ky}%uw`SFp)P@J$h%Aj&1PW3+-+yCj^Ji){lK4qc3u}9x!?+3s z^S&80>td=ZE)uCS=hmJj}nY=Iz^SouvoNIAIb3YY{=;9{+$(C`nNTXXP>bM4LUIETc`Pfme>J!GP2= z&!uAE&NoII9>3utga*Z_EL=<~%otRJMjm9+)9 z=C}B=b`-kh3cvChMde6T>U(caBJkj@nLZgQ+a4gcM`qQZKh31Srr+Y3c|R@n#IZ36G{OuM1u(dSTv-J)Q^wYj)|oSXc```smA-YB1J+o zX+qa-4SpWw6LG1qX>WpvN_zuFV4Zdv8pXnld}}@;3%RkP)zTg zU91Be`h3E2ec1}*zsH!!x;J)+rzGcpS&-~G4f49&pU@r>ZQ~I11l-Z}8{$fXA_2!R z82)1E6i5&H{&=n7<9e7{?N3Nou3?|8u%~^DFQyx2h8!)Y*~X44`2H5 zLG(>M&0YPCoRn{F}(7mW0VssPx)qw4PweAxbVrGT!aM> zecuA?h_!}&$nZ*KZWAK5q;pKd8ZYX?mb_eH|>13 z;!fytpB?3&+)K!wbMax-l`DwX>J}xVyz61Zd--$RVjEBB&$WJICQE;%2iY$#<2W=~ zuxP*E-v_DsK=+GYc&2r<4)~)lRHyBa=SP*nQTX4G#=p1o3_}wT3iFw;L88(WNv2{3 z@X`ecU3gX!5=`$!`9E#-R?aku!^2tM8=(>0CB@8A;7J@Yx4K2ZuU1Ozji%97NfIN0 zjksr~MbS=-3=p=3%5%v0=zxch_w!M{g3FV~)w*NJxT<+##$41fw;1Y~J|tW|jo&0S zphOg_^>^qGx8D&G@B zNAAZBWCdpn48yOllrSf?qjYs>)ZxjXLG8|%AlG%DU2Y^Xi(Abh1s~H|vp zV2e@8Pcfa;SJAeMVJHN0z!{~Uxfw(s&qWkfdZ6t+ z$dl1A7IHxl$8ex7o5D$to=p`6H*KSsE+{7R{mmBFjmFI_OPyzph+u;q1`6JSDy@Qw z3zv6H)FOz#UIX~#ipk|S?9?TS((68MBw4JjVS|H@1CL)g)9W!2mz62#>6GC)eUkkO zDDO+HXOC3`-rA4apwH)z;rcl)jZz$t1?YIek!)6>RM%TzgSttZr5U$gkZB}YosjY( zB&+Vj2(Lsg+#+#b47n;i)<6^{nPzEv=h;so6iua@K1vnoC{@yRzI>S!X&;S)YgGv|J9N6s-Jc zrrCl+B0AqOA5MF=0HKJ zSSi!lLnOGA*sr@$RBi!)@@m}1b%J1$ivqJn$c+eHKgaaEISj{b5@t83c=pHmbuWT# z^lZ^Uj3P?qVst|;bUCm*JLORjIf`N)x}b4*I>hZmw#JDD);i!iz-15~yE*MVnh&e` zQ;!;nbuZ_dlVAgMf`_mjR(P!+>?{$*#;w*X$!O;}z!Wf1As2fWAx-UoD5`QUlPJcD za>qLTrJtxV-m?x8x;);cs%7vB9t7694iB@oDMHR>9?b=}^nausp~-e7IFV0SVy&XR z?>MdZppfMD+hbnbcGlpP+iEe2Sx}gEl*qgA?jN`TC0tgMDs=~hYQF5cQDE%`tEt|k zD|e@xoYk=P&m((mrGV_Efy;xnOfKZh$f8&w;Id+dAmSLyVS3-w#@^I9d}iAeoTCXr zh9aZz3#v3G?V3qwiYBTk$vinK)#-c~)euH>@*tTu=npI#%Ce4=ZOiMwkbz<7SCsJZ z6+VzI3;7>}>}T5b2wBKh`t~D5>+LO+R&4~Kk+JZU{{#B`mk*V}2nEwcGzVzD;lceO zJpTrA*GZr_zVFuS`oDs&f||d9`ik#zuNeQCLD>H^(a!T5sPC1rLH+01KcKuv1(ePL z`AC!aPUElq1pD7~mZ;cyoWJ$!^y3RC%KuZA<#XBJaD3P`Xx(5E+Uh@Glz;lL{u9cD zfjGy1#L@mwU;pVBHe4&T?lm5TPjY|jSG)6jC`Dk8;pgigf0-{z1RrWBMZi9-JK=Br z3fTJsB|eO)JIR>*&n1IacPj}c(yZ}*X8vox#_*tvAwS>>dG@_8RWw*^^b0z$JDnoo zu^XQ$oeNy^!K(1_Y}i}p5-001kGIq1w%-+W1+TU!^{u3K{Z5*#G`Y8Edz+1!k0go3 zzWLx`wjtL(Mi8*n09MMq$FvyCli46Yn<`XLZLx35ceS1i_10pQg?UlOj4C7K@wm@k zk@)R-EY|aM9X4Iad6s=}Z!}};hTmh@HZ-z6N0wztXZt}?WDA~Rx^gY)^bZySF2Hb zD}uG?-9~5hSUNdq@n-~!e)Ik%?=tw|+-_D{@Q7D;%eWQGa#=jpZkMfmkMLH^FNJqi zJE>>=#raGAfoHban^vzKh8D>6(scdRSm=$0KyQ$_%UjpMHcq=s!ntv(?RXabKnS%L zymHGqf!dG$zWN;^c)@;Lpvwv9zLj-L0>djHrs0x|$Bc6%T`2W@$2%5TGks7i;*EUr z6%^tR+6Wd!;KAO8W}$bxLRWzB=F`*uRsZTIt>;woj;0yjyt;q?F4|do3xCnYSuPhDa54o2y!Y?x3JcGSe8IP93hKe_G)+`U=T-cu zq(ks25SQ0yA6p%o%Zw)HBYg}wI7}&teYkv#l})6VfMVE`g>OTXhl^DU*p3cVAzXK& zE{d+aN-PA=4gUDUnG_%*{y8$gr}#`{gynT}Ok(bBpD-~bc10YNnEP&M#5WV9*ecV1 zGMvs8VO7-85^nM(kxnei?>69j;Rm8`IX#ZmTc%N!>FK8ysnn#Ti6{%~j@2wNudoB` z^qN#|M4rP%+0lH}LZ2=G4H48~&&D3-_YnO(Z)moh`^0v!Dj*b#NW8`Sn)4(Z%yGO1 zqz@q$jd?+h^i;H{hC!Tdb3?-Wwe_(CAIiPxuYxpZ-cBZd4hP?=pgv+BTF+FBK%g9U zjT(XCs3SC4%DG+80>^Z#o&b4#=ZA^?7t~kOi!Ig!&_zzIv|nkJ2bR2WkF@F_m#k&` zVahE~Z(kUCbqFPe@K|QyU}wo>N%fBZ>>0M%2t@RpCO7(2fLoxKYEWcfx%#na9RkIQ z>0ymwN;CX)OYseOltK z#yS@8=6K0m&{?3vhI$h5WPNW}zN7AabH1nant;=Gf34S!EPwIj!e`9Qm|E`CjS>}P z_o9y}Q9RLhmbp*K9M<(66*9TKF8A9qPyJ`N;BA>p$LgH8n-L$T{$%D?m7ns6?uZZ2 zUG2+f(J;}rotG=sYYMVcjuRB2ES(X{FPwp?kX_GU@xq7Q#{G+z^s3l|DN;97hEPJz z=gscVx#f<6>E|@(9Or}yg8M%#%I&`bl##v`o&mgf`H?oLDz}IRX$~>AMQoROgKMJ$ zG8LXZy%P^q3yaU!LUU&x!zk`r$~i7P8nrDovn!Z%TS=E(?~}Qlk(?`3+sNfrh`HV5 zbiPUw`m?hZ68+Bc`PTeSOM?l2mZ8@uI%v}F-3#SD zyglq?wgj)XW)=8%bPM?hJvOp%*`!tiOv(6xTlekH@WIKi;@q9d>?@G#3|0q`K(=f3 zBSq-LwlI@~={no*^H4LiFOo(tEa0={1Md;;+Lxo}^9efN>rWnYE?Zn#Hoo@=Pvjog zZx@>H7;f>r8;Bp$ERrwPAmv`1Dvm9*F!u?bMO#!}nVnUC%7h*QK&&xtbr@t_UHm|+ zzkAESz}_$t9-&KeAV+pQ+b{t>oVGLkEXBc<6?p#Hg@~s&HyJ;LH``Vef^`Sy=_=ah z$M3PV-;IEub{@Vl?}9V=Ygt#o{ygP~z@jW0gH+JrD_6G9h^n0{Zl?nSaCH(Jd^D{& z=_o}OeEstA8`dp&?Z%Oqx6af7tOm4hQ`XES*QvH4g5>%f3MVu?mtVt6+56U1)e`*j z6Hh*wZWX$rPTPjfgGU;Go|5T^B^qxJ97tv)Xo%W3wyLr0l57nV%scuH1u$^Uo+IeA z5iJ|+Ms&PbfqwU`j?@hLKM>R*Ki)h|?^ffNT%$|bTOKEbr46zVW>my}L(VcSeSlqE z)E*frHrTZ`=zWZSvGbUZbL$%tjWshnqFeOwZj9b)o9^S+Z!(5Z0+iHJz0J;rG6Z7_ zD$`tAr}2k2P_*R$752-k_t3*4xHV5uqKxXvvL~I)_dK7c-wcr6TFVk=-3-}8X1UzZ z7`9+F42H|Q3q{wKIAQe~z5P5l&D_sLF1R$ZAL2_jHbz&29k=FLIi>p_+n$$0pA%_H z8BAy_?etB}-Yt zrpg;xn>~v%0#hHk(j<^D@+_bSqYCrork=7~L0zF(J5>&CRwKm2za9(o4~8vcyl7U* z!2C|PZ1>X4nf*_awDIH_shet(tr(W{nQ%9YIzlRVJfwiKXYOUM@pTIOlGmW z)Cz(I8w##?SHROlalKbzB$2@uKRo8!$cA&`N&emu5qmHWm(@$zBsQu(M!DItkAU7U zc(IiuB06|?Gn!LL_9BkL+Ni-h3_c1wGY=AUy4eVHrItm(2e^HTsb01v_^MXNZ><5D=y7}fBY660o~WPS=E*(1;h@28Ko5w2xuG!2p{wbbVi)y6%q z3ePw2`>N{o!ZURR4wCH27V)22?@@MtlTo4` z)Ul$(gJ)oKJE*fg(ioN7kMp~8W&ZWTA&BiXs3V<}&&h$D%{sMAt2GjAI`BPY$$a`I zoZ~~PhR8&4^;S_kGGcKg13IH70xPlvl$Ese{^vz&Hvd}G&kQ1d54NVd=f)iZd)oqB zRun}3Rt2|VTaL}`X~}yXsite&IEcbA(qvilVPTd;CYLU^mjQbV(Yoc01a6^QTWvN? z1cCCFnbm>v+2%{bsW696n+Z~72cbt_XLsz5zs~?KC8*XVB)C;~KfL@dxTD5%z?L?c z*}&QTz<(Vdw?~*IPJy+%

t&fDmiy%XPd11G(wK_v`=)@Era9ioj@fa>9<)9 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 GG5-UiT$?8V literal 0 HcmV?d00001 diff --git a/developer_resources/images/dcv_desktop.png b/developer_resources/images/dcv_desktop.png new file mode 100644 index 0000000000000000000000000000000000000000..3c62f20b1afd22e7e86d9ca0b058babcc476a87c GIT binary patch literal 709382 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%0Ac~%w4zVVKrQd#+xf&w5I{q{K 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

3ZUT<-e&~;i z-El-bgf4c?3p_rwSx3XkGbS9DTf3|4#2i@1*>|IE?nCu@52q3lbE&k9894SP(hLI` z!yLlSv8YFBFl9LYUHbmP$_)1kJSfO`x~>HxqZ^ODYw0MIvyubMblz5^ z*BfdFw#rUKeN6R`1AU&+=T3X)$KKPvpCM5O$Nk3IGfC?3*z_sa$JZoUi}9YwHm$E~ z-SKnCkkma&h;&SY<4uK~rUyC(@q%1!c=Wuh?dF%(0MwO4dWToOjl`UqsJ)@&HNZd3 z5oC$iS)0;(xx4*SA4hy2t#M-vp1-n!bBmX4mL}wd{D{+IquV7F$f$awt96QZ`^lGiE1l>711uD#G#?+YgRI)IJ_ z8SK1bgB*8hsx7_F(2l*3&tqjJ{#V`y8&;C=4jUuXY#8bERaEdzBaD!Z60!P>8~_&8 z5zpq}uEc18vElgi9H5OWNBkm!{f#~5d#!!d=L{7z)+?>`a=sKXg530UF3H1qa;0ly zYf|=BDH4qGZ@R8YxO$9oO{WUDhRt~&0g9t-9;;DxDoU5wJVHVu)NaJ_x@^y|$^SEs z^Eg*&$ZKzo^=d9?4?dyVbh8e7g;Xk(u80hqzIF{jUWIS^f&2zpPs)H=J{TcX3)ca| zE|JY^`^(VMoh6w&R@!N|?+g-nPoYqBb*l`Zm9c{UA;k zfPD;oAC@zk((#gP@GsjkI%v9gzN&1ekonPxWM*&B&gPf;?a{j!JnQ?nhiE?PGRKz3 zj~bsCgD>=l$BF1Q@}g+NC@kbggI*Zx&A8@xiBaF?d5sfO0Q>0^LWmCa@8{8Iz5N7I z=8dfjp2G+8y&WKr=w9=BySH&2p=szyEF6TbslA1s4G`@t1rvNfHpJj@tQ~T)XKtkE()BA|EvjTt%h%3-STP_d&t4Q7l+pQL+?kCJpC3s7Bv>ha{|gkw1$GBZCckJ(e;iFZ2jH^fjAbw!{|X zD+bgqz2eaWSPT>Q0-62=;-d3Sruf3cyDZ5W2kr>sJjXqp*Bnib6!^t!HN}ERB35a> z6nf*@p9u(kz%|)^+_iQg`@=`$jP)i8u6d9tUbFQuAL*srDTJXphy8Oss~LS#yRjH{;yo`K-Zk zzBG!pqF&Fv)_*morr+{(&4VW0u-3H3{hAiWCG)lS1~RtKYyJeM;r=(fP`SS#H{h3B zr#U$>^d#1Sz1cK7P#r`#(AhX;v;p7|!e3|6bDYsOc4EeG=W<0#gdQ1JMggGG9*NssC6VveA1{8@aUxAV9n`A<=1PoIX{%j>qPV2RijB`|e{p&Ms!yZ!#St@On=ntHt0L zmgA8QkxbsHE}G0|^V16xx35#V`EwJedg|)FYG9mka;rkb2Z2P`X&cA!FJ}W>e8Mf( zIL6$3geYTC*aB(tVh4UWyc%yb-JFnC#S7GDJIH{#pil249`TVQT`j5W<|tkvBa+kv zrTXf_FJv6G|Wd@3_SIPQg-CyW(%zGf*#0jJhal8%qV?Z1A%SSNn4JdF(MH^Nu>*IqRVT$YE_7#VS?0S^3MNDCL z8)NCnvo2u8u%c^1(J92@?@SeRizt`iy&gT!rPkCi?-xLIZRy~YUYs-;6R=rpfGGVR z@CJUH4onCqC(TpJ9cy|IiMKZIvE=p*^P3)rFD3q4x6*O8P&aq2tfK= zBs`0VZ32%_359b%VFgmQwgiE+!$?`@b+wc=#XC>A5hSyFN*mGsR7%TL*0QK#MM17* z`y0lc%*Ai$<;11ogg22pB)@Vo5{LcJ;3ctEa+lPc@TEe0-JG+$Z?@dOKa+cJzE&aCD{&JUdXbqM$e^m1?y~GpTOHjFT@xO+VNa=+) z!aCS04%2X;^9hl@0#IbW8gTDjW`9!l!!!p=U`BGC)CNz!wc za4LK_A*Vpi;(Tm-8~ww4gye80wtAF_SRl`RGO-;$fSq<)D5n~4mviZLwq!+qz}GB? z4R>u|Ii{2A+J@~yam{{>HWvKgE|0`#AQPJo-Zke}l2iPm-N)Vcosq6-l9ca{ov_?> zQNle;Qj#B+JY&G3R6~gt0==Y{S@t|!e-MkufFyh`uRPpYZ?;~dVjt*wXyEj_=fBb( zYoU611dCF&a)pP`#dw`!P@bmnmJfE;F0l6Fui65IZy7w_o6F=DB|U-+`S-rn&?*ISGnxh%s?%CgdAz$si3d4w_FE*+bZuojrz z!!jt_HlK2|?Y*Pc|JLyx89*&@w`|7oI?Hg=8CL^(-DFZs4l|guVjz?QD7V*+0{yZ_ zYAxZOoc4n)bm0F%3@Mlpt53BtlU&l(Eq%$wG<6GpuGOgV4Yo#StDT8S;Sss%4flP@ z{%;?zuiw}6wak3RJSgw$UhFk^KH5uOm&n4rj`E~Nwti%^CvEL2%#*dA z-7vv!J1L3A2DAFPX!Id?QSx{+-qh2k3WccDc$3y@98#6p#b+;kn4>t>P`Yx;vx{?> zz8pvIZ`y}H+*5&+h##?AZFmlr|BT2=EAmd`l?v8>QCoVooN6PA2$@4jTPk@y9TE3U zy{u~J_d879m})P(F}InIp)Ca*#ku*5OU4}NO`NlF%yTexsS^)2BxRhz`|R}=I$+Eq z`9yM?Z@ql!Lrr$vVB+D>b-O*T`4Qr(BJI3ZNmwPM5Q62TFo*~L7^$Z`mpYG9E;K)IAZ=-UeLm39}bo_;$KT}_HUKV! z-m3XssE&`fl8pz&vI&9TUL*-e8=FD8)}qSNgo>e42yz%S3o9}PDTTE+n}rwHzQf!J zjku;+Ur%#e6}pCHs^p6{;F2VrJ5-MA*vV_1ARIcX87S=7H3NFTtn$ck`lM>IHNF8(bxNEMJ|QQ zS>kdWBiI9!X@&mhZ((8QgQW+Iy##?Q&%HHh=5#0bk|Pf)!%zR{WnDXW4YzExi@3X3 zdp+2g+iAXdq$r=uKt9TOgngU2-5vKxdkNOzUUDVT55b>L002M$Nkl;T&J(2 zT*^@=pz1sB9soGo;hM;l+gAtrjwbUE9ZnxABSngj*;NjoArG=?;6F^k$}EWJUgCWEtsFXiiqg{_D(WzC8u)dH!GNpDPIS@ zMb9G)Yj4G)Y&}AliiK$Ig4iL|ZfW39X+^nW)rK;FnWaJ1dyE2QioP?p6?3IOsw5Oy z4+RKw@_cqBFd*IXCFZJ)M@KIvZ<(05I}H9*?z4=$bLOpH=EISi#27s}PIg`F9q{ec zg&Rb72E!*Bb%&jI*gALbTh_w4`)`tbYE1ewOYiPzCwmsqYkg^7T^{{bpH{ptb$T#9 z31E;rCtwk|vM9lW6ED^>-eM+sYUMo6D(Ov^STYY(UKsRbCZqfr6CipMgob^J?<{*F zPD~yP$v&M2JlVQfnv${Y)d6_&s_j3m=j7^x7)SF>@OLsnUIN&9Cju)O+JnqWj&|oh zwqz2MI(9rkH%WXFke_~z80Wp_4dOyx<)|)zGtZmKi3CK?J)ZlO=fdRS7pi)>3A_4Y zt}n&E0~2m$C$v>AUiG_;@2f~re~-HvKZTpiSWTifcNY!KFV4X$`Sdzh^qST4mc_J> z2X(^uQ}ny_Ud|agHbG~{)RQG~pW8Zv3r?OJjth^OQSjh7wzR5*ztUH|JTZ#NmmLP> zt{&C*)bWS}`|1OHoyb?2L?H8@G#;nG>dM3@cyKApVWt9FCaX61f-^zcoGfXUGxTia zNry)2he9ELtOL5!dH z#!}FaexR4m6k%YTppV@ikJ^Yn{!qrJO8*dqc~#?4AFan6YtIr*F^vW=zj z)nc#ap#PSG)=1|!_^eAsFZ?>JL0Ig)}c*m<|DX_ovz!sEVw6a|D9>(n6zOi%sXVEjMd=RB5BHuHU0sdo zdA(;ojI<0dqtUmoKaMdppH{pkb=o3YyjD5Y{*+v))~S=enm^^!H?s4V@Na|ORy@z> z1rrcmiyM~{VRS~- z&V2#WSQpPa@oMcn<&D+vY0cZs?1}An=kLUay$o&|&Suw%)FIT~t-BH@P6{^W`h32l z7N%EF&a;SdVj498IhE~vIMH{;Ki52+8aHpdvUxHen;T&#{%fwY6IUX8!=k9*YM4f%R6y8|nRe68(RL9BZ9=jxoC*%N;;Y|ZV&&5kKuuB6}$*CWnG0@jg$(BXFy zr(MKzn!^keZeMae19^#tf!J@zmc7lom-Q0)c@YxL?$!L6FU?9DNo%!!lR+!XGtMfh zd?sAsyoR)Ew>BKDDxK9yON;(YT+?n@VEwe2$oVJ z9>o3$ovU-@O3d%Xu72Daq;%BFd^!irQL1Ol#{9}QPM7Suq6a>iyE~az$Ex9<nux8p&;+=W;yp%f`J`dgy)l7fI-PoapG`;SYPquHv6#CrJ_ggRP zdH34Ar54+0tMQtxUcYhj*8GC7llSI*yAxY=+YKkAGVeR>1CdT6?H- z(v4t*+g2f{Eo*`2 zH_|<=Z=cBYI#>F=Pb=N}=J`q};o%0y;$TJ+p^h|*dq(fntvfT9O`MDdlnI@FWceen z_X%|DUT5awU|N(^7T=_1Tjtb{Up%v#wV7=wO+u+|mML0*)Pu&Wtwo~*h68t#E)V7q zfd4R$)CFfEHE=D^XqJAcfv)vufaSFqRDNTCs<|S`<(%~VrrR`o9@j3wS$-w&Dk`4J zH&$!~5M)iD#5z3Dw&;+Q@nbV|@(YeAh+R=Qw=6FR96L7F9h~IX z-{Xuv}hRbp36?}o->#u z^)=s1_58jMdD7JX5*KL|4@{)BY!GAD%eJ^>=8I12LlJY#0E|uqqxG*I*YniRYTa{M zd#2kY{sFC++z=30$Tc2@>YGLw3rk#(i=Fj&L|OEj{2n`M+qpvY#nHCxT0r(%=8$z% zd8{VWt#n`&uPjuj%t|Dwx}N7{NEPL&50B86z5V*VXF{NC)MfwhSmQdBUy6wj>fKFW zme>;}&i!#K35&$mt1`vGh!@(Ej$s+G|z*KYM%<23ha zC_;QqpMK7-m1lOZ&^JDA*jFsgWQVn9CU{8q*TGcDXykqUkt5xEa+3U=OuTlbC4cYI zTYaX#^Xo+`F{~HC{xEf=vMwUUTg7UB^W3jm$r;O z(BRj~H!9$K&Iv}EKSrMO)eBu|KL9~Jl;)W!cv4UV~JevG`Elnao@K9{L{EPvDW=hXTnpx@Kl`RrX6jGxL^zS7>y=6cSJ zIlN<~&kOwTX-nK^+|V^@X=h-<)0l0#GWtKtMmXXK0zsmH>x}}VJtzKZ6Xtr8bQjo; z*F@c!9Yoyu>X8abK0GGGuyuFLUL-*%Dqc!S?xi|WWzB@wu@#`=dlr%80@$u|z&e|ckm_li$lv+ON333`VBQ9!Q0SnH>+f?a#(t#|~9k>8pp%S98wstKeuPAXjskKvZBq=Y51)gO0!{M=Ts`8z4?r zdX(|ztd z@V+F5;M?{+f;rYNMqAAI8oZe_mB=qIjZc+i{CJ*LXQNjmD8m)bW$Ubee;5;1b$OW&8U zG2|HM$Lr{0^}|lw212Pb^Fdytc+#_4*~=xWMtAxYz~?Uy4ll(YvYLrnyELrFA#pIVMns#fgaGF%#isv|5!x5qChY6MVyZ)@5(j5%Wi<+CF6W(;f#DqfKS|{^2 zqgB-i)X1f^)*ZxOejpszpb`Hqlrk2G)$dzdE$vP;C071$p5q`_2^se!34>mdSJyFy zp(Ko|BD!{&u=mWHK&^o{o%;?>k)&U5;~i+lRGXe*_WkP*{8nqa&FCVWu(DhYu<#eU ziT)tFAoOWih~}&nfbwPzI(ljL@le7{u$Q}G)DxMN{@3!3#=W?BMfOfq%VEWuf;WtG zay*su5ywsQZ3ruWx5}>yh@c?Nz zUHbe1>m`$eCD6k*5CZqxcCOUDEh1L-5*I$CFm=lZR`YnX4ty)#ztblzXj z(@sVs@1Jx`R_!;2rxpD0N-UTsi25M^MDUUDVTi^!eIEf%L14)){8RQooOyZ<72~hpMI)iYHiMdoqkto)Vb{C5CA~4 zZI(pu9cAZ7@!&td8mQhc&!yKKF3gN+EiGJJ;MI>L&81I1d!X}k4k4!glHCQmke#u9 z|NdL@^Zxnh?f0XMzRsVnIv5%1k>5x{ynW1Bb@Vcs9)0R%Nq_ZdZx%@u`fe$rneV@) zU~PZZ>g)Qfb>#i}c1!8H8P$L->|9@^C*9^Zec`d0X)=vAYZ)dmMx2?>D|F<4zr~pM z@+CJS7|~;oa}Icz7iYczyRG~5Wu$p@N}V60r=1?YjUoT<&E*v`dChmr2_6i$wdjY$ zU;i+8=bDZbVLDzzZH&{LH;va@@FVl3M^+jAJ1;%Qa^HRfJ3FT!33(!z(;l_uBG>EX z(|(;#5u;%{ts)yG$wy4wAz@M#o?`CU;xhT)<)Rcdfto=+6~&;2`34E#E4vJkje&LW zYS(JE9t`zw!Xl*>kB6rcNDz%Xc&!aBldTpAjE{G#) zoL8pW(>OZd>I&h`BUlT${a5p8z4~n;%;?c)Tbk+o@BM)sHcScZ94n)? zSGYFQZBnN1`_MVj^E!PSetm9p>+qpbb+3#`P|@>Tpw!MhCjjz$%RA?e9XY2fq&9TD z#yD28RUCY*wdeCGf6`N zA`PVv_Dq8Q5x)1|aAj?Kpr9BYEKl4qr>3v;aw?#V*<*>iRKU2qb^x8cI^Js&e>|7t zeiFzP*%Q1kmq8hYQVN}(S>0uApnSNlROX`bj{No0k@Xwh=;MmqE(txe>yKFR8{#I; zHKSlS$Xh&d=3uW<-w6)o}JZo#MU%3F9gH^GI8=tp$Gk`i9bfv!ua!-vX&?^f> zHu&2UqzI_qR&X81dnZ^HS@UP+`e*A5Ud%jczV2Iwf$_(V`y=$# zy2x)DR$6E7#;n(+;7qxb%5TK$yqSf0)Cunx;5Y zhbk2aqOJ2Kt$6O9x?9Ev5AWKBRVzF~ZY*ixnwi(lJO+Ux)6+0^b_wQf)r=N#@O&Nj zeAsu$zO7_0KQNu*XPWT9Kcx3oy{Ddj($?D7$zd`6Y?ZlGhstkx1EKvi9dn&~lg%;1 z(8$CV^!&aw@0j>`M(lV!AE(?)2b(kzLl#FOx+cN6eqdtm1?-$hvo?2+JMpbJ6@8Ol zC(bTL1@~~6->eV@)-X)E^{;!3Hy^S!gmXOOc`G}!g2b5r5yAW$#CZlV@L}*n=N#u7NoH%r``ufuneVs${Vc@imZN|3d|h03 zhYB8TeF0@2UUcSEE^1xq4F(3n1+a^vGBo&L*XfcnEg9UQ$hPtvyk9CeMNy3QLbT@H z`ogMdUT#$rwCNCp*Hg^XPoKxLke z(TUv4w{|`))kEJvq=)rb>Hr$d&lcXB8rnoLhK-9M;?-kE$q0n|WB#07^UP%IPe0&> zvLT?=dJ*eWJ$vJ*kMfFj>XxHEV3D{ai6?b+#nMi;&8eN_C;1#@t8J^TGy9|Lyjq&< zT;|N`_mDz0;e0qo6Dg4MLRV^TDXZliZC%QYI+keILXa?wH1ny^0i634WoROsqDymt0F87D~)Ocl-2ENTYNoOw_`m@-T4xc)|yu7AY z_?|{^9o;&aZR|kP>l}RYxX0FhXH3B$o6*hEln0YRtrP>)1kd#dB*&=qBdhU2(bVJX zkx*1AJ^5a9N}m%;kjPQVlOo_H#BY6&e_;^tWY|c0RN{~{CzrnW$%e@Q(Yu>?5dk8S{8|nvJsIxLATdQvTD9b3=*JF`G$|!Bqu%)A47#Kw+hNYBaM@@Y)v za}Eti`PdC&3j)SDUyl|_N32yM3a^UP#u4(+l41b!ul5u3FY$KUYazt0f*QI1$%%0J)(9~J_iN?&>`vE|{2zo#CH z+yvuG!VA8*4(g{5sq`_{WBv5P`)JhKrcQGd=O+YiVG#MjIY-DBj`RlWh0kaR(cf6P z_HK>Y@!__;Swt_!K+F$Y1DxqmP$^t1fQx7_ZX7%GeT1q|Uo?Kv>5o<5g$6x1shgS! z2|Ta+7aXA~2e&!~t3Fp0oF4&UFw86Ti8I#&$8@QejfuwsX1~kNCyT$3dTygl*m_|@ zaNV0oK+B?}m6Lfw*{6>!hs{H_z+)R@z}clb@)G(Y+xiW4?Qbr3nvYXC@53D(uaEYA z9qKhc)7P;|Q<@TUrvTChy~!vo&W-V$+{CTr?Xo(IW9xofoqJ98dsm1O&sLOP9K9~Og8t&S&H-JWMGqH|%<_758N92Dge@+J0ff`{w4Q2uMOw~b1S)SL{lFVZ zZVj1&C5%;FCgM|)FK>^jv&atx1#OTNPis(G$Otxyqjr>6QiKEkPF3YQS#J{+h)V3py*Pr07vPisLgbfMah zBzd)9ifejZ+zI227?pQ)*ECHMSb#3n;V0=twtXY13F?^k`jG8u^mWRxcqeN7g0G_N z-ehXt#TLS4$dU6@kLdl;<0C>BrEB(5zCUaKq^VATR0>4`(BI*&tvpw2W>SQM$IlaH%gOVWz9}Lfil}?Lao`n69?N(|p>k`b z9BM+{`8QGX0g>eC2>aq@EpBj%*!9?r$=4T`Cm zX`oXLVTe-D3!Rms@X8G<@?Jn}aVG|kBg~x>2T*`mXZ9R^FgT9kAfkkooPA3s*CX|U zOEK*Pm>#9(ewJNiY7RPi*!O$K?z%v+IfL=AFZzYW;f!f@oMT~+XmhTCU$wT`J4u^Ys?r3PNh)8JF@G(5QA zSHy!N{S#otNx(9acyHM-^WE-I|d!^G}^K&$cC|(l{E9{1&q`4|Bg<okba5xc+CxcHd9fy9`1@=&WAqFTucwLBHX9+Nd zW3^ug-D@D8EIrxHOold;PzN^f)gCS>Ofch{N5&s(EA!&RG;xi7+hT@KW{y69l#rdE zOBMwk$q8zccq-b-X-3tVj?sZ+es&_;uKKYyGhiIo)5JlT`%ylgG&_OVs&nX=h%x1Z zvyPxL?qLnk_0u<+1nI~T_poXeFK)+sB*P9BIXT)zk971hi%RI{o5`=_z{BQbq}l!k zQsX1Va333~)`M?Y)Y)st)%fX<5wNKYEw!uHzc7IF#vt+$LLW=tf7%I+8#!O*2+XCx zp<9N7m~7vvHJkKvrvbjjLZ2JPiEfm6=32q7L+DquaJgsYS?312n8)qbjd4fh{8}i= zXiotX`icY{=fO&J;K^Wx4-5?gjo{C>tf9u8x569}U#&i(JRer|s}4f*cD;ZKl4v=4fKYZ_pqhdn!)&gPVfs}`ENtz?UZ zGDpRB^^2b4T<-C#Z8XaCc0g|{s&Si4#Pi(qHZgddYc?NGYNJMqM(OCGEFMZ0$ikYN z6%Os4$o4?^29*5t2S98u0xguAD= z9`#Au9)tU~PMQDN!_+O>Qou5V-1u#^?nADVmo8oQC|R2$A`e-FZ9SX`eoG%UO+KR5 zzqv+2k)~zVzpjU}eygUF6>;+^%weN8QbiL+J0Jb{aji~(dUdl{JBP1;h$_8==Rjh; zUV+JETYfTbPJ1De9FSBGtZj}N1@fbc);D5XT|wF)M;xtsZ%?6x;Ay2zlE1HvR?IK0 z(_)IUS$@47&6*l586IDQEr>X=z@tJGQ7Ys*RVQ7V4i}WG@+07mQVdqRwGm?UC{DtY zx9zHjhU~Z&QQBA<6|1chmGpQ+*M_V}7M8Sr7JScom#nw(*|rQA#!m-NUq0)89mBU>{IQT!cxe6CC`Lyw3qg?jYUKnR~m7Ki11l+f}VL28SvK4cYzk zo7eIlBNz-%2psdPb6}UxiMc>N@%Th0fL`sC1eD=0Z6>8NKIBM0wF9A`ec(X{Ts3f$ zTsxuh_k?af!G7F8FPDUo@n~xQ@3wjbe{(TQ*`HH@Q>4qyCYWstha2UbQ)GvNue7BkOt78}pjd20MrhgxmA7 zAA@Ui9C^Ky7#9pq%%wX=iX8S19!+$KL|2SC^Im|so_4uS>>iBt1aMUwZQY29Jv_Ne z7p30Z)W#@CC_7gEY7X^P6d|tm`0!ykR-o!srLX}`#TFqw$YXek;(b2^*(5S zHknf4kvPVIJYa|At#t*23$`Ny+wn&C^v!P7;tS@PyunnYt!Hm2jWeD)o1?lw|IcC= z5NCOjIb3A}5m+*UYPjc* z7>H>V*QntrV#BOC+F?`OlNVGsG5(T<`F#lTF|mCf&s{mkviivH{xpALbcbfSrF8Q$ zeL&pUp*3m;_Pn!EOxcB)@?c3AyO`$=y@SJ(#qNqcH@3M- zMC!l2Z;^o)ihI0%ctb>sZy>$F+5ma`Ts0v5OUN>iuQx9gWoG0fw4)Qn^MS1=Ax{Wp zxz{(5q#cew?b{7<(F?3K-g`2+%gXBZY^6K@`Gb;=A)H3vz`_>L{i5+DSW|PDCj(o_pP53*JCfr);!hF?LNV*6E_5FrSwKD z2rC{%`fSirb>ezs@S}$io0Q=RO-1@__j*}>^k1cbFLTAu9nh65NBoVB>H`>)P0`ai z#{i%>@gc?Zda1xmL|z8yC%Azm=6Z|pmUUFQAgZ8o`iNF@*7JND=D9^W4B1#49rJ@@ zPjB(?xH?r}dappHToLJ_{qaM-JHez-e93wq05~TcDxjmQCX*o!u(?*a%Z=#$ z+U4tboEy!imuu9##lI1Z(enAlY_zkM&M;}4Z~C{5q)AV)T0jpuwpGRVBc=$1t@%kb zveD;y09wzd+-pamDl+Dm>{v5>4o=W9Mp$0(XI7a*{PkLRe-%sZL8&OpUmI4^l^0b# zOxNXkKu6RFqCGQ&yh5^J zA4nxOeYPNWT1^VWUX?jydYdDRz9-+9VkbFOL^gVV8_JM^w`Y^z9ha@t6ih@hVGr)Xc#xLPw`@A0c1 zSbe>(mR|Mmj{bBqxsy`C)eGo5Hg4k1Szx6?rwtI?^j(ipCclDNJ6ygg>; zI+S=l!iY&vTt#NQCXH6k@f-;G*fuJ$j)Sx zk3BOKYcHvo=FjaG?9w&^ItM$`fRxyva5}2D#B! zNblnz7RJM5zRy}fE)!s7m7Y~S=nNC5a$93iY^>S}IJ0qxD{8zpf#)mltEI;p(f%G* zLp;gF9?B$!->C;Ua%a2!9P2EXfGEyjPW7n^eo7~d4|K~`o{0I8;hgf2_(qLxa>UQw zd3dnw`X3UuYP7zsio{fm?F+r}bAGF&Ys(co42j5y3EtB>>BmO_o7=NA>0LJI%ASRwv$Hk)1$n$&Z!6*3!QMe?kU6QFHIj!(x#s z3#~in9+v+Mb4Hg4XV+8j4St1gu`XO*DOcY7CcBDk8}`!Rb|U58(0z)cQ3YT7i}jJ9WXq{ zzSxXtx$+QKE~eCz_@*+&8Sqyd-taJq_BzvOH&8Q)#1h5|yRf(qQo_gBU=KB+7ocg? z4-l%F#%gua6sjeypJKJK#R0(lD&PLGNbMEA$*<>&tjx+nGP|IcnW{lJIB5c}x|Z;v zt-IPx1qxu1i|}94+ttRyV@|dHh0Dy;qX=+rw4;MLZdyIm@!RO-a`RZd zZ%vm`cw_Do!jntea1ur(S>9^5>h+Y^2QIeeTjcv*vtYUJKWECQSmE=mI8+su7cL@> zb<|X+#1j7Ifd1V9Sk*t%E;Um;*vz{c`@~_*k?@$SBfmswDGyuKUTrjJk~ltv^SeC2 zV~(kSPY-(h9Up-NZ6aurwMJ^LQY^}wFL~xv7(aS;N1D3!4)=F;fMyN zuFfvzhPQ8xXkLd-aDGbP(joZ}U+>l}VrTGjq!mD`B@m=T-yn-Nj$mQO#-sJ@mG#t9N$vjHrRRn+vLc4kbI5MMGcJ<8YyOtalLKPKgRlsh6>7HQPZS400#N5u5vSjSc*oZ+geP$n z@y=$YrVX_zcm+0<@k9*=!n17(6cQoY?&-*|zBQ1JrB+wwXKn?$0OV(qAoVRfoa^7x zxtmU9V{A~9k#^)TA8*>9s%4Hj+f%(`Mg}(0GB?^s4~~r;3!dckJJ;dfx0YjfwJ=+L zkMlMcZ1yfK&U3)V0kntr?Iz`0Sa^#Y(%8#;-RIl=X`#2kV%!gEui5%1x_us-wzc{^ z^(X$Gk0e9JJyPi*C;eSUOpQ0a6Ob(#R?2;|$~OOnvrC3(sEEAS&*QY4qOD;sAo^#~ zdZp{_QyYls`gmRR$2qgC%Q`qV9(Ys4sWziZgy+~2iHc(q!z)zE4ixUaTr?xSpSV>y z%T`{iirAZ}H=;cQCqaD#S>iF5QFs4wKf3TsLO}$!S*xF^*mxoyfhejl0D+8@oogaqcZO{=iX|RhaQW;NDB0^u50)@{plU zF29@By_Qw6%!Q)pqxX?Q@1)`tzkbS7E~7kPZ~UY$SnZx!JUCcdwmE=L0>zl&#&XS_ z@PkfBRtvh#Iaracyo+6PSsTX2tGoDABJEI=$EI=Gf?v%yBw_zEc3!@ycO-9}KP%*E zXmhoN@4Y&CQ3q1PkHV;k#@~ZPWy>Ojz6Mb$;7 zyh&Eu($_jrV=7xMhDFJ!zD|n;_0xiEiOA$Ak0Wj5`S$#%)hrl&W{0>les!SwB6(17 zyp&y?q^HduFu8-8*_iVMyUe?Ss0W)@>VUWgo7Qfbz&OE{%*g6eFJp*Jmwoe>y>}cf z2k^%)if#2^ju0o?Ee^z0gF1Hax<-LUU5DB}FbQMMpmyPN!Qx09AT=G)wfXJAfy5oT zl;?8bCE7a@YnV3gqzd-9Z<0n4O}&(SQMo|Rg~JGtRSGCW!K9D;b)j;%XC^>guSb@Rq&cLFuSc&^<3E3 zf5=JM&;mStC7s762_f5OaZu;dQ7{YaR&8%rA_)!?(kD}B$fF8&bQMnlDs0ZBor7Zm zz~N;qXYS5CysC35e=0}!nTsd$LF~tm;^aI0%rHI8x39%C*0`Jg*PyEO=*{bx29Da< z)z6M!-TdZ_={a^BvezQP_0}i0l^Fz!-IosJ{VmCSHz?X4>2h z7W_T*8TkAi=hRk8oR(!Oy&@jv%ol`$3E?C@y{cMSe~Q;Tc;eiB+x-Rk4Cy4dCo(hq z|H#7(i&Q-7Q{a^rpP0LpDcC4>pocs#7mCySpl6&*7OK}T<)xx!a&ss_EN} z=pUA9)Ze@Yqx|S09BDGE2La1RR}I2N2IpM&9nAqBVcscq$`uCH53CC7MZlL#&yH=t8^+zR=2UI7ga!GSX>S_$ty5 zdf%tK9Rr@bz9`%%{Dz+W%}DR#$^F4tRjV~-#XAk@35?9vGqr{M`8~6AN+S-xDLdwR zizEqc;hse-OJ`zt=eNd6&0(*)k+O<{UUX zEJOjB`5R04wD1WEkk;D~&QLc(K)}5V=yMNdYjy&4+UaqNAm$yO2LerZX-`C_&`&U6 z^Th5+ZdWqkt@z#So`!}8TA9Cheu_aC6d8V;c=Y5W$GFH$-FOQl%g@j9kj^`1&vh_w znYT(H7u?ScB}qG1eye1wg}sl6+iy+R zQ(L>2xA6oBcT9xWw$a9Gc+j3>#sv81p5SEX9-Zn@?Z81Ol-!_sS-+WB&AA>{=W$bw zt@5T)Aoc*l+|`8XM@7?#v}R{UZxa1-n)xujFl{ggt>_DG2G-v|it@PuFVlPJc=ExL zI9tdQDw}Fx^%j4vs@#=hYV<_a${^@A zvlu-nrj-brNi2f`2%Udjw|UzTn;)HUiVr=_UbWObE3I(nYBaqem1dKjfD8G`&8x}! zYf#G-=zO!wWLj)_AO18PlX=F+Im(bVf&KJQV@|P&|nd^0mse;X3ew^v% z(uFEXfIIr8%`DIv0CbB!M2Ml^W&&tSMUH?0kR3Vb@AvQ%Xn$e1QOflT^|$*Cho#^V z)12lvs_e~*T_6X*h;@^Y)%dBpoYej4xukDEEtRcK(Q|y`x^AvnX{C|*&|iNmCTb}^7ReZ@KPeu=)~;x(%%l6MwL^~PUSyYMO>w9s)vT@zw6(HXsi_*ggkQ;Ndw zY%B;326WB=GOxQx1Zq~>9i!_~{Ov~#_3c)625?I!8OR=ndR0A3d^l4&N1n5p&FhSY zu<-+Rv&u6%{K`LH1>JU$oujNCV*9kmnazr+l^jJs(wm>sCQI5!y!sACRu?Dh+@O}8 ztMl_*;9R$oUNTpT%Cl;H4I`$7kHog72Z83rCeM!TuU`hhgrIMhHA9KSNSdubqa-Po z)!G{d5bMoFCkS@=INIUO#NbwnjW?TmMkDA@v~Dlh^-Zv?yPk~|dA@FW$@}d&zRa=# zHc&JPpl~;FMJ$5-S;Up;fL#gYfpbKy+@w*AC7d1U$e$g^gwL8HySLTzlXO#cdt9yI zb&W1*GFj{Vke|2mTi^G**!FePkFw`QttWc+jU#UpneDS{mUNxcza59Z_?3&9@Qv5& z>)vMMo4Jf}`BANH`h;=Levp0lL8MD3jL@TsHqX)n5_)h103zNQx zpOy*b)K`UTt$;3*ow9*mIUhb@rk}HkDcQ*>F>Tw1h1WN0UpPHWiiKCX+&P{N4xqM zkU`ia-&YFrKj1_MLN9~QXjEG9Ak*__zQFHZmNx#JV;&5n3>774J{96=scCpoUuN~WeiKbw`i7AQnVi^D2 z_BFuMMa`qmbVBY#VYU!L&dZvdJ$fJyN6@)bL8T}pd~Be>C*>829`vPn;SDzCQA@F} zi5b~-`$LgyF0X>))1WV|zrS&k^Hy4rEofjDKiZ%{hA%C(xYbQr&v zYWUV#r%u*mJgiX=yvVKxv87M7n@!?={y6$j(sWQ3qwYKWhn36{>w|pun-7}!*436t zGseaw3Miwse4IzQhWAPfYyLI;wY-5v8E>GqHDl6kl-Leld7;4QI*<$R;*@bY)hC?D zBZh2LDUuz%JWQ%tCWA*RDw7=u3t^x+e$upcDPD^i4RBZ!+eW&hw5GJinhxyCxro~A z!Ph=WWNrP%5Vdh+8pn8m0vzJ=X!OBsA+$#|-UK##zxhPynm{6JMg;yw|Qnb3UorC)8oK zH|^)9>5?KxG)2K48cH6>qLJ>%T=3}GhJkS{AoWcYCsiHnywYtQ^@cCqmOSS&9{kj&LqxlcmssFo#iFi5R)u)-ju!?(iQ(EQ0{DhU>TRF#u>qL)xt!-5|4PXnVZ)z3y z0t)==+*VnSD16db7hsd7q6LFcs0Foybxj4#4BLaz#wgNu2)=qwCr>NhznLy&J={#T z%0OT%RHgGqkAWCu_da{Yw$hMV0J_-8HS()Y5^Zx7Gg>+im|LCqHeMXFSM&E6e&uD$vmTz_|P(WA+#wL+N` zM^u^Nu3epJMeKF2T^i2i9xaHkoE0v_`?-Ur{p^ah9H=%M@_6#Y1qUuU?2Un5)B3Y9 z2j=hR>i_^i07*naRBpr0b&Y!YWK>{}N>xqFe56+s{&@%lx^=XBDapPB)OPgGBZTC+ z^yud0F&H80aPR%@>**EGGe-*TCqBu$UNKgdk&{(kR=nIRiCZv#%bfC?mNRQw9MYe& z^8!iRzT^e}66P@p(XTRa4D>d^HXq(*;w4~a5H){cx+Zg*i%lF4#y>h41=gzkKMbd#r0~*5HN1zmgEA z_Hy$TyCI_&J-L!`_$an!uFmKeJ!+Nh6-PfAHL4odY2Ghi=^o`$TR(y?R%Rc?7qD;+ zEa@>D^sciA@`Tk%zSPB!Aobgc>EV2O(N~`j-|l@u|LmJZZ6vqySL+Y*vpsXz(QIw= zZ$$61%Q)uORKQ&247?rRx%hZxA)kA{|Qf!82$1)I52? zq#bOA&L}*yGfLj4JZ}R*tpg+1kIDTAOp{gDA790NMSoZ8#6FdyJdSsCy#9A=vo4;E z&)(o?yxzu&cEn4-+)_`7cxtZHv61PHQaRg{+&W=NHMj zhe=IUVVvs0pUEiCohS7|M~L|3zVf;XOD|NbwHpn+cy$ikf-wCn1elZCOsBEF+_>WiOMVroVM)}nt4x@Q_?EtR3Ra@ z`=dSz>3f%Zc7|1Gy(n|caR6*D)lyv-3$ybPQ zV(ly>^bNBj#*1yML)d;|HUekdyl0v&5yA2IPvJ-n|Kue0f+LJl;4j2a@=Dkdie8MI zCn>bwon{jg@aG`-pgETZC*!78QerUFzyPX25xrQl-+yd!P!B1t)n-dq2cLCyO)D5U zXp?545bz5^LgN?|iQ<3lSp#|=yJNR*Vn7|Cvge(DA0E?R5)F zNeR8vr0NPCDsv>9zre*VC@KiFIikv|j#QzF;d;BPNbn1!F#q@sVQOkL?wjER-Fbd* zqEFR0GIeODl7*puihp_@P2cXAAgG1HJC6@j)N6Y10YwCrh8HRoA;W>dpfw76BcY92 zwl}IVw{32iKu|vlGpwNXHG)z3ory&?fxtBkcL;-Xv=!Zs|cv9 z=wsZ0L4Sa=+={OL-6JQ+=S%*rWyfw!(T4@>7z@}9nlWu}4Cta_P zzd7~Go%c`y;R;8Tw7x_Mdc-FNG0h2YtHWum+Nyb~l!qE62e;7}+--obQLOX6)PMB? zV^})4H(|T-FE%i4yZXHdS;gO06V<}kG?sB4)~jEG?nPmReP~Wh%qK!$V(0$6T7A*d zGOtl|=)IylfPDi(KPP!D_c7P>TJYuN#oS$%$$14U7{!5!MbanAx6SecuS@5z;Xmyk zTwA#pc%ie_Nv_Zy^ZD~Hbd2D?X4-UzoxqB|P2f6u%2XAw(=gj2}0X*34_7~df zO-sIe62ihTU^}nV33`?zH#8L^{sG(GucsCX36xk^Q}w!(1cGdiUL1J?4rZ$5aIQRyKI(e(5ewWI z&L|BE-cIv7v}r@m12Q&kd~$?4)V?maHg?I|I01D=MNzJvo{qWqDdF?6Z0jtJl%EnJCZr^7i+0s-E6n%FPRLy`cJ% z%imbJKmY7p<+);%ljL5`FLeBc>4ny>ZK#X02!0w-^dFUgV86MTEZ>)s}xssSMORPgTXlcBJ~Jyfq`D zDHwNh&Ae17ZEQUeTd)_kWA(hm)<(tLh1{Wyw%_xh=LT=*T9bVEWxe zPJIr5lQ0!4;ep=A2Eq^@ga)FsJk9TbUX%#7I%_!mq&chkM07)fkK>m8jg(Oe6nqGQ zoZ2A4@jz;PJi=&tReX_V$yrmc3Yy8^c{Z-rQ2%M}YD5}l$5UDxvEV^2{7YPHf^TW5 zXSF^Vb6BT~-6Hvz7yX+08a}j3_PQkYb`U^DTL0UN$9-$2aN2H zBg)#p!u93>p_8Q8QB1A2DU`{JpxPG8>d)xGZ#kE0jf|{{&04C2FKYDT^okqPaJ$9G z($>Cl@QTfyE{B{)$|L_eP8ch>C~9vO`5G`Stbq9{NVM4zwT0`5-g+WGkr{Fdf?I%; z-^0(a@Xhk+W+3ewi9M)Sj69zka8OgAO|6xAeDVg8Uatxk-lW2}ki0GL(a;v-{j(VO zgVDu9d;E0Vbc1ffga+)F?`26VlPZd4Oz(9ewU8_d@qoCii)dd$$gE|wX!E=`uFc1~ z5(_?F*>68wO_PUl!WjCk>xzU?^p#9GvdISJ0+!U%cKs6|?`?(?Fli9P>V%hwZHQ<# zVW+d@CEKl2yRYcJ81UojzAgxUeEz4x@`w>R8I=>6rJ-}?rY;*$ zCy4F~r{#t_ZFL5xa>mdL?8${FRkHym@9OcDA-WQoFThMMkEx7Irf@aTr{%w+Pic(K z(Tjt9GA|SzFV2j2BOg~U(b_xN9iK?2a+Kd6C&58ca{9{`_a5v~2@ENIf)hVOS2r|! zm*FSKI79cms>p^2WPgks`q1s~E~s|nh_QNpyv`g!nlN;@htm5fyt%sCkh*>sdE~X< zDd&f!LI71js=t>9U9kU-ZGHOK#P|+}9>>fw$JHvvm*oNyQ7R*BoK_byKQ?-&>{5$^ zpQ5i;v%oy|E3S!A{mDF!mpP*R_2PFtzo+=#iCr5YIgs6$j>^+4OQNN&93u0v(xjore7;B!ElDzQxN{^~CUzd8sJ9YQ;I7%go zTN+L8p7!%PPeqT2e!fG&`fDFBl8{^aqSyX{BlBt=O>xly0rko_02}^f8~-L!##`w@ z9&aEyw=xK$i4flunEBzAo81`YZZNTa@E(dvx}5U8yh3uNv$KQQIqI%4kd8x z?VNst=V-i&A^h}R*qmz}Cy1eQ>JMa5&F3qSDnRY9_)K(>@FMWN4w~w1{pCLQ>s2oG zdFprd>rN*6`8Q&4rE`;J6bckz?s0>Pbbudi#9l8y_TyY0@kWh*DNknL>bUy`K2x= z+&X4eUK*J{8O`gU%{+QK#^7(+``lxAy-yf({2e4uEv_pZ$EIQ{)8-?1f6Ji#l0mjl z?|aRv@p6OXwF27b3Ep1c5K-On#ts%d>_{Z`)m9ZfNTL9og6%U1^pyqhuwMRMKjq`K zdpm8N=sDK!E$yu5DEFxFjhgFKpvh5wJdQG~_?90Ijn~#15=N6Uu4;>a`xY3xIEy~3?5q$_L+{GxffBWr|0FSxF9Z4^V4>Daxe9$#RM6qtbKfgCT;P!YS8q)(# zFV>l4_xu`_^AEtN4fxVF?*(d4>rX^E4#xLVI)gMCj#)+XVujdbmMd$8=o|2-*JK2w z)7PLYYX-gyC4bq@$cwx}f^5t{?0EA>b5S_~y>-Nf*KZ8e0&zT5+Q?JU>o~P*K3H9W zh|BcpM!W?k)b-o~*<`a(O&9|Sl7gl<90>^J4yI!>U^;@vVp!D0vDJ~2O`7owa2Bk- zS~F8B)#@TZNjmKOsnnu?L$B-k6(JK6n)j{Bro_q}8mJ=$Dtb8R z4x7Y68#^{0tv9^lK0It2`5=4P;kakwSIl`Fi&?bGwM2$Jqg}B%!}u=rZuFLJA#RQR ziqaBs&)m;*uKIf{FVW-r+VFC%ZPELC&8!aelDFiim6l%@iCD8~ge0eWrt9bplQ`ul zase?ed{uZKC#FOeS%ug(PHb#JE(*XV_n9igi#%pW_4=#@J+pV(0MC&+U3llW6v?PIk-EYRcp0Jolrg9*Xs9)BegUDxK8p zl`*~|OCP@5G0RE#nFZ&t&oQcq4+|;c`JnYxiyN}PWycY_-aJtG%}0)vew(T*(%A{G ztr_C%#WiXcj^+e#*k9d{MET#Z3_DniothW@Lz8<8Ka&Uo^07jFzav}F%;JhbK8Q@&GsmZQ-} zt&#p_?_52e12rklMyr+ihY2do>VteJ0lCSci(aMR16wKsxyhy{GvR4%RLxPCawF$kP)=)P zmyXwh0Xp`2Wm4gI-FEHV33cLCsId_SePn~8!*?tAD@t=&y11yY+;Pq2sg|=pQGo=d zW;Fx8tpzfU6C8C`c(|nOualsHhwt_#B(14Ne1X1DdVLB311simwktLl$m%xq{(>_n zTfu}ceqY%*fz4%3of@@gW9B7KWW4;U4NvnNL@LG#A41&OX5?Ob7~jqzFH3!hMEd4R zMijknXCm#|DM742kvr^O1ri(^G#xTov4ellW$x8n5=9|3VPobg6_V)#k2RL|@} z#hXEqAt6_a&FgR5HSm)xZPBIzPZrY-OHYkS!a{_l!*3YD@r-Zuz_A#szUQ%BjN_2_ zVF2y*<;9`c;qzD=;R(G_OZxP_*}T*$KsB5ilQHbict)GGtd@p?hl%8lKdPL}DWI;9 zQC~Y5Z+TablvUib#K;XM9v<-P*HV>I^!B^-Ug|?_@e{7%O)Pwe4sQ^l?|1X$xBD&iI-893z^fwS%^TDKcGMbn z+3;#D?Z%fP2fdY7Jr8pYn6|V?OCFG6EnBZ=Q!kuPa~XzI!g4xeld>b{gd$@&ccTE9 zz+Mi+Fa!I4_P#_-l9Wess(ZeD|M%VPu9Zm`2#`2DA~Li78L#qm&|x|d_!W`a=*Vw4 zNG0)2(#*F9ti_$(AvMqxb3dC5W-B-Nps*yI9HU&E(1rx)`Z(BA7=55SdL?}@hfi&r z`tFgzU<6&o%I6EL*S*N*1vLalbI2`N8We~v?-a2kUIY zoAH|c3ayP>I=(@aZKGGS++M zvU$0aWys{A-!O=UW5a8F(598W7@Oz>17CN(v{~n!YR#(66PtJT`$F_3l8e17LKL0s zS*8sqibFCXdfqO5;StbjoD}lM;*0v{+g@gBuRIuqDGP9Jq_N+QR)?+6RvT+l{PAqO zyhdxo7wqOAJ*(%qLQt;!ARqco3q9Mo@_ISYd>@jOD{6Wmt)A+kv#g(uvuV8}i5nC5 z>~p6c*IFU0$s#}alk+mu=1jJ)kRb~h0A=&ryP z;WI~e$a2nzYoo=mhiI}tpapk-n#*Tn^(=X9_~PY&sQ%>Mbd2kHeeQfuewCKLNG0%_ zj$b`)K3lYnykKXaM?ANF_jZ%Y6Z0z>ja3Y;WXAYz#`;Ee2ijRC=?nN#uE~!~u=dD<>`I<;pE~j(x;@vj&pFaZ9POo&y;zDq;P7t0G#`>w z^#?D7%3i;sg-Kd=^*tJZg;R(LTX#ccr0vi3T+SWQ-?q6$p9NrVZFANk<*6R^Z;xXQ z`#G0q=E8~^;OO;w-d4}?J?P>R4c=@#LVcC3lWt_PCn)&RiFF+Z+7PT2$tg$h1ar*q zsD9edE_gHjYWJ$3oWE5s3$R)UU5Lll>-4zQT!{7>kygD=o%OEM+gjfo7_!Ihwb`Qw z?2pGCf0Vbr*YfSYkYn9v)Rw5$dWQ54tu`m5Zsi+ku}_j2WsGZ3FRl4=No>tg&z_;& zK1Ye;1$OU8c2!|7nVK)nzaE({qx?NXFHw4Ktql2vxUcP%_G`R0zOUhYO54^fj6}A- z)ACp+Gd9MG`&?JE{QD^@A9LRR%cQJ!U|_DZKSnUym?VqtYF#G^WbAQ2DWg3Vn7)C8 zF~I!eFQCK9ge!ErN^ckyRh(=yyYbm-NTk>i`W2&R)gJy9lEu1{tST3ccVNB)qqyt_ zJFk&AytJf5Ts^GV!OE)Ry&sF%a!hp}U8u`TV0l)qeqOO=;X*OE*T?8}gw(~iFxtB5 z;8sQ9#Ih!8@U{+DSQ&4mzssh_U6hp;$v7oeN*J&jfU8Ghho5T6j} z1CJuOx)O$%{GRsJrXmnSJT&Z9!_`>ixX!;^2v#fiblx?Ms@gRePe+u_NJoE_x>5h8 z&#}MJfh_f=BY4=|7}W>+P%K-xK0=2Am&a)ABiaayu|z51TRQl)Z`?EnbfnR!#zi0V zt^MjZqeBu{-?ibIR(Ej#e(3MKXCN+!-(^9-uWaMXB#cKiChv>|K52d=&ushSsV&RD zt!ots%JSe#@sI>;E@mU}r$n0aDAOMyZ?$eY?zx}toj7|U13yb{QkNS)&5?+V>k-$1 z6gFb0sS(Kp_j4EL3dF1f6QL_@%u0=}1h=yT`KklNASsiK>Wr4544>&Y`hJu1xL{+? zFQ7}jUQOCwK9=Yes=tV3iYFM4qEPjExS?lp*x2+eGX)fHgLwk|WV0M$R3_JpdQPV; z6VywGLD);^t)3?g?qPjhuvMC4s&&S<v}v!4pJuMsc+T6NJMC3*6bSs<2jL1clzxR|0{uWWfT zPpqWk>t}s&B%d~nFg%`qh@&GU9hoyacM^6+)+pfan7m9Op(F0qcqeKzxy*gm+bnQN z5j?|^(ZeKrG0wGhpGd5y?Hf(-!S6GU*PXc|rR8U@H;xN0#fYhO&5j(c&YvU-I?%?R z>oOxPeJza|@(d@hO)2N^f`14@uaD9$qAUW{cOOy{#u8IJ-i#U5TkBo`6-Kn4&YC71$wrv8sq#JyGUN!do);26MEi4~d4->ye-ikU4y z{9bD}Zd;!k?Om;@rp5*B4Thf9?9;eU^lp68I_QewEGb+U&!j&swU_{bY2@%Ek6!gb zioCi_*1*kIN-}`!ZN8y*Q%i3!_oWb74IG{M`h|7xHwNogXO9|7Y`>l4)V`vKoVl)< z4L}vrPY>cH3HJAFTbmbVmRKiu>OoN9!YXoleOZ0O4Pl@R63MkqLRJ27b6K< zUZCt3>nA?mr412zEB*KxRvh)69WQ+|@2Q6x=1$t`ILUHscw8xuJV}tx5!n%qJb#Sl zUqtgdwJrYomq3x8KN09lCh>OiO$gCNeYNwr@uWKNO2|Bf@7Q%N6sPSIol2=*!AiDQ zp*JK&9#sK_R7+O{GgnM~exqJkRubxG{v1Y#qL&!sGZkV$z2{HKonBLoIkyc4#cdB}tn19SAxg(WmYo zxi%=3uG$<}YFZuG{eX6$yi;57Yu1t+rK&|9_0ZKsQNT;-TS%xjoj%S+SE*uUbuj(N zw^0i@z>dE!Gs^43?onavi>XnspBYUdIxly1C|F&;sdlZ|USXHCc|J&m+%P7BWA({y zjHHEMk?OZvQ=S;KU%BD+aD#cr0!O@Y0_K}!SR4At%*jL4gq@1;OHU5(c+k}uoH}jv z^&AO5duIj>`c}{I10P+%)G=MJ(EMgn05Fr5KF#8la#>qdFKPJe2w(Gw_+zrwO|RZY zO6Z7-u|<=-SAA0tUSXZZ8r;kS9KPWS@H@9x#$#7rJvK*Yt0hy(Ua1+7piPn@Gbl7C6?BfX0~)d$G+KqJ0x-<~^a{qjhIz zGZ71&6k-xUKmMoQ%|@Q#ME1BE*vqTQ62?|H%Atd^O_PKOdRix3OYB5tbGeB^xzklb z`Qa^iI@*Xgk9ox#kyv560s(mxIOsFl15qcE`|pJQz@|T!J#zmu4F?DoiZR_3}`j0z;k`n|QE|)4KN^0+4}L_6Z{||7xsaX4qi;WP|5+ z=~HWBP>Yd3wG7obYQhG9m%BP*FQMq~+b^~3ZG(g z3fnHHyGWhDE6sMHevUHhz%%UK^YO^tfELB=uT=w;b61^Y^V;(5S9qlqL!CXW;U?~o z=4Oon@-y2}8W`%qm4}lVn@wlrw7!=y4}e`yYfUg|L4WNz{oP?AUzl@iG&^6^yhUCK zfX1La%axw%b`FeKI)LUB^F7YRrh+`k#zEI_s}`DZx}RB$thH(fKGS$Xu=BQq8~Dlz zX-;Qs%1esTC+o|KI5NzD{A7F(2!*PZHMfe@2IRTsCk{ZO%Cmuo&G_VWw8e3V=Y?U{ z7{Hw4K{|VV^{_M3_%qK7(w?VvZBcLMA*tVA_%IGC1Gu)K51;h9tC7hrl2R$^H)6Wm z{Ph4d$G-V;f*a=|aM?w7;%kIpdYWIlR>X4Y$X2U)jswSx$55*kKpzXn;IHBV{Hk(b z2pxNwuds*tO#s?Q9|+h1p<5Fx-OAB^eW?T`0xIX`hr?8yrdxe$Bxzy(IUf_d8lySBS*)qk%JZojx1`jKOT4dChv1=W7PBfnAl7- zY}Kp9Avz#CH$5&GhKrP( zyQeWcRW;aZ+!#S)$JC5-WrlbphR?flx1to=2F-(wN9kZ zBUpbgz`UG;nVYX*L^+%+z9jsffa62^iZGXt~YFIBL1B#!G_S4|qI!Z5UWv+WG>E=;4Jz#S=z zI1hHEy5hmYSJeA?B%hIda&6;1S?Sj^`RPfJz#N!t05UrDarA$G!_&uhcJo~2wgOdB z8+;)671gs!e(zP%)0aqgd3BQ01m%bfU!x0yGvyO0R9PQ|^`x45vVwIa*Ky6>Xkqa4 zOg;16z2Fj6ABb>f416g%)&h^G9^J|tZknZ2vnqEpwGc6^@`64x6nUi?bA}?B2uo=q zd?gS6WKQ`yM}D8>xc5qNqz2%R`h>u^Q*>|^YtelK1nZBtF<_ivem7t22Cui3^=yXU z{CrpRvqwyQ_ji$s*j26wlpHancoB5E^OhN|=(z~E(T4T7j8Vh}&1_2p7*czXuP1c~ zOdB*%?^ur}=0GsnM$8;-5`C)~*xRD!Xp{8QW3vfwkzX8p&zlTTb-hBPY*THBa$Vap z87gm%icN>)TOj`x?g9cCb+h+;1K-$D!Ub|2;Vvy(TS zl3%ks#$iYG%}LQfay7y3*aN9IQ65zck1;ghUa9t0^DB;X&K>=$pi^VkF_DN~AH0OH zSiSP`2JqYdbcfP9ljtzpOC zSsEowQfjF3V+mY|v`@+tzdu$@)EP`a+4R~!R@9U~#dVO`_&{XEBgBaeWd#tRl8@MN zUHhu=YYmR`ZSpa0@%KVk{ve(f6KrRjv1)Z>V&`;c3u8gcNb`DwB!$qX=B#DIW_;Ly zR&@RD5r{mZ(GvJxhJE{0c07MOZ4toIJaTNNQ@hE70$YYBEf8e$J{qO{B+6eB zQ%vLmZVxrROwYqGmzXazKkL*@dNh===0f)Z)KQOl2}J*dDY&{8VQAy=iOz`ev|pby zh2vFFcMlg=#-nkp^1{@M`$~A)kPETPb1>q?A6)!nHk~NX9eziVy@r8bjUri33vCx$ z;{(EcX<&AlY@^wz`RKkDONQHg90R4lZ>e_)&|Av9c}_pcV2n=9%s=oc(;*DR>VztIb2B>__m*#m}m1rRv0s&kAHzNwd*7e;y36d?B`;9y70Pj>u5i`Cv+ z^S#u2FH~=!5zpbZVyD0CXt6WurKDp*-X5QZb7i?!8Vn-W=mAh(92qD3X}Pjr3lmz+ z6knj5O#rxOCokY#sETP=w_ldB(Q9tTf|4#itF9MKvE-YnHcqQ~{APoDxNIQx*O^3# z3~KFPtA7|n>vYQ=C|v7n4CZTljF+KAF*VueV>3oBo^+;Kr>8gD=Pk4Km;4IEh8k=ITqU#-p50r-gPfA}%@3!BwFHdLlu5o;U2 z>N$JNZb}2J7|Q6WmkS0Rn?+{3kQwF2c>)=GafH^C6eH@j+|`ZYXtv<+5c^8*`dEg+ zLfhC`A+2g`#am%|-d&8*xOlXEdtOU`iTylDUwb~zV;b{6_BEy?EPL3QV;d)W4P>0z z)()%Bu&p8(eOCe5!#M|S9^pDRs0D$F!nGIs_Ns_b97FhFzt&WAML$5LN_V6_>_s*^ z;h}?wu{yfQ2Z>ep)>?%14h)C;ERghNO%ad^?xvJ1N zAgA@vlV9q=m)l(p+EmbHx460_YFzR|OB!?~G;m(|qvhshFJ?Wd@Cz6zbulZ)o ztgczbdQ%{xkek?JHL;ej_>@zjBf+Xs8BF(C69fN)sK_;Y5qbh^BV~C)5%B^TF4K%`Z5~gWmA5X53Knje$?&3^kj=Jl7TtJZz_3RoFDAA zjgq&=yAg!#aYsF2_kQiXz>=cNiX826$xh>d??KfgdRC4}sCtse1J+FdKQ) z2bde&LE~fHn+xe1+1X(Wm^Hi$KN*%8wg?`}&j^Q<-onSvU5Qsw-XdQ(|07-p9lT88 z7F%uSbyt)Kk%HQL{ih={YBnFT8w9uamr&X<2a;~z@Ou#XEjraGuuLj)M?E+5yVqPPG3Bj9}ww--#^!#~@cVA84UP$p0 zb>_o55I7!9GxF<`w7$O9m3iVNWL9!JK4V>BQ0C-Fdy41B^FUeWz(QwLOMu_;A%l$X zV%_n9lWqO@rc%N{psdGCuF=<(A~ETFL3}sfx|14SO+>Yl>tkkM{49$*T|dr{{R>It zNTaR&-kM>y(E-=aVZEI11u*SVix<>(JRT-yPL-0LG;ayMURZZAhVv;3#wqFg?)v|! z&F+%wI7rFPI?)yBY>Y83=a?1z&yx$jn+sd8(_i@FPP5c#TsUH9m}6y`VM)f6|4{x@Lj&bgLdU zfO0KFy9lL8Rj-@;VXNk|xV!hdSv@pyB$hq68kN;Q`JpfGHm-O!#?Fr)ar3!p+G?+S zsu>jS)c+Ajz3CL+e8AqZGN@qdO;#%CmEv}^-b5#WT2~GRZWLGSrHb@1j{c>Q6Mthf zOU$_mo$KN}Z&Z;--34M-6Nnjq7fHYIqc3oz^THUY*8mOnFjBGkmlQh1Rloe8@0bVw z;%b;eU@Tr7mE}lLY%K~c7b`r_8vE}&Hte(1?)(Lx$yocTfAdOm=W}8jO&={T*wGyF z7Fc7@x&8K$$4T2Tps}SA!a)3UL@SM_yj?yFHybax#PqCi@HP8S-FvKOWB$)J(=cGN znJF0uA7dug(dDs==(LA|jmZ>Q-g{v3nzXg>tA4_9$`nK`ItLIJyvKZ&<#t&8?Fa19 z`cVCHUFA1hHFl;g%Di}fyETr<5U8H+BC)o<9rZk(0DLN zJ)`t}`#iOMAjJ6dPkJ$P8U->eghoY+wS_$6l-4$@;e4zO6W`{8jOlj(1uD1QY&~zO zMVP=oZV_#i8T!D}5^3rKGs(5r~a(uT3t{|tg7KSpOm^k_IUl;J)-%@IRakB`0%~? z-{V8N@w_hRec$(1JTKQ*VbA$YZ;tOXb}msRVZYClb_u=~$Mx?s(`UKdzi9F+;tmr< zCp#}xhv$!3q>EC`RKAG5i}#D%$jtoQ#AP18NWUGAwLGu0GN)eQL)Xuo&c?gO4HuTX z?c}0Bf78hhNcg969Te7sj_}hu$%W!K`Ta`Kon7?K`HwGMf5|r?hF^2x22!);`aLQb za-+->LC<{DtES#Hc}6d)fsyg^`uhBH<5mr)eXsY&)d1y z+V_enfaA4rrwN1d#7*TBbOGBaJUp z1Mv+hw*9{K#LU<6-*`jzehlM$b#{U$x8R3oWs!aIklFB1BV~>Wf!E_L^8c1*=NZG) zBRF`_j8{mfo4x=qw!(N0fuP&3nuDUG+1El`Ev7S$nffTKoB1HM zmrp!?`Wt6Lklw!@D^v)Gt8542-%9G^{Z?0;@o)7?C$@9uv>BILqJ0?QDdwr1_vX+A zukvTNpCrj5zS6{^@k4TZvu^&`V{6`b=hRP(!4lIkd2_Q$YJWq$l6=6E8a%%&S>yW) ziM8Y#xDV#eiGMqp9Y2h0`9>jMGPF!et+4DrQTAJAQHcqcVQUu+-@~6HTug* z)MfuD*EvviU#PAKuHyd82C}MdZ+u5qyoi7K3k;6VDAz|VQVs-7*X>2Wu!lLK>ly=r zQ?=bZ)K;P6;GHiB&FiMtXqT=1+?AU&@%@F0HILwHu;ZH`<8E@op!{V_N8-$VIo59{ zNguId^`LniA*MHt^3ZeoR?@?hk-i)(c=~OpVh6@xlYaaomhH10LWLvT(1t$xbe24K zRIDO|CD21SG1r8~Zrh{m5X@=$DdtYQab4i(`mge+=Jb_#>^ET`m;D+u!sev>Iyi;H!Mj9sRSU9T$J2WXs0kNs(NQaEuSSyayHMe|`-pK$^eW=cLCgzS_yV&||db7xyf|afh zm}`(fLd2%qbOpVJ7cTUA-_YwRTac9i-N$*%$&pObnEU=)s?Z!YsOgWG&)!N9-@vDK zTT6R=yg)j!OdJ&!1)$hftzG3J(YOZ3W|`>i7^nRN7p~sEK*HZbnyaSap0r>aFM9ZQ zl{!z=F=WJcWapP$>)=~g$`YqB2IDx;E@C%)Qs(1s-3#&6NgJum_G~GqAomudHd4VR z*F=ow`w<2zZXT)FcjS|JwLyX$IUbHQG$TI;k^ec}mdr1W+3HqI+G2fd`)cf>@~D<< zexQ4bS>e#Q^t+n75jJnrNtz6>5tT|a9Jr%ZDZZ1H;|)#N|iIw`s*E?``K$sdZz z=NB&4=5n@6ktjQ$$u3U-AJ>a|BR0!ZM71;+N0o{Ty(98HOgLGF=OhCT5q$X0UH-dDtlwqmZlDMq>V~W z8fzhi0n}P7!H&o`KsDM3sL?_(*fCpV?<_-ZCqtu>^7J`z!mqXCEgREByEJ?$(H!uIhwPm>kfG0OjVJV!6f@d9MPs zC};ZMlYkIfZg%GSFa7pE+Vmh(0^iH9-)Q+bHJJ?k$=w_5^)|VVo!E0Zg?N0==Z1rR3wBS$;OUAg! zJBf7@CY-x#VRGTqCI=Mt$71L3nU~i*XbbolhvcQErXY+W1hzDm4=a&~<4vs_h}YJ0 zl&v-PDhT#RpE`xoQ7HLw^8yK~c()514@Re0ZU;Pt;Ldx2zoeG=EBbH;f!OB6H;k;M z@ny_M^ft05^Z1d8sld)q@T&-4-^TSDh%!1z?1wtl>OXdH$B(rhmDe*< zu>IvfrEb&O-@e<$_hy?kZ>@Tu+o-iHone78hCxx|>iTJ!giFj}e^o(bZ zJ(82F#8$_5h|k6fznvHtpmP%N>~`KD2T-y1!V4sgrI@tIG#l%N(>sCz8wQQ};Zem4 zzJ`W&vSXehd)Q|$6zT8>4UFP4PX~WTiLOt-J0d%?4UVtnYmNXErQ(NT_cG%L+recn zaQyscR=TnCMtwd+RO57M&{~2#{>FnG7@b!`+`IMEo4jqqC(UDLbd93E(qTFBTSXTT z#eji84?E@)v1&pfve;@47cwbJ9rgz3i5=}llD|ddizbKYUKG_AOP=j+G5H(eEmGPt zVRZ#ru!a$3aPSSNXag11$8S@ixb((065i0X1_Y2tFHV|2dj4J82RCXWB0E>WR=iOL zqARR&R!|)Ls#Cx9;6OpmVN2(+v2AEX0eOcWMd{(WRut z^ZVcbmpJRkB@y``*~UhER5!){gS@I}BBvRMc&fw&-vuP}zvTME{18QzGrrmJU}&S# zIx+22N-rl)f>02{QULui_8W(_+$j4NeBz68MJ^|Iy@zmd&PXREe<2kM`Yn3O;sKdx>lL5m zme;*Va}}XyAV`8J1G1XZpA_=PXf7$9JRSf5KmbWZK~#G_0P}kBlD>_2u(!>;V104C z8=oyx%J_z9=L%}{$IfVFSzVwuD#l1bFkNImFjy>c3`=MV}N4OVB0*;&(QTUqX+1ZG@+E*LvCt*l85wNg^M2SRGngmR(Pa!9Qh5TEFv!(wTWpT z(*g?CwEbThf}VZRFVER%4{IOlt&4dS+V=ZM%@4s8T+6#qcy7{h!1J$jA4OTbw13FN zxQ$~o^25Hu^nO3W0XWVfvs}y{Eka_lPRa$xD zQB#3>Ijxyfx!gy~em@4e^gB3l0ohpH`GL=(p~mJq^M0Z}(BH|K&h+^<4;8fwcEs|u zIBGBPP3=!QW{Y$f*p#+-vUa*US364SMArcp2r?%(Q+b75?f4(X76w9KRUaLtROX50bBxMHtrrSeo}kbc=i-e=v~_P_`oPD4?y8 zK>(LV*mB#2KRn`79o3wF$Z26+w>p-Kk<^Rp(@Ea!$1y~9ET*P8w}2Jn&9WyHc=7tB z#fhc&$k110%CZ&b3~`m~^Ug4&bulB5<3cA!b3!jSW&GsH{qf((fkV!zS~ay%_`WZs zq5HDe5y0&Q6z-dmd+rhDt2AP3+QgpTtA8XJPeAz+X@5M=!*KS&6^Q%~%DbMY>by9+ zS}Csd@m{GCp@%pRQ6%#<&nC#}sqn;aH{Fir5ih=SA4{kLthq-X%F8|IQs1N&Nm7=@ zTM+X@4Wc%3*&o5d1BajKYws6k*51#R1g=9?{CGH`$3*LOUTtg&9_uCKyg#ju=T+qD zLm_b>LPa6lUTuph_`(ejY_;4;cyg?<`{-_gUeUd^70A0JWS%G;Kb&ljG-{flQC%%A zF?z&L_xd?!)M-hbbYr3WhF;y$qMx>%(xNny+n^XGlAdPMy!z(!WRc=Jfl+lbA_=i46Dj{{uF z$P<&4RT^1t9rs6Q$#$Isxl8@9Y(i_bgVkliS@qUB#DJxg$HbHJ^9dowS4M z=&Mc~A3SMWEYtXDtA}x7V9d;BXBEk;=YTg&;;t}OJcCCGH(xg0taat=H&d3=PemJLLQ(*;*L4)3H01Yv_k99fmu<50U?Dv9C%=IS2V< zWi!ajd`T29&=@M#ghue zHJyH%dnM<1PxIp-T=VY22#UzfX?~ocw7H9C#h-bc(hCn47tzrAwc#U>=-1a-UKV!C z&Eo9yoEpfS$WfC~vyUS&^tIQ^g=%;npKZGwx6ATX^pu~Ev(~M%S8*|`OF zCZf5nKuwK0nO>8;Zy`Q=_!f=yjHhD{Q75i{3r9#OZ}kz!A#vvW9Kk3DixF)_Hy(Z- zZgfMAxb{SswT5qYT<-$#k0iwOq!uK8-~qSprGd27y)ug+4ny9AbiM(&RpPncTO}o^ z5}?K+@i50cVIyqKHxnU!bsfi|zIO>I$XDC^9MKR^XTI1F^tGl&PS6c z{Sma&u@g(~d3j(TVt^MiN?jUuGiNWAx*AfZ$#JfOG*%CF8Xb0RHy$GJ2tdIa5cxOi zn(XwGy47gY(*?#U$jorP*$>C8O?gC6+pRIovBq#MZ_AOp=7~(FaMZC+(IeBA6n%Ih zrt~PJU-HRJ9~Gy!(uNyiLui%f^^}Sbgh*ShjSn=)1N{z9q&z^4M!s7cGpfYXMqFFx zXlwoZIxxI(&W--;_@jK^M=sx;Ppt!tbtzfe;B})8YvJ|Yl)4*T!0*v(gk6I==CQD_W{L;i=Av*G)6ZL*wpRceW4{ zYVCY$vZ%J`qb2LLaIQDYtKq&DI|r!wh`4%8tEQe7MNcdqn+(cn+>F-SMZrX}qwc;B zgCq7{>$ya}KH3Vi@+IO$G_xTBi>8Uu6RuuNDdvR_ zFm>Q}P}aSZ-`2Z~^}x>>Yi%4Ty(04d5SHHT*SDfR#V?Ldw56$mS@d7R7$7gZJpb^z z;Y=M4f7t2WiPmc5uu=}iPJ+jU5te+v|04_YxPuSc>s!IVO*uZ!etuYfEZ zAZO^RALN}n0qeCm34DN()l(NI6OaYCv6I_40X&fr2jHWKLK^wRk-IeCvxyCTD8i$h zt;Tg2Hepz=fu+gozAOjljw$lF_**5LZN>w5o~-TfBMD)w6BN;-kAA+-`L2%N2kU}; z0^0IP?Vi&2kXELa^4ntvfr51!zU|1?Jhiq2DX4E>*(Pt#38>c3`g42%f8ul<@L}u* zU0m_yn~hP0ngk^u%VC`Jm19ldn{2}{_SuFV-Q6rm zyeuDhi(l{2yt1+I_0Uj+>KUTccblZ)aa%kg!hqJ(hYv^=_#R!_cw!JO{m7GhgL5Q;7pjV5m{Y_<|;WRaN^iMlmQZ^BU{j zE{u8Y=V!BqhnyJ?Quds8pWBAW7Ib30ZZ!}CU7zZ~5q=_HII7R)Tp)QtQZV|ds0YfF zKM?&E5qvEA)W=!Qzd*uTIM&ixNHgx4-l{w*thL*S!r8uJ9nEIsbPxdW~dw;!cnpgv-Ej!TxbiD7GloLWy z3zPItZuNVLComy!J%-;;eFv@<0e+MnIkJ2dkL3X0kkG%6RuP~sHaLz4fd#&k3eHX=H=tz`4+wF3ft?V00{C1mN&gEI6Z&;k! z#*uC3P~KE{^ASzI;{ovbDCH(bPX7thk&8c4+a3wc+>D}ubj+mmIvL;D$?G?;M1eUv zxr5=01aGHntJ{I^B7{1@K65*Su!C517XYp=q2NGd{bV%+U-V^3(PMR^t9}M0lVKHz z>2NDQ0Tcq_ule(iW(qs{fWcf%YLFXuSyKL$oiCcW{MxS(l=+Ks5{J1@m?J^)HRB`a z3;N|>3W$;wde?=9iRzOA3t848ICn!63>2mR24$g`GrIyZb^Mq5;SHYSnu4b2Q@ zb`1$SURW&>;(u#uA9)h4Se!C z#y54^xpKb2F+Zc!Tsh0@qXGmwv#lI)mOalQhoeWgF^Et6!2U~ph z;12g^HjB?%FqRvwJH{{`T@a`au#pFfDO(d$sI_fNgyk9)qKqQm+UeM-g}f#d=;4pt zrUCBwJG0O9yNqs3K=ysP;W`x^H;z;`MpQ=?u9Z;mH)uHQwcM&kYs~9jTP}$BXaO-PX_59l0It(kcSR7a!khAl=Er1pPRzRu0 zEMBVVi^_%E%$nms-Ldvg*1IV-&C!fI+diSpIFr2)W*j4o0R%ms5}Y=8#y45VD$R`E zBt3qk`qu1+=YBz3Tx@F+>}9hiiY1c;P9zVyZQ!azokQf@=1Y-XL zOzr3kHgSj-FDv7xlZP=!Sm3Srkq&6F9vsg!JRQq#EC{NehyylAs6$+csf>pV+Kh|G zK*W)N-i-3^2xzSi1#9>c4>@HRY?Z9ODgGa>Vz;_ z#+ww#fLL#ghEI&A6+p$g^;R25en zO$S}P2#B_A33nQ0p6gIlpN-Q{%1hOAbB5R!k6S6|&$^T@I0h9jqN8^k?QNE>wD=Vr! z*v2QvI0jWXXpDG)$dZKo;6wh19h%_}d-VUTHK~S## zS(uf6+R!to2m|NX=qb3$)iK04mVE_)k=9+@u~CvsOsobo2N3rWf>fpnC@KdeR_0SbCM+Wk0*OkOOJpzs9 zOvkWE?|ExfT-rb$2&0E<&6zum+3LCp>N|chq2KHjCk=nLOG-Xv`*EW@j~e?Xc;u*z z7}buCoFX>=U})`62psvR1069!gd^gv7SyCi+I$0F*Bvik+VGn924v$`Lcd&u1nZ8> z5sw{n({T}x1z1?|c?e9WyRp*PmYG@iiSLFA|G4&#t9i5gjjiz|)94B=CZ2~sqP^aK zI<%4HT0FXXwK$ih!xe>qPWUuWr*brLbF489N-V;Ge9%RJed+R{4U`#+OGAeV{;tM4 zg%>*XWroPSn z_3$I!qA~2IG)tu;8dmla^4Z+VeWd4s3uOJgBlFgIhIIow3a9KHU&s<<-L<-&4*UST z?1~L}S%CcFGncq+w!L5HCJ4DmD$#T-o+DAeU6|!1Q<$0#VeDkJ@fEoleTn+!-+g`N z`Mu9k<`-9zh@a7dd}AQPEs#~YpE5R~(|aOL8vewA7e-mAd$dc5EY}`pBeU=|)zlM> zvrz;oKd$SfI}NOCx>wpHBx}oNqHNe$BrAMv&`x3bq1)N>9uua+6{7z(d1SuIZySN{ zTb;?Pt;Q%|4?*`hPrMs#wZ5UDZpPYaGM{Vh#(kL$aeehni192j7NI@Mvz}1}720es zjC>^vE+H91Li7yxEZ8@AzcS1mN*-5YgBNzjzEBwSeHU}m=B1}*Z5!|Cw>u0e&j1|V zVz*zPC*%r{UyoE}$UY7qin%hNIj^d{7aOnPA?G(fnf#5*@b5JrXKQ(eXW2)TCkAe6 z?2%KiDLoqlt=MAtNm826yk5bz#cS6W4RhUU{??)K3agW!mt#8wAu~V13-v_xao6dV zqg*ZIKo=iDIatL)eNW_gcv{xJtDTnj4A1C$xiIA?jtlgY9L><72kWrDko%H%`}EgH zLOUU`syu9b1oWXVJ2m+FIe)|Y#h8t6^1PebgZGT?byv7v?wwe`#Xb3_P6+QBo_eFj zheTK@^?bT8_e=a+>wRaS?W?jlCzVm{!!=R*y|!=&05cMpy_}`8E<$%K+hhl zIy~0||D?v8%3;%dQ`gbteyIIcF$B5V3)^mqc9sG3Wb5^imvmSI_#@epC2Uf z5!ebzqI-J{*Wvhhtuz{2dFC8`TFcl~l#L+~Dob8Nl-zoh#>nW9FqHtTscS2N9;Dve zh2P$H-#)UWgBRrl@s{0vE2+*G2ac6df32dNMCi|WbmGU&9z!1J;&<ov zf|#zhE-dJd`rZopGRB_V85|j+qcuL#JEb4i349&XGJ0I{?lpaTO6#b9)i2JZK9SLR zP%PML5phhwW_ILn(=mKnfu8cR+H-WT13jzPh720FWi4X?aZ3$#aI7|*-Hu-cJayHE zf94}py;y7M(zJYgw(%e4CfN20GdD2f!5>jNWqKtqxeZjHi zgjC28*l6A#-!{b0{X80n=e~fsU}4Ps z9;sR_6w?qGKEsiKwL-ank)W_M-Z#Pz%X(Ir$j(+bL%Xp=K5&3Ync=7U$V}% zITUDMD7%eg+Zd>b6MvAeZqqs>Ucr#A=Cu>-4U8}nAN&bKMwE@L{`yQ zjoyRs@p6oPj~C-KYIi-`$jg=vJtQJ`2AbvHk3xYSj^XBT}CzP-Q>Qqf88 z_?>XxN$2;@&ALeB*db?!>y_UAaR0`*cVyLm6J~d#6%H;g=0ZmEF1wN1r~v?BJRMUy z(8WNaJMQ>Rw3Mazo$4&|Zn2bgXCwFC8bhMtJN8A=)u)AHEfLRK1s+~R`w0AsH_0=k z(Zu8a8sB*?frgh!5OHG1jy%xmP&a6nt-pjV&#>Dl+akHmBD##=Rl zBx!~NI_-|nLr{5bR2GT^_)k8T8rkJ=PJ!ic%HY!wrB7ThRgL*^7;vum?WmjPwL*ZGW8iNWx4G6-?W3Hz9wj4P@_4kcH(2sSDa3MW zA)iL3qf?xCLJ+q8s=oP2RwR8*L#;inwfOPsR7L`#Lf3Q@PO<%Lk~rFHiD3+G+gWPyGxYEAD6wfU{xO8H-!xh)o5*#`@r#ABkpXT@>lsRzO5apTtynpp2boj`UVFsJND8;Z;VSE!=j=71w3Vp z^a1kAyBmM}g6|i-m7l}-tVEA^T!{5UAejb@X7Q~4j>cjg()jU0k@(HNT4GKbS=Rz| zXAKiVy+(igPj!?RXo@kVE?iY~?@xg-KWBf&dDHh>9?_ylUPjxQzZU9ee(FLdYi@Hf zw3DBk+TSax5G6of>M31lm0v7)K2+@L-)`H?9yGjf{=qEhBcfmgv@oDg6J;zJcVwzg zLl(m*K=~t&mXa_(|P%Zf~y_29m%<4RG(w! zlxR*^n;G4hqm^0O+ZwTbo+lolWXA!&qHnY`$v-48{$71=Z5%0bLoGaNb*cs~y zrHgMK&?k@!ozB`qE@q|LAM!i3moO5t*3=Y{4E$5Kqic%^|KkJ~?Y4-W>?6N+`Vl|Q z?s^IlhezkEzh`u0EGNDjwr{@evBSH;s?InU$6qmDWlkCn=R`b`xh`H5*Y?-g#g4_) z$g5A&P>j7dQyzMD?9hRXifpdtSVO2awqt{P>J&$$68K$7r2!o75ky9dr+F-`vNS9m zG}o7T6z=h|wV+AOdV8Iw%@%cdBt1GZ7H?UvhlH@z=Y2;69MWJ##>*wow<8tx0cvmx z$8j45avZB@pdy$Nmi?nTrSN~kvF7t8OFnR%DzR4}&-}7BUM$iBL}Gs*2_@u;&wB%T z2wsJKCG4#&+uM0pwAZz{^Ue4twsh)=I5c|H*7Ldc!L5Dtl5c8<=dk8yZ-o)jd(X{u zyv#SWv0(lyJC1$_?O;QsjQT+Q<0AFCRh)`5ZgF{D^T&xgUrZ5o(M_j3sFC7C)#p*)BJHfmC4X z^*{pM>BgoXQW>A9C$^0-*Kj_!Q=o@F?$q#0o$TH$@^zf|Z_A~Gxx@lUgi6NPODqz$_|puG~QI5eesZRG#e<1dJa~g=4|V%yYtQGcVWmV@diD z*X?YF@^;+ud+AU2?0M75r_WWC#s<@}&(mf03Hk1FJ}b@X5*fXWdEw;Redu7e&{0fw z_PrCj=-k-uU@>f3#xNQGSBO!Y!t}*%@w1wv95k+_M0gsu#=XD2m?e_U#f!WEk=Rt-1sxFPlE67E%O%GcC zh%Vk=w@;Nd{*xBtjdh(r#XTJ0hwk}RRSf5-n6t!jY!G|36gN`Lw^#x|ZGgY;N_I@)dtR=v~+G3m2cFlf(gaMug z3jN{$A>2{dW8##HF;x|rx>h@R*pdI;#(Bj0RC8i`l~c`4hw?og_@@&t=Z)afM^NQ;*a(h_aMvbN$Qs^)b-W zB{0S6LMH!AoG7VY8zc2!*Wz*_37peVWdi7N;Dh$KCNZhTIMj&z;7Qck^Y*ERUsrOs zVLh)W%g%S=>o}DOk8>0(*x23L+IvQuUNWMQ&l=*9bR4P2W99KgT^QtN=U?#cs+5() zdhzl5cC{2XB3~hx(L<0EB5QQv8e`wVSq=uN;pLKIEo=?iU6=TJ1P1p`>a63j&NOyX za0YXPYh*9K8n-SUdAfeiEp=)kkpR(f^gN`BAVJ>TH zm0dJeW4};4VgY+s8y=|1d+N~E^HI&zz?{3pG(Tqk5k<%DNb*PsPg?XJVqqw9G^&y6 z_&%_m#hTHNoIVngxuyP^(`$QuQJXCE=YYv8ndv-%c%ahBw9bs(cn?|$9M0zPlRPLS zN}+kmw(F@r);@>&(n?6YnxJ+M-Ro#>MX;;KULo#@&RyxL-$0~257o~b&pBuZj(2zg{{YpAybR#5Zkzo; zvcwaVUN{l@DEY*L6PeJ-$BKgXif-u4B~e#n`|Zn@nrqj~#pEmDojt(Vl-^NL<3xJJ zYuui_rhnq{c&!eL+?)Q3ew4J#xXr@YQWa+w&2||wO85P4aqL+i>5VxwBhLB3sy_RY z0HfP)#I4umqR!)>e%w{RayKeY?0;p?jp0Fw3OGC3#E${kiOiTPu1X>ArxMTB7W1AD z8oHy-w$sY~DOo7~%5a4*jiPmHsD*VTtP~#C()Zkkd*)VIz!rwia25cCMN4x%39`h{eEZMYmYv|jc!UaOTG?PdZ?&2?|*oPcJ4*jG)&N{4k;5HeI5gL zBP}jifq^>{9CAt;pw&m5%P_f30sn;Mp#l=b?mFsoL{5IkoU+Bt{ z(jyRbclw8J5Hdc#1;n6t{>Bc3R6@bKBM+(I(T)_oLf$@Ii*f|ViF|eJ_cu=xv65Nw z;O&mzM}%b{-R_`Ln2=#NLWQ+4)X9p9j@h8|^ua%WL&{0s>H;XXU#**p6=vsxC|`FN zQen!tIg4(>P8>gx*|@lh?~Er-)WEDU>&=e(PqKC{>KlZPGIe0(X&nJ<_Kzk?AaX79 zt9*nEltQJD9mkKD_1yCwQd4$@9@=w=n$1CIzWf>loIc7eDmf=IHE-n!fLzb{&V5ro z2@tv9g+8RIp|KPE@>p>Qw$OJUw4S7tmtbgFz{!EHUD5|0#(&I_ojf6k9g5iV?dkaB zh_7+l$)7RY<5}&~Au}$)-sL^2)tyc{noe=VwQFxW$zz{9sH>jVDP&~V32cX6+V^Ofxb5L~ zoKdyp0e*11sO>lI;HrDeM=2HW61B0e)`Zq?xUtuJmcM<-=++WA=+t{g_OsXyc-8^?@3 z;XNQ&IYqHWwAnz@pC@oD)ohKq9fR5a4P_b8(YR#@xAZ>lEIWN{&4xZ3Ysu}!{=lC8 z)~UICrbt??wOmX>LP(*&NG?oLoyb6?$@w5uT>Dqmzo7wtLzg38Ymb@6o($-c+9>%1bK@e$wxGAH02Mzh|byi;lbb79^D!Hx2Ece^j1;i z^B zCwU8?z0}WH`z@3b{+O;2Tg99Zn#jc$jrQoy$NKt0O@g)f7W3i217PUOodelk#3j0C zwBGojgyTrn(r*fVE55mfl2;^HuREIVx!>IzW4Q1~Lyu$5Q1CE;dnWS^I&JW1p}|w;WMM zFmptm$TVG@yxZ9;JouOScm?zY!tisMY~io+x{tHHE(yX(>T2Z?>iPF?yat9}vu_Dx zGv2ujeGp{l!cqV_F_D;jQo<~&}Pk^hzbng`~~8!zc-(R$|G zCYC>k+XFq1;K#Tan4x|gg|UT>?ZSAKFGhdsoj+zvzyHz~M*m0NoBVg^8i{y)^!KoP zB(VT1i=9X(M~}?R0o#xL9*3HE@n@WbHgbNKhih-{6ml;N z=Zl9yjiO@Cw_Y|Li*vL;R+0n7(<%+au`U%lZm=P-g0gfknvQ*bL%FUB$!?f*xs^(5Pnqz2+1CAUQ6s(?wF) zxRifo8!s+Tuq?Jkn#v2L=@VPH8%HpR%e~P>zLm8wp4qgEbpZf|=*yuVJ)FuViDV9< z6M3c=>l_5)opNpZ?MStWxZY9U1pJMswQ#i%c!UpiQ=L>DDSb7CZjwcZ^DV?34FRZkbCmeLeoMai;37Wt7jiWTr%Dzs z*P-tVo|awQ7~7f$i-+N9senvUckGuyHG zP~{s?C0PRoT4vBv(MFPfn^S}Gd%E;Z(MrG`xg(WM)uE%FP8vW!cYW3CX+_gpbn~Vs zpY=jSr%L;NMRV+TG-+aoh196KrLoe(By%qe>KY+5m*K!7KxbgpN8w^j<^oPJtscD@ zU}K{fIHLa92d{ac)PIFv($8hqOV^qgXbsyS=AWu$^E98M5b{2<-FyOY%_n3b;vIs( zgY6XNRE{o;^7d_Wp@Om4YF-DKKGeQ9h+cOyo7X^2!A%3BjtN13tZT|dyn+oDwrpkK zs*Vil<%zE-9U@C4sb>T<3{4;pk4EjG?&ljS^X z^Tnk2v-%}#ipJ>NP-N+Y#3e_sF@^CBJ)&rz*vqf%v9tgHrz zc~P|MmZlR7MB}}xTH6N48G_8`Rw)qZ#VKo+s+b;!J3HewL3J@fpSHo{<5=uBGD|qOX+4Gdjd=dh?72@59&T zr(sWnRumZuB7f>D(^7rGN`SeX7)8PoR)v@vI9H02z)t2S*_jZJ=PZ{|Ue#aWp5`63 z`mbD6;P_~Ro{qQApb~7ouH@W+4&8KdHF{HlMn>(M)!O}d0}BP!Yb{HGy%%M2MUbabF41)dPxMBCw8)5hiky=AT5JR`eF1q>w8@uw6pF52P0m*ae zrkAz`zzlnnk`Dexwo|Mf@j^i6hq;EF`B>FI)EH8AZUt^*)$uQms9i3!*`1ENV0U~0 zJP?`8Hi8vt>qo7~f{oQIUCw@mkx5YxOA1b#uWx@(5b(P59A=J9b($0QmheEmbFJ%a zt^GLyk{4WqpYAoVlYFEya*y|v2k&7<7eDy-@9q*+f zTn8`OnqLt&qoo5=6)-(+urvQEV9;pzP8&_`fzA;rsN;Ra4cU2<=G~sgH63kvMY4oO zvacGlapcnrpVk`X3nv# zCo}z(C|=bagL@S8t4_GAt)bLgy0{i?+=cwv9L;8UF(LRcv5{*2NDFb`JP5sod!5dI zVn-jBjwLt*y37%ht_jqPN=J^8*Sa58)>$14j`{BCAXZs`NOHZP zfTHlrVF0o2?&S*~5RA%|u6HfwA?;S)s8srEzLfkFZ~`P`h~n4S`G1l0+GeCN(A1|O z*@Kw*ei6W^&wd%V3`srlOljkCQb{=BZ8p2q*a$gxUZYMZXhN^o-TM~6JST}cJ^wEd z%s-ATj%>sCzVBi5B|ivFTw~P;9nA)%XbQcuf>eMMkc+Y%YECOq$No7TtwSFT91eE8 zL8-flbV=wsKPR>mPb7X_cgh67{QOsbnNEF?mW?z%L4{o;-#NtnJX{4}W44z^d@Gz? z1W=aqTZ&-}`_#Fe2WQcqqWL0;$KvA4=YTO(al9X&!Jx`JT3weNZIr1tMj0?7T2)v# z@+7bICT<_`#6BTx!T|extO^(oscVH&ny;Th9 zaEKeKr!S7Z!^7y8lYQj1(u#qIpW3dT_YKGgSD|^jOP#Odx7b3N5_aT!@0s;(Z<2`1 zV~5F<#9@@pa?dRbXhG$P6m$u8(OY+1)+&f|*Yk_AsZty7nN4 zUB?b-cfdLTjVt3A9QFud&e6ZpT-u{~^~Ji#h2fPutAtDeg*c#q<8qrl-}m z4$P34%Diu&dRf6%#lT+UTO4bd(GwlFtxB8w8yALgUIDLoqnGdKTZP`2VLY2oYvzgP z$V`@aO0^)SA{R{kDhz)47JD~Zy7Bzd`3L=mGf-Jq4r&`2_;K_BHhT+B3B zJ7+`yXY=CC5^e3BUr11E+U(v_C$MKfBuRe&M-y;zDD1ZQ6!Az{pl4cLAT~)5!$L zFOyam=sj;NF#&y?j5O&tzjUDJ&8IYH%wa_wV&Ah++R%?oGYOW)aGi}GATyivDmp7*KuBqeS<`; zop`sXb^7+F9kc6jtv#C$yrJ&qIZ1RdH&5HxPz?tIRkzRu+DR6~5z|!01KvkZ8k>h(_1TT4>|3c^%JABc+gG)bSa}CVSh$J3Te4qgcI{vF zDblT#mHhtNtjpnQ+Nqh(*2F53kvGk$B9PO!!Hp)4`yQDY!jU_Gld9P22RfK{zTB__mUlrH(rmNk=Ko!oYoBwdJLR&JW#&d@nn-0WK>@ za#PvY58{BlY|`ZKu&(uGobnR_Xv&X!rxe4#K!VwaFy_y0ttWU1&y?QuvtUQ#SIxq% zbl8WxcwD`@>4Pjv4#%?-o(=PrbCs_}ZLA zOQ(G!38ifuqgH2)chl;|E3u`%*rZONqmzroBZ|PcQ7EbtA%P6YRWJ(w~O%i&Y)F_0z51MwMOvmqjF6P`Z(Y#TQd)~Fi-9Lj=77Cwr#KjBPx~u zV5;>VaQGl)u9a{!0SRwIwrDIx_E)$kx<7~aGu(jYbbV#wkA88N7h}e`;=PFs)0HyvS%69s-iuq$z`MY)**_jJ@>HR zJ`*E#8d9976_aeaWi3J0w+G#icHvWR8{g)(_uCVZWo_i-Ol5}2M$j6{{*rOm8?Z>^>0l2!Yn#Ssbz{F<59R%EP=+t_J}z4)dxaO zIAn}kt)J`1y12ZlpOcyFHQaS8#%?+>|KJX*LHtRrINYZZya(+Q$qpBTQbhmaWV;O6 zYY&y@6~P+VOW2XQ(VZ^vsy-eJdPgebps~~2ICWrwB0Ecz3y%lN$N~N?4j!UvTSoPH zUP3Q)eBny!PRdB|Kz_Au7SIvvaj8ULJDTJp`t=x?QP`0#|9~Qd3v+5?O?ikMkG14m zAqU){yO_$OB)y1^8`&=%d-&qlvdG^?(>a7W<@Uz?d9B#bas6uX<1vLq*8;)B!2f81 zBri9c^3QHXA@v@&Z)o*&-z&MoL7V$CwPwGld8D_sIWFTcj|S)iY3|(zKHt_>#5e#s)X44_|(ds z9#;EL?uZ%Jf;YRJhfd%BRXkZ)EJmNGH@rm9u@<-bRAoWN{_m(ZvNqPg^w(EO+Z*%% z%%i7GZM!DE&GQ6vKzK5qgnijR&4p!;nBRTeJ*k=fi~MinuS>$Lw51@o_y~aBKd@$k zHDL>MD3Fikd*_OG2Xp=%^S(~C+VEELb|kJoUJ*zU1nWo_PL1kJ)-_+&={@$j7_ZF%2=m--W*Y<`Eps7kFHk&HRYA zbmY)+;G(J^j=gkKXq)8tg+7M{Qlw&V#b5EnkvDh{T39{iQeOGAhT6visq*b3%gtZ^ z^_RZ36iHk($V|7dQ-`MN>8pXjR%;JPG;bXjtm>y#*p33NO{C~2~<=SeE25?bD zy|_M`1(8Gia0(mz#Kyk$(w}(n^Gp6-L9>>M4h$L+vKFyJkgGn&b$U)lCG16#6X=?& zIok>PPKlf2L>9=^Cp3gm`_`pse-t5}JPf)h_flO?Z5KbxO6_!V-`bHdFd9AwXfxL8 zn-{3WbwkU+iD>k=6A!5)m2uKH9`sQN;08HEsDGzdj)_!@Ig3{9JJVzZiT zh=b_YbZNf&b8ptpE%$oVcr@Rr?2ga<;MlqIF$PHfGd=&x8qan$Ieij zA-k5tz)qg4e``I6;BU{U=;jAzfy^3prsi%GUq1Og#pt71@a-Nbr;nSeHH3qc}4>Evi)J2Omyb#&3 zB0s#2cf?%};cK$>Z+dw7+D0znU!T)yj8Q;YexX0`xNb~1)vn}D^Bf08eJ5U;%q8_K zaP8qo$%FP?9zdps0ZC6o_lXmkX?_&5FCOp^ZHF!CP#Nz+o})P;?_#d!rSf*om3KzP zi`_15CLP%%4v(=#faUS{y!p0a;Uz=+`!af!DNuh)ndl77U_qCS)nvUg3)aq3RFBZd zmBwmQxG9e-jX#6u)8xls>Aj@t_wRqY)rNNl^VniO01cna$GXfuEgsPm%x%_Wn?neJrU#Wj<^HcT5x>3Kl5Yx%0M~-R1W6Enibyom4Mu0%H8@-k64W`J7 z`N)Gc3b?XS5y#=1N;X&AoKuCOQ`D6N`?Bk8EM;(1q9>fSRn6lomi!oL5gg(;k&AQ_ z8tZXiieeb{-@HXL4CpxKF}DQ#6tzYjePJRg6b_5 zJZO0B+Rk9Az|gRZmAq7qPbDvR;*FEnTo7k}#0fo$Wv^)x=C>he8igEs+!4{)TkUgl z>QR&HOw!_Ldhdn?G-5R??{DoF(id$?Fs@=04A0i07^Cz+E|RTY=}q9M8P8wpc)Y49 zjp>CF6}ls$fz}vRC)7HU;P52cB)+lLKiK_BM=;;UePw@?Wq+k}#&gvm%~}tl>_-@x zTI~*HFbj^~2ljP0w{#8l4h6V_0uQ&q*MQ_zZ^u$CD$>xo%RraD|#y+ zL1Gs1A1=A|(>V;(;qiT}BWXUPJW(bbC*+r(BBP)?PPu{sZv?)T4L-T9QdJbhQIAR; zm_)ArROZiWXwrupp>Ooi&%d$#8MoX3%R29e6~p_FP*AU3%|a;HG0w=O)jDRc^=7|W zI5@Tqb?NuUiCSW%SD%E!xlyH{zZ-Y6v9g0SxRth|_l@3B=yX%07p^^ye&>4%4K&TqL## zs3+?{M)}CCG{%$()$$2F6-46;H`v@%w&Y+v26E<$;);k#WFvmxZ{R(>fkpI))-(=V z&GezdiP(Ca*IeSmG47;2Jq|$*-3e9r(e(o5qKewaw6S^m5C?L8r%&H^v~2K25w7X& zL6Btxb07cy#XtFG$kF~+llv`SCB?GCmr?r7(j=Go6?W~{*!hfLZL+nWxic<&EawC# zuCLN@Z&KC;n8U6S(RTUPGH4y0I2b3$P?>ap>=aG5_s@js2YTQ?+02y08mw6wFXLK( z=j+X!!x2U=PaW|piat=eFSdmY;XBw9O-^lt)e#8>$PG8N2sF_=BCQDuO|H z?fPNRtGGLpz%6^#`B)=xCi8pe!&AK-?%VkDSQ7fL{X-Xu{@KT1xDNxm)0`&xo%*3q z55#oFmP!pSo+~1L&D}WjE7KZNNCRQ$4%%_|ujrxIAc`BXY-@RUv(YshKSL1V9KKV+ zjRsyEohW2>Z3vu$odwr9^vP+2P56=d5-Jp;H=lZ&G7Lm-%p_+XYi08_9-J|Up2VBl zmioj$Tr_Y`r%4bfNZ6Zqsim3G;kC}{d3lp6aKY71l|iF+X7e58RIXF{!j2Ao5bPJa z@O`E*$7LwBR`Cl+G3T&jO_yzada-d7_5P0lvfksYdTJ|<muCibf(ap5GADnB%y>E6dZn2ozKpwIk?;XXz^4!;Oy@_$6I zmc=jxA=+6k$#kfc$R=dg{m33GWtMw=u8uZ8+m9aYo+ohiFvIhFdlgT5!=5OiluydJ zK3hCkyif2FcYY`t5%C*FEjqh1&{sur?vxK+NRsqh;7#N{o`RwCQwH`%r*`j5xzhXsn!&PV)*Ir~lS_%rJ#T==o`sup%uAsPJ>S(-7Q zS`ROCM&gg1&`+Z-`Fj}Gr{};ty6>P!uusy33-2%8#N5MidCAQ949| zej=d?xUdI(Vl?^b22QUgyGk*ReI6V}aT8H8QuRhU6OJ&LI)|W5>Y#%Nh^5Tr z2gdsy^L0JuiSdD~u?p=5OJf!t#;YG#7b59{iL@JjlK>!H61xr_S2R2{hsmQPNC0Q$ zkP6~fyZn>>O%7nFY~hqI=X@U7l#Z`MT`5=s@o)HrU~150BoioFTWa^a7e4l5k|(!v<~U*t34gAY$*g z;oKF<6pcx@On+f>9%C@{0UC`UfZ@X%_UaJ=tRHDA_TZahfi=*f`kmV++|g9He5CQs zb*1^y!V>*A`Znf$-Cz5z+@){uea0AV`n0Ue0>)@?#;rIiMmftZY_9B9-LGuW#ldDJ z;{iB$a#Y%Qb2{o(#ewmL?p&b-RBUqnJ28)VQmhAl-aIsc?2Y^bcM=uY#jm5oizA32 zQ#dcSe_j#a6k6>?oiOv!gTbEczklHm0f-;zAjul9OpXqYye8t&fbG}Z0hm{-M#oS5 z?Z01tiEdfvK`SnppGW`*Bi%?w$FI0^ec#maQziqUzXEH?t@x9kCtSA8q|bxd_mm2m zIbQ{QBScVv2&P5rG49&T9JE*uq;;uP0mF`bF%EvtbpUD|4|G1b-P*a4pJh2On6VEA zb^$FP+fwQ4bDR%@#gN!#E^u9F8;-Jz9;cpHrM##8Z~HC-%=Dd>NFRM`@EmnlSHWdo z1+Uj$rChr6SC#s68mwy`k37ePZ8S*+<@Gu{2oK%SpWT=Z>e9{6MYHTBrJh)PMI$GI za}xC96Q9}B593tRW>?p-&6<}+dE#@b{FG4xm;q{jXI4mg$^TWIz{l9n$3qwf;D{`A z9vv%fp2(iaWCoCe?!js%_$E5W^QAF;lOG+7E_i`gSPWf_;PFzrDXV+@)Qc`uDdNg;o@Ja~y9JFdaT-HHM0{xA18 zECXCk`$&I1Ppdrlxmd(_zZqw3l>$Ps)LVT;awu^tKA6xFmBo^tYP2NWgzgNB&t{?vn6~24C z#%yCa^2dJD(N=29%WW{c=xy6W`}QqPApaEZw|o%5wxU=;#EyLi9JGHapDDV3^V+CHHiHzj{LAjsP`;w7Y zjI|d?K!O6daW1PRVOlJd!cjTNgEC!bBHri^Kt||J#+`>cx_QEf>DIHK+61P=Jd+pAhl~lZ{WUtXll*AE4su(f7#;mfORlY@nUoPUH$@j z_grI9AvJ%!hgZvculk^eTqKSFZSgYhzxUP_zz}&-MNKZDMXcj9*PKel{ubl zUdtSPxIe~r9aS#Oc!66NSS^wwqX)<=ULipSFI60D=c&*!2|70GRCPP))=2=>PtoVa zafjQqwS~VCV>eA?NE{AV<8pmU&Bxvf-Jj(eg}3SWyCREu*A$YLS#B@rS}Rd_KxV!A z+@vt#5EnK0hPi`2ZuvU>L5_IP(RwiD4vRALu|*BFryJvhe&=ff=;gi0iLRuhZhG3F z<3eY%3P=Mo*}2i=X06}&8(oWS_ERv5Uz|S+b!DlzGmV$00GY9ONIf68hSbyHpVpF+ zo#8=j+x4p29x`0=u)^^WD>?99&BqQO{Hz{(-IdppgN)5dEnvI#3J^Bu1pzRg9%1wuC5#{6}I@1*i(HlDf0AxHdy zZ}6yY6QOdn0ruG@lA7yTao}!K(D`W5Q1iJTojIy z#H_=Jox{Vjo=2#9*)>$T`0e7EWA$3}q0s!?@M6+VLt2bcs521RjbbMcu4HjEy&;yt z|7BNH8;(g<+qE$xELgL!P)_7ot0BNZ%yKe_X?K+6ni9#zG<<{TBm$h+Fc#cnw0Bay zS7`GKqSap^B3^t$2yWs21A|fdqJw)OUGgW#+PM<)CZkqF5;4{j`J@Q~BzYg8pNucg zfsRe_*b#hP2?Vy%3r~GTTThlrvShxG1 zW?%ay*Raj_><9v=!#2{;j|aFa0&m`=t~|MH;@BhSS zlAi@a0tAwLsZP)AapJPXWpNRbU3OJ-qpB$FN`9Us*nU2ECaqE=>L zGn!8vnSq6J0h4Q^;poa?)h*wdvqFu*`3K$bn5MuEz;}?o_i9wv$za&{<*kpN_#5;F zn_34Tkl%^z_)CEL8nEWLAU@mCiSb!09vwp_H#TMH0X$WCe6NSpxlC!{~)3QLW zW*WWySjOuR?TjTg%R{^O1JC8fVmLJzoB{<){Z4PwcWM4XEl4`3{9S*mgUQL>LZV z-3c7NPCMDbjSarJK}RIL+M9nQ)qSqoB=WHhb*TGeBZxKIkPoDz?U_iV0SXrl(4qh4 z8%R-7`;fY}U0j;4fqz(+y+Np%7`|t&yi>Qr*c;3Y8y7L?rR&!A2OpCLVvCf`P>UpH4rh^9IGGDKCO!1yrli!22 zXc5i~wUEzP89+u8-Ftp!cK;mhSqwN=oNaX$i?!$s_P$iIrht?_I0{xoPR^Fu*(Qh| zcQF=s#^a98u~SX(D{NSw?p*^~g#U%MnN?FggMi)0^pqsDNxus>j6|o4U>024E}f#U zL0^p4QATyG zi6G<3lR9S$<9@{O3HH7=WbdXBLGZ=8xoYFVfd1_d_^%HO?BzmXl3`bNkuuShy#B)c2x3Rl6*@*R4^^M05 zn|4)#bL0`l{R2C7vESKne*3Ehr$4e(<3Lb0sZ;G`$KY=w^2Wvb-VcmbVtgWbA>2)sg9%AyRPaKZ~xnvr8A=}dduFYHN-gf>dM(0wa(VU#+ zKWKjf^MN}zRb@>bi*yciX)FW8)jVC5hdKPZ#L0uB;2L+K$7PZ+k7y{`F(>c%uR5pK zjw-)%&&CBWSJTVN?r<~ysZX=6cr`LOOMEG%B?&cuB`2q{OSz1h(JmxJ#>IosFB>P@ zsye**ll8zOp|`TT;>}2&;(iEwXUMDmn|es$M;;=5`y~0I&kOD6viu~(hLhDIu`)92 z8S`jz*9e^O>PBBO)yT^uO-MO=IpN>{uNZ0TM1d-Y-(@~ zuQz*Ri1C<>Zkxb~pp`Li;4E2keebQwJWjyTedmw$;)~lZftjD6IiW>O-pgH#*ymDh z!wkp$tsS|s?n#}8#{HXX4koPHp2t1*Av&JOF-h}Q@dq8S$#eE0 zaH|#k)b1jWvl&&IITZzC@z!`)8=t_m_}spfn@RhCFz55mS?l^O`PuG)vtb+)jF0E* z#LMp{)ADpUsgtZqK#fuIKM;1T#q2C`)hwsss?rDKzhwRRfZzW?78yv^o_FU8&~z_+ zVDh2W#NQP4R4!G%NPJ-HU~Qnc8Hc&CZu>X0mNT~@dsTi$c}|fsk+)Thc9hujLFYE|Q?{4S_Cl;h4L8mAn2K_l=~ zh5apfLxxZp1QcpBuyW<7zUt9)^B#>_&QL0u!lX*fsYG#6B*vVT4@RCP4p?5pYTXNAjWTBcF_SL$C8&|fEc&(mkgU;WS07#Q_ zvaVwki{>XTB6!?5NN@P|GacbVfVi|nys327QG=CWLH8rA$3mBUMgEcX$hHNa zalNpTw>-3MoVIOo=QcSvjS+(t8%HWwh<0J+Qt6M><3t!hJFnt3h=S^vj^VM zC6&KM`OuokQayGRoe0iO8xj?EN2@v7qveFP!)%I$YfOplxKRz#+wK{hN>#_LnJ!>Q z!M1^H`(1$;DZLAvHE>;Za&2`Y1B<6}XWm_r(rnmytF#$M3c<>SF< z=ngyej&BUfGZ}rKWqhHDfgZ2JfTK;{JK);Q(uIq>vJ}0bG1dv;!;c0e$gK~W*!6LU z7GBv8Z47d!_jN;H1dU*UtQO%8zn1`)0|8UG?6*JR7%QYFfekFjz1QLO4lXoxKC=I4 zDRqVIWjF_j$CDXA(vmO|(#oQO*)_AJyxHx&4zmu))y zkDpCMmxnFPtC0&C8wd!mi+->XBaZ&!H%_W;F%`N>KfkpB<`^3{+UiQ1hRvCXjyziY zS*`}Y;)}IWBM#10d80X+S6id3+Oml`RBWaOheWHvw01@6YFs;ctwkJBTlmHi{%tpP zl?3IAN?v~vh}PfjZy>2tW=__1)f{12?{%)z!M*Us9!3`Uxs8ip3vr9T8%u$aeE7Re z3j<%kYRiyVGM64&C&|zmuPB}$^!~EV37$4YIv&MiL1S`iCLjk>WPQ5s_t$l4~?sJ>$~Fy}F01Sg{gY0=EaAafUT)&$E0!G;y6!!u%VObsW>Exi0F zOY>~&$r{wKaa%R|Y!_h5J6(5fk6Uwa_Q-mkx2>O(1ROtieo}V?B#z%9EiF2g|2moh zxyV9o$_E5+;|V_y75AV0Jf)g*^*si(aD~2f88R#H- zXC0T-&+8Nt)!vP~+{iu2jqv)^-@sDuin0x#6&)cr2r4BNc2znz398+p_~9*gWEkaS zp$kEH-w7a^4Oe!$$&F)QchI*PP}w(+>YHZSV=LEFlb*?mk0FswNyh%q*{WtDRsAs0 zg!aBA3e`qy+p{tCL~q1tUnH}*~Fc!KJj7U#UVuJhFNulz=BBKrtM>{5*Lg5HL<-RvX3e zRODtY4pMMp(S?7yFT{v-X5%zo*!uZ1KD1R2de-|jrE=swNAG>U!2=^^&hlhrFL_7# z#sBpM?Gd6MgE4M{Zm)mVkV9uJ_tjikrbcY%_A8y7Zie5Pz=sA{qY`k^FLlTk%$X(n z7#P0dr&D!Dv2nZ2Ydk&JguiwykoglLQGgGUYevKd7A2>@jugQ zMNJ3()ekxsu8wVellQ{vLuRDgk z+zv{VKq3=e5>MvrW_h3!TRft6Zwv({=_gpD?htD&x@k&(Fo!LQBGK~;n_W)Np5Vhs zh_BgO<6|o7-dyKH#1bCnwS+?#=I*JC)g@1~R>%kW6cb|4FbR$SF4E9f-9d>hcpy8E zJz!BF>{yU(qTMq3D&Iu8OLTq?7Sy$i_g4I^4uiJ{U)BEDQQr&32S*q)TukZ46-iyC z=u!DNVm#uO(kQX~(3BH1BXORwo^cV)d>+Hh7JP^f*nXm8*|*#5VpX@dQ9q^#cayBX zZcpcDb(HyqHAOs<^;x~6BZ`xE5y9UTPGP9-57X~_4Sog_XnpzGMon)3s@C)=ru)}*YAH^rW_ z%n0j~;O^vO_^#f%KEPMbWX7-4(p(UX^C^XeZRLRnhf_PUVk zwMmN?XOd5*#L#06=FY*jnAp^qD!FPDD|&_Vn63#Sx7qXN0RN4g1pICPmh-0BKaojX z{SXORLb2cja%gkbx-Iysdncw1RI;sR#nM95eyY4BVw`m6hYWoE=I18&)C>vB@>4%R zlKDATfc$+VeUPbE0j#mC-Oa|AQ2>EW7Y1r_#+1%HT&Wm>k>!vr5AtFAY2*XzyxYw4 zxKmAN26SpM5U0)fNkqHOmBs+Vy1B&kH{cesIf78rG^o1;WT*bYXW$n_kQe=YYCv6%Y#x7_l2qrXFU5pGRn0xqL3*z{kvyJbvlC)rSe7B z3a=E$DfU&m=U)knV}((vT$S%QoG;`|i=uPZjZ7T0tfrC=(+Ifane$RuyXx1e{P8!A z$S>69FZwpfub(t;>6mU5JIml(BV0dK4JF!c!5w;>m*uz&Sw+p`pXJu_${j~H+)JN^ z&fQiX!vUJh}}jMzRFjEevDrwmXo{gvk=aZ1QX<<<%6 z)Z~Zd@`y5{=aQLrq+yOKq$LolW> zNcU12Kwi?YTXKR|+BQ-ax@>FCNE{r#B9 z{H%P#XziuGfi(X$wukymqG_;oO_qZXIJ2PT|{%?m*!hK{t8hjGD~wI6J^St<<{ z`I`+f<afI8?DOU4BJNV#NCc(-4m}}o8(=;0b9VX&fXp*{2NJUT~ zfI>>i*Q8bJ<`Kr)wKuLIc&O;;dy%AA4;1m<*?`9P9>b?gyEiaRLUMyf9w6~}TbCdLpk6ItssN7kU1i6I zti-m<&vc`U;P@I>;Tacr&3dN`1F!70(jka8F^npx(>B?jB<>L=yG(#n*2xp>S{{(o z1Edp3Bg1ZGi!5Yn(}J+%Upr?Rm!_uH&pcLeVCe*7&3coGXL7DsbL=P7eT0g>&-v;B zlA`F`>HWio%QNRBDE2uJ=tbAz6*6y;SGHEXZl7b*HLz3j2JWfweU+RoR8!lGoynS? z`DM&fFjFpRyLjPQwPa+VxOahn+r`)_Qz$z>toYoPbI(kV6q9Gex@!BXyfKwF-xx{w zbm|vpfsLZ|JvN(z7>DIKZ^6hyNEJxX(B=9iC>y@B^IzvU16S6HW6&WO25c}Mx3V{y zk3nw(oX7bozk&M{`|OQ$HtX!g&90;}{Uq^8N+;4pNN_sI*yX16xeKKY&Mm)TO4*(G zb8+f@IyT)18tl4>$1$~owCQuCIZj2tnz%~HiU&V;{B11HbL%r(7~J`(bEpIZLxmC>eA9Qq zPgE+>o3*YsCd@KU)$qqDeHZmT+MV8k!PN=)j>$ylY=rrWAkjV`X_)P(_VlO-w$G)f zdMfbZG2Rr&pigA19{jg4Sl*Mie0G0)avo`kKMPmmTaQpoA53cL1Z>XP;q!&MLu}I= z9mdp~ql#f;f`Dp1JOefOh|VtPOKPfVfY&fo{97DNK+~G}$U#lUBM_%NTpcYZpq-`Z z_ZLlB3v7MCfu$4d>FFABUvBS%rtJLq3CzQ_kxgH>pXJZdS~)oyzq`F|Yn4Zjzmh!T z9pQ0oFU4^S>m}Q}l#p-vho5If`mPbpPV%db`z*1dARgUUa!+}yyy+UYlDTPLo>r8~ zw^CN3tr;JPjvriM-W<)HwR^&~%YG%_lIG5@hL+JC)K@0m8UBZMmidyZIvKWo^!R8~ zx_zQ_Q$z0($?eOYFOx0qxdJyH<4rbpd@Ae!#%R9TRLh7QJ2pMG9(AW10xU-3uc8El zzp;@=LPE6Y@OK~R)6`QwpxdnuW4g>EIci2cf^ef`ye@Jw#D!K7aLRk25im~`7>?JF@31SUBp3x zX!A~;Of_OfAEb;F#Y@Y$dD_%#bqIv*W@|QFFsTRjxWzjbP}F0E=YklFgPo@g$z3^` zQJ?Gix#tF<<&Ed6A@7nv0D7Px(O$?LoeVb5Tq{xaF7Ei=T(x2B$7 zl>=LBk6)B}=QsdHE63UKMGI0G&`%qr5g|&x2!v9 zoGU{nX6V|TS?2l$Reo0KDh0=6y!58Z+eh}Xc;Q&+Md}^Bv9X6bJpA5EzN5e~D!oN3 zDFD#W*A{;6O87SBL{JslQOCE>>!u=JdS87HZiq17&_t63&;W;y$$80|k9d}cwxCC< z^o=Pt)BUd$NkRP`h~leSau|xUa-w^yh0chKOQ`iIzi{M61} z-1{`p&stnx&fVN{M9X52GU)H*Y!149PsEuoU2oIiT4C&sU}MMH%06I*d9s8AlXjWM z)ONW(^FyTk*r$1eV7Rss-8_%k*km-pcY^ z#AsJGuhL=bH-GoGV^#RJoQ2Q!%V4TM2D^6 zC!cOA8LQCSg>dJ8b>o>o$Xm=^MmvhixWbsIB||&HAR*jsyuD5Ji&^jh@3te)6!pBF zq13!poQ8*{=?)ve>^1U~$sxzB9Y2WQ*2!?bo^~hNotJUqsXT1qM-%@1rctNWa_n9e zr>#Q%WM5`RT`<=4?TR6dro|v#+Z{q!WE!yE)de%$+_Cbb4MaT=4eHc_7)&%XxVVEB z_IMM6NcT4eBO}YCT!+sWO$0-Riloj9lNF?8eVaD?jN#ex4`hozMHrcFEFyW*`ygS? zj~Ih%;AQW9nMaYH`aRDzXtv-l#>PIuw~KmK9J){REmqxDE1$Pi`|u*?E5k|O(4EC{ zlI>mPpq{TkuBQ5qBb5Tb> z-0!&Gi9dQ>^*1M&mFYC7U`K}`kbM_ID=_foWc|syUt^Pfd8h7Ohvx+yf+_DHC;BT| zyGs~_nZd0xT!?dM<4NDh+S1llba#;hE2GFFSglK(;}&M{;~31P8$JR$#;&cyj#3n zPV;6Z_w9kzM~`x{*V{>Sh~8LeEM4E6e;2ShOWvikTT8pS_6c?5w3eP^7S}p8%9?XM zJfG|8dQdXBwhivtyY4;CiGy`Ix?$y4|vYs;LgC7%hZ0&>BLEI*GZ>aTl z{4h=*STj<$E)n-JT!MR37{k_vPDgNpCx#z4kpL~DPx?0qC+`nFW!t*@x{Wf)WYzM} zwtaRAg!VgI=QmGSb9%vF?RaB*>c<;CY}b$nM!q6G*mz<`zBPm(vC#Oc!9tH6H@)4B zZ~k4@m>9Y|$<``{1rQc@$Rt8!1P>M5SWuU@KxUfx`vmb5RZXiO7>50q2N(P%I1qOr7gfOUe`O{iicgl-pejUyqaAszTUdEVq`tP0q4 z{0w^ijUoVIM?&O8&*$6z)i48sX3N`n*hIQEpQxiumt^#Lp;`>cm%FEPtXlAqX}I^e-idGW4|%O#=ja__ZY>~WsiO9s`v4$6zRmQZSWDfEq*H0p6sKkDth5z=}e zD+F-hxaL2{&6f5#JVMPokAv0uju}vHz{rD3jW8g z#$y7wpTG#-`ilt!C(j%$u!(H0EovdH3lpb1Igw^#oz_`p3;H;(ROgmT?|C9LHc9B6 zI9QWm@S=FN$DPy0QO}W;s$4SymlPVj^^QMN@x0{5;Icmopyt{H9#SeWj^OoqKFHi!=|O<`m5};iFlSLvW~!(V zz=~~fpEYwMJU7gkjJg@tRI|#TNG{I51M0ZNYdA@B){tX-0`cIQq5Hr8#A4}7$AEp4 z8&=>XB!ga})eO!U2UyEw99_3Fo~2a}maI&#y&HZAj^sjfCi#lBK;W@>*j|(aqFmQF zAL%{DG!94zqt`!+I81+qo1uE03V#~qUoG);E} zUFTP{cKj9gcjEmM<5>B;;@!`?6pda_-pAQ!9-Q|#2sPWjF|4JobG~$9(>Q!$5I&U~ z$!3g&Hfa=1tLZfJI$wG z2=1d9^gdiHAgAdmUen?VhZ5D?#VV~3oW{2;=}#l-EtOtu=Q zqIbm`joOO=hEPqogK?t;9QQ!t03-VNi|%?|&jnDBeci3$-NlZ0tr{!aazk#6a@RqF zVFngUp=&pClW#(Idc?AQ2xT{a1#so3HHo(7SdX2cyyiAzcA<#!ZaALWqc&^V8UGXKGH_)#zb`PQIwToS|FC3RXxUq~oZR_vK|EJhi-`ceF zeH-s7@VAaWvB~-BDRLEC?z6AKN*6w9eXL}x?_>{k(&s>~*V$I}KTQFP9q3C=v(SJ9t>qJ4K_A;S~)kXyh5d8#BQ3UKn!b+e0Sx9_Wq_Lfl9| z)JRJe^%!NVJ{xIDI28H?nR2-D61kBbVvy8dtz$dQUjJqd^|=kXw$tJA_WL(|1BpJt zHTy=sB<@0vW!ax70H^3bC3?bhpUS{^BUX{God!M|VtH$=w=t-kuud6pqAGdXnHpN$ zn*0xZ?Vif1JY2$s8NT;rH|^=)%!1tAZRbGVi=F zOniFFYWK4?+dOz2oF@2=wbf9>(49) zTjmWSkBi!$r90)+ne8}>tyGM|2cH^rc#`w(_ss^)@=|l}myRq4#5g)0s+*xR4RJTi zih_q6e1)eBKeDo8%q8!&77O(K0WzVe=RZf(v1M<7mO|UMb8ZOZuo~v+8u6xdBP+ih@DW9SFKp zbG!Kg<(!Z&cGEc{-xBgahz`j<2dSYS!eUx;iP7iaX*&Bka zwPWo-gvDftEz7i*Oe42xvcujfv0dkBLVWP;Ba7v0mL>xy;#r))^wC+1yY_hwPOOL@ zMS&NtjGTy`s}~t4*7WvszXz5Y%YB*UXehG6#x+GoXZYL)wJZzH=q+2J4q&pjn;t*eS2FVkQOx$z-C5q(r zk32X+2F->CMntkVJ`J}wwGK16ICHxakCy2L(}OcwySl3Q6@4I|x8B4$x4M_a7@TdA zXuN(RmU_IScjuB(^R+&bz~_L2;(Kb8-h{>V`zhqB`Yr_**Q)LaCzN`8V(!#kBe$kh z=hzOa=HG!~ozps1e`gnJ&Mf;ein|##pR=#}czUgQDt8+9RXP8GBqkXWWZbTA(L%)bTXXpOY;$CW2B?% zC9{ZBGUL5Kt4qs(x5pM6S;U#eYJj+z%Up|7>sqn!K=v=*@6}}VvFfjXzK+&~HlUkS z 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

m_@krCR@BF4LzA@y-HQvMf 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 literal 0 HcmV?d00001 diff --git a/developer_resources/images/dcv_login.png b/developer_resources/images/dcv_login.png new file mode 100644 index 0000000000000000000000000000000000000000..9ca3208fe46f6bb46f84d8d8194370be920e382a GIT binary patch literal 17974 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

n}lEf}R$ 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 Oj>~%O`KdAMe{&#Zc5SdsWEN79ty-8@& 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 VtLI-A_W^&mW^cPQ@e?(S~ENnU!+x%WPw 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�Uau1 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 literal 0 HcmV?d00001 diff --git a/developer_resources/images/vivado_startup.png b/developer_resources/images/vivado_startup.png new file mode 100644 index 0000000000000000000000000000000000000000..848bd6879e738b8b7b55b3823fab5b96d69c9aee GIT binary patch literal 296078 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 z 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

q|0-R8XlKH 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 create_libs.tcl - cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl + -cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl cd $(SIM_ROOT) && rm -rf create_libs.tcl diff --git a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa index f8c9d391..808b23c2 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa +++ b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa @@ -41,6 +41,12 @@ ifeq ($(TEST),test_null) else cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_2_3 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 $(PLUSARGS) -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) endif +else ifeq ($(VIVADO_TOOL_VERSION), v2019.1) +ifeq ($(TEST),test_null) + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 $(PLUSARGS) -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) +else + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 $(PLUSARGS) -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) +endif else ifeq ($(TEST),test_null) cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_2_2 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 $(PLUSARGS) -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) diff --git a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.vcs b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.vcs index 3321775c..61cb8232 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.vcs +++ b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.vcs @@ -27,7 +27,7 @@ compile: $(COMPLIB_DIR) mkdir -p $(SIM_DIR) cd ${SIM_DIR} && ln -s -f ../vcs_complib/synopsys_sim.setup cd $(SIM_DIR) && vlogan -g -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog +systemverilogext+.sv +libext+.sv +libext+.v -full64 -lca -v2005 +v2k -l compile.vlogan.log -debug_all -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f +define+VCS +define+DMA_TEST $(DEFAULT_DEFINES) +lint=TFIPC-L - cd $(SIM_DIR) && vcs tb $(TEST) $(C_FILES) $(VCS_OPT) -CFLAGS "-I$(C_SDK_USR_INC_DIR)" -CFLAGS "-I$(C_SDK_USR_UTILS_DIR) -std=gnu99" -CFLAGS "-I$(C_COMMON_DIR)/include" -CFLAGS "-I$(C_COMMON_DIR)/src" -CFLAGS "-DSV_TEST" -CFLAGS "-DSCOPE" -CFLAGS "-I$(C_INC_DIR)" "-I$(C_SRC_DIR)" -debug_all -M -I +lint=TFIPC-L -debug_all -debug_pp glbl -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog -full64 +memcbk -licqueue -lca -v2005 -l compile.vcs.log + cd $(SIM_DIR) && vcs tb $(TEST) $(C_FILES) $(VCS_OPT) -CFLAGS "-I$(C_SDK_USR_INC_DIR)" -CFLAGS "-I$(C_SDK_USR_UTILS_DIR) -std=gnu99" -CFLAGS "-I$(C_COMMON_DIR)/include" -CFLAGS "-I$(C_COMMON_DIR)/src" -CFLAGS "-DSV_TEST" -CFLAGS "-DSCOPE" -CFLAGS "-I$(C_INC_DIR)" "-I$(C_SRC_DIR)" -debug_all -M +lint=TFIPC-L -debug_all -debug_pp glbl -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog -full64 +memcbk -licqueue -lca -v2005 -l compile.vcs.log run: @@ -39,5 +39,5 @@ endif $(COMPLIB_DIR): cd $(SIM_ROOT) && echo "compile_simlib -language all -dir $(COMPLIB_DIR) -simulator $(SIMULATOR) -library all -family all" > create_libs.tcl - cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl + -cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl cd $(SIM_ROOT) && rm -rf create_libs.tcl diff --git a/hdk/cl/examples/cl_hello_world/software/runtime/test_hello_world.c b/hdk/cl/examples/cl_hello_world/software/runtime/test_hello_world.c index 54b671f9..6bd8e358 100644 --- a/hdk/cl/examples/cl_hello_world/software/runtime/test_hello_world.c +++ b/hdk/cl/examples/cl_hello_world/software/runtime/test_hello_world.c @@ -125,7 +125,7 @@ int main(int argc, char **argv) /* initialize the fpga_mgmt library */ rc = fpga_mgmt_init(); - fail_on(rc, out, "Unable to initialize the fpga_pci library"); + fail_on(rc, out, "Unable to initialize the fpga_mgmt library"); #ifndef SV_TEST rc = check_afi_ready(slot_id); diff --git a/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.ies b/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.ies index dec3281b..12842ce3 100644 --- a/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.ies +++ b/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.ies @@ -39,5 +39,5 @@ endif $(COMPLIB_DIR): cd $(SIM_ROOT) && echo "compile_simlib -language all -dir $(COMPLIB_DIR) -simulator $(SIMULATOR) -library all -family all" > create_libs.tcl - cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl + -cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl cd $(SIM_ROOT) && rm -rf create_libs.tcl diff --git a/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.questa index 206aa5f0..3b5b17d1 100644 --- a/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.questa +++ b/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.questa @@ -41,6 +41,12 @@ ifeq ($(TEST),test_null) else cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_2_3 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) endif +else ifeq ($(VIVADO_TOOL_VERSION), v2019.1) +ifeq ($(TEST),test_null) + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) +else + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) +endif else ifeq ($(TEST),test_null) cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_2_2 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) diff --git a/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.vcs b/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.vcs index ed3f6487..9f3fbcd4 100644 --- a/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.vcs +++ b/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.vcs @@ -26,7 +26,7 @@ compile: $(COMPLIB_DIR) mkdir -p $(SIM_DIR) cd ${SIM_DIR} && ln -s -f ../vcs_complib/synopsys_sim.setup cd $(SIM_DIR) && vlogan -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog +systemverilogext+.sv +libext+.sv +libext+.v -full64 -lca -v2005 +v2k -l compile.vlogan.log -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f +define+VCS $(DEFINES) +lint=TFIPC-L - cd $(SIM_DIR) && vcs tb $(TEST) $(C_FILES) -CFLAGS "-I$(C_SDK_USR_INC_DIR)" -CFLAGS "-I$(C_SDK_USR_UTILS_DIR)" -CFLAGS "-I$(C_COMMON_DIR)/include" -CFLAGS "-I$(C_COMMON_DIR)/src" -CFLAGS "-DSV_TEST" -CFLAGS "-DSCOPE" -CFLAGS "-I$(C_INC_DIR)" -debug_all -M -I +lint=TFIPC-L -debug_pp glbl -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog -full64 +memcbk -licqueue -lca -v2005 -l compile.vcs.log + cd $(SIM_DIR) && vcs tb $(TEST) $(C_FILES) -CFLAGS "-I$(C_SDK_USR_INC_DIR)" -CFLAGS "-I$(C_SDK_USR_UTILS_DIR)" -CFLAGS "-I$(C_COMMON_DIR)/include" -CFLAGS "-I$(C_COMMON_DIR)/src" -CFLAGS "-DSV_TEST" -CFLAGS "-DSCOPE" -CFLAGS "-I$(C_INC_DIR)" -debug_all -M +lint=TFIPC-L -debug_pp glbl -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog -full64 +memcbk -licqueue -lca -v2005 -l compile.vcs.log run: @@ -38,5 +38,5 @@ endif $(COMPLIB_DIR): cd $(SIM_ROOT) && echo "compile_simlib -language all -dir $(COMPLIB_DIR) -simulator $(SIMULATOR) -library all -family all" > create_libs.tcl - cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl + -cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl cd $(SIM_ROOT) && rm -rf create_libs.tcl \ No newline at end of file diff --git a/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.questa index 46ff2e70..7e4285e2 100644 --- a/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.questa +++ b/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.questa @@ -34,6 +34,8 @@ ifeq ($(VIVADO_TOOL_VERSION), v2017.4) cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_15 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_16 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_14 -L $(COMPLIB_DIR)/fifo_generator_v13_2_1 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_14 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -do "run -all; quit -f" tb glbl $(TEST) else ifeq ($(VIVADO_TOOL_VERSION), v2018.3) cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_2_3 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -do "run -all; quit -f" tb glbl $(TEST) +else ifeq ($(VIVADO_TOOL_VERSION), v2019.1) + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -do "run -all; quit -f" tb glbl $(TEST) else cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_2_2 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -do "run -all; quit -f" tb glbl $(TEST) endif diff --git a/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.vcs b/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.vcs index 1e0d2200..b3c250dd 100644 --- a/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.vcs +++ b/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.vcs @@ -27,12 +27,12 @@ compile: $(COMPLIB_DIR) cd ${SIM_DIR} && ln -s -f ../vcs_complib/synopsys_sim.setup cd $(SIM_DIR) && vlogan -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog +systemverilogext+.sv +libext+.sv +libext+.v -full64 -lca -v2005 +v2k -l compile.vlogan.log -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f +define+VCS $(DEFINES) +lint=TFIPC-L cd $(SIM_DIR) && vhdlan -full64 -l compile.vhdlan.log -f $(SCRIPTS_DIR)/top_vhdl.$(SIMULATOR).f - cd $(SIM_DIR) && vcs tb $(TEST) $(C_TEST_NAME) -CFLAGS "-I$(C_INC_DIR)" -debug_all -M -I +lint=TFIPC-L -debug_pp glbl -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog -full64 +memcbk -licqueue -lca -v2005 -l compile.vcs.log + cd $(SIM_DIR) && vcs tb $(TEST) $(C_TEST_NAME) -CFLAGS "-I$(C_INC_DIR)" -debug_all -M +lint=TFIPC-L -debug_pp glbl -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog -full64 +memcbk -licqueue -lca -v2005 -l compile.vcs.log run: cd $(SIM_DIR) && ./simv -l $(TEST).log $(PLUSARGS) +ntb_random_seed_automatic +vpdfile+$(TEST).vpd $(COMPLIB_DIR): cd $(SIM_ROOT) && echo "compile_simlib -language all -dir $(COMPLIB_DIR) -simulator $(SIMULATOR) -library all -family all" > create_libs.tcl - cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl + -cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl cd $(SIM_ROOT) && rm -rf create_libs.tcl diff --git a/hdk/cl/examples/cl_sde/verif/scripts/Makefile.ies b/hdk/cl/examples/cl_sde/verif/scripts/Makefile.ies index 59da02e6..65df9e03 100644 --- a/hdk/cl/examples/cl_sde/verif/scripts/Makefile.ies +++ b/hdk/cl/examples/cl_sde/verif/scripts/Makefile.ies @@ -39,5 +39,5 @@ endif $(COMPLIB_DIR): cd $(SIM_ROOT) && echo "compile_simlib -language all -dir $(COMPLIB_DIR) -simulator $(SIMULATOR) -library all -family all" > create_libs.tcl - cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl + -cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl cd $(SIM_ROOT) && rm -rf create_libs.tcl diff --git a/hdk/cl/examples/cl_sde/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_sde/verif/scripts/Makefile.questa index b4858172..decab5be 100644 --- a/hdk/cl/examples/cl_sde/verif/scripts/Makefile.questa +++ b/hdk/cl/examples/cl_sde/verif/scripts/Makefile.questa @@ -41,6 +41,12 @@ ifeq ($(TEST),test_null) else cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_2_3 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) endif +else ifeq ($(VIVADO_TOOL_VERSION), v2019.1) +ifeq ($(TEST),test_null) + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) +else + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) +endif else ifeq ($(TEST),test_null) cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_2_2 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) diff --git a/hdk/cl/examples/cl_sde/verif/scripts/Makefile.vcs b/hdk/cl/examples/cl_sde/verif/scripts/Makefile.vcs index 61f241f9..dc2f5f3e 100644 --- a/hdk/cl/examples/cl_sde/verif/scripts/Makefile.vcs +++ b/hdk/cl/examples/cl_sde/verif/scripts/Makefile.vcs @@ -26,12 +26,12 @@ compile: $(COMPLIB_DIR) mkdir -p $(SIM_DIR) cd $(SIM_DIR) && ln -s -f ../vcs_complib/synopsys_sim.setup cd $(SIM_DIR) && vlogan -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog +systemverilogext+.sv +libext+.sv +libext+.v -full64 -lca -v2005 +v2k -l compile.vlogan.log -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f +define+VCS $(DEFINES) +lint=TFIPC-L - cd $(SIM_DIR) && vcs tb $(TEST) $(C_FILES) -CFLAGS "-I$(C_SDK_USR_INC_DIR)" -CFLAGS "-I$(C_SDK_USR_UTILS_DIR)" -CFLAGS "-I$(C_COMMON_DIR)/include" -CFLAGS "-I$(C_COMMON_DIR)/src" -CFLAGS "-DSV_TEST" -CFLAGS "-DSCOPE" -CFLAGS "-I$(C_INC_DIR)" -debug_all -M -I +lint=TFIPC-L -debug_pp glbl -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog -full64 +memcbk -licqueue -lca -v2005 -l compile.vcs.log + cd $(SIM_DIR) && vcs tb $(TEST) $(C_FILES) -CFLAGS "-I$(C_SDK_USR_INC_DIR)" -CFLAGS "-I$(C_SDK_USR_UTILS_DIR)" -CFLAGS "-I$(C_COMMON_DIR)/include" -CFLAGS "-I$(C_COMMON_DIR)/src" -CFLAGS "-DSV_TEST" -CFLAGS "-DSCOPE" -CFLAGS "-I$(C_INC_DIR)" -debug_all -M +lint=TFIPC-L -debug_pp glbl -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog -full64 +memcbk -licqueue -lca -v2005 -l compile.vcs.log run: cd $(SIM_DIR) && ./simv -l -l $(TEST).log $(PLUSARGS) +ntb_random_seed_automatic +vpdfile+$(TEST).vpd $(COMPLIB_DIR): cd $(SIM_ROOT) && echo "compile_simlib -language all -dir $(COMPLIB_DIR) -simulator $(SIMULATOR) -library all -family all" > create_libs.tcl - cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl + -cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl cd $(SIM_ROOT) && rm -rf create_libs.tcl diff --git a/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.ies b/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.ies index 4e46036b..d623c649 100644 --- a/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.ies +++ b/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.ies @@ -40,5 +40,5 @@ endif $(COMPLIB_DIR): cd $(SIM_ROOT) && echo "compile_simlib -language all -dir $(COMPLIB_DIR) -simulator $(SIMULATOR) -library all -family all" > create_libs.tcl - cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl + -cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl cd $(SIM_ROOT) && rm -rf create_libs.tcl diff --git a/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.questa index 0cb6d70e..3d31459e 100644 --- a/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.questa +++ b/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.questa @@ -42,6 +42,12 @@ ifeq ($(TEST),test_null) else cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) endif +else ifeq ($(VIVADO_TOOL_VERSION), v2019.1) +ifeq ($(TEST),test_null) + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) +else + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) +endif else ifeq ($(TEST),test_null) cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) diff --git a/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.vcs b/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.vcs index efc2fd92..367b53fe 100644 --- a/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.vcs +++ b/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.vcs @@ -27,7 +27,7 @@ compile: $(COMPLIB_DIR) cd ${SIM_DIR} && ln -s -f ../vcs_complib/synopsys_sim.setup cd $(SIM_DIR) && vhdlan -full64 ${CL_ROOT}/design/ctrl_uram.vhd cd $(SIM_DIR) && vlogan -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog +systemverilogext+.sv +libext+.sv +libext+.v -full64 -lca -v2005 +v2k -l compile.vlogan.log -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f +define+VCS $(DEFINES) +lint=TFIPC-L - cd $(SIM_DIR) && vcs tb $(TEST) $(C_FILES) -CFLAGS "-I$(C_SDK_USR_INC_DIR)" -CFLAGS "-I$(C_SDK_USR_UTILS_DIR)" -CFLAGS "-I$(C_COMMON_DIR)/include" -CFLAGS "-I$(C_COMMON_DIR)/src" -CFLAGS "-DSV_TEST" -CFLAGS "-DSCOPE" -CFLAGS "-I$(C_INC_DIR)" -debug_all -M -I +lint=TFIPC-L -debug_pp glbl -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog -full64 +memcbk -licqueue -lca -v2005 -l compile.vcs.log + cd $(SIM_DIR) && vcs tb $(TEST) $(C_FILES) -CFLAGS "-I$(C_SDK_USR_INC_DIR)" -CFLAGS "-I$(C_SDK_USR_UTILS_DIR)" -CFLAGS "-I$(C_COMMON_DIR)/include" -CFLAGS "-I$(C_COMMON_DIR)/src" -CFLAGS "-DSV_TEST" -CFLAGS "-DSCOPE" -CFLAGS "-I$(C_INC_DIR)" -debug_all -M +lint=TFIPC-L -debug_pp glbl -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog -full64 +memcbk -licqueue -lca -v2005 -l compile.vcs.log run: @@ -39,5 +39,5 @@ endif $(COMPLIB_DIR): cd $(SIM_ROOT) && echo "compile_simlib -language all -dir $(COMPLIB_DIR) -simulator $(SIMULATOR) -library all -family all" > create_libs.tcl - cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl + -cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl cd $(SIM_ROOT) && rm -rf create_libs.tcl \ No newline at end of file diff --git a/hdk/cl/examples/hello_world_hlx/README.md b/hdk/cl/examples/hello_world_hlx/README.md index d6d9371f..47e35ebf 100755 --- a/hdk/cl/examples/hello_world_hlx/README.md +++ b/hdk/cl/examples/hello_world_hlx/README.md @@ -101,6 +101,7 @@ The runtime software must be compiled for the AFI to run on F1. Copy the software directory to any directory and compile with the following commands: ``` +$ source $AWS_FPGA_REPO_DIR/sdk_setup.sh $ cp -r $HDK_COMMON_DIR/shell_stable/hlx/hlx_examples/build/IPI/hello_world/software $ cd software $ make all diff --git a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/component.xml b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/component.xml old mode 100755 new mode 100644 index 1a4dff5b..de54734c --- a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/component.xml +++ b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/component.xml @@ -4407,7 +4407,7 @@ viewChecksum - 01e58ca0 + ebc2f515 @@ -4429,7 +4429,7 @@ viewChecksum - 7a659885 + ffa0fbf3 @@ -15920,7 +15920,61 @@ aws_v1_0_2 - hdl/aws_v1_0_vl_rfs.sv + hdl/sim/axi4_slave_bfm.sv + systemVerilogSource + USED_IN_ipstatic + aws_v1_0_2 + + + hdl/sim/axi_bfm_defines.svh + systemVerilogSource + USED_IN_ipstatic + aws_v1_0_2 + + + hdl/sim/axi_mem_model.sv + systemVerilogSource + USED_IN_ipstatic + aws_v1_0_2 + + + hdl/lib_pipe.sv + systemVerilogSource + USED_IN_ipstatic + aws_v1_0_2 + + + hdl/sim/ccf_ctl.v + verilogSource + USED_IN_ipstatic + aws_v1_0_2 + + + hdl/sim/sync.v + verilogSource + USED_IN_ipstatic + aws_v1_0_2 + + + hdl/sim/flop_ccf.sv + systemVerilogSource + USED_IN_ipstatic + aws_v1_0_2 + + + hdl/sim/mgt_acc_axl.sv + systemVerilogSource + USED_IN_ipstatic + aws_v1_0_2 + + + hdl/sim/mgt_gen_axl.sv + systemVerilogSource + USED_IN_ipstatic + aws_v1_0_2 + + + hdl/sim/sh_ddr.sv systemVerilogSource USED_IN_ipstatic aws_v1_0_2 @@ -15938,6 +15992,12 @@ true aws_v1_0_2 + + hdl/aws_v1_0_top.sv + systemVerilogSource + USED_IN_ipstatic + aws_v1_0_2 + xilinx_verilogbehavioralsimulation_xilinx_com_ip_ddr4_2_2__ref_view_fileset @@ -15979,7 +16039,37 @@ aws_v1_0_2 - hdl/aws_v1_0_vlsyn_rfs.sv + hdl/lib_pipe.sv + systemVerilogSource + aws_v1_0_2 + + + hdl/synth/ccf_ctl.v + verilogSource + aws_v1_0_2 + + + hdl/synth/sync.v + verilogSource + aws_v1_0_2 + + + hdl/synth/flop_ccf.sv + systemVerilogSource + aws_v1_0_2 + + + hdl/synth/mgt_acc_axl.sv + systemVerilogSource + aws_v1_0_2 + + + hdl/synth/mgt_gen_axl.sv + systemVerilogSource + aws_v1_0_2 + + + hdl/synth/sh_ddr.sv systemVerilogSource aws_v1_0_2 @@ -15995,6 +16085,12 @@ true aws_v1_0_2 + + hdl/aws_v1_0_top.sv + systemVerilogSource + CHECKSUM_c59ef6a9 + aws_v1_0_2 + xilinx_verilogsynthesis_xilinx_com_ip_ddr4_2_2__ref_view_fileset @@ -16429,14 +16525,14 @@ AWS http://www.xilinx.com 2 - 2018-06-05T19:20:33Z + 2019-08-08T23:47:40Z 2017.4 - + diff --git a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/doc/aws_v1_0_changelog.txt b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/doc/aws_v1_0_changelog.txt old mode 100755 new mode 100644 index eaf4576a..ab0095d6 --- a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/doc/aws_v1_0_changelog.txt +++ b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/doc/aws_v1_0_changelog.txt @@ -4,6 +4,7 @@ * Bug Fix: Changed default Clock Group A recipe from A0 to A1. * New Feature: Support new Amazon shell v1.4 (SHELL_VERSION = 0x04261818). * New Feature: Changed default DEVICE_ID from 0xF000 to 0xF010. + * New Feature: Added AXI slave BFM simulation models. * Revision change in one or more subcores 2017.3: @@ -20,7 +21,7 @@ * New Feature: Native Vivado Release * New Feature: Initial release. -(c) Copyright 2017 - 2018 Xilinx, Inc. All rights reserved. +(c) Copyright 2017 - 2019 Xilinx, Inc. All rights reserved. This file contains confidential and proprietary information of Xilinx, Inc. and is protected under U.S. and diff --git a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/aws_v1_0_top.sv b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/aws_v1_0_top.sv new file mode 100644 index 00000000..df3ce581 --- /dev/null +++ b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/aws_v1_0_top.sv @@ -0,0 +1,1006 @@ +// (c) Copyright 2017 Xilinx, Inc. All rights reserved. +// +// This file contains confidential and proprietary information +// of Xilinx, Inc. and is protected under U.S. and +// international copyright and other intellectual property +// laws. +// +// DISCLAIMER +// This disclaimer is not a license and does not grant any +// rights to the materials distributed herewith. Except as +// otherwise provided in a valid license issued to you by +// Xilinx, and to the maximum extent permitted by applicable +// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND +// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES +// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING +// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- +// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and +// (2) Xilinx shall not be liable (whether in contract or tort, +// including negligence, or under any other theory of +// liability) for any loss or damage of any kind or nature +// related to, arising under or in connection with these +// materials, including for any direct, or any indirect, +// special, incidental, or consequential loss or damage +// (including loss of data, profits, goodwill, or any type of +// loss or damage suffered as a result of any action brought +// by a third party) even if such damage or loss was +// reasonably foreseeable or Xilinx had been advised of the +// possibility of the same. +// +// CRITICAL APPLICATIONS +// Xilinx products are not designed or intended to be fail- +// safe, or for use in any application requiring fail-safe +// performance, such as life-support or safety devices or +// systems, Class III medical devices, nuclear facilities, +// applications related to the deployment of airbags, or any +// other applications that could lead to death, personal +// injury, or severe property or environmental damage +// (individually and collectively, "Critical +// Applications"). Customer assumes the sole risk and +// liability of any use of Xilinx products in Critical +// Applications, subject only to applicable laws and +// regulations governing limitations on product liability. +// +// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS +// PART OF THIS FILE AT ALL TIMES. +// +// DO NOT MODIFY THIS FILE. + +(* DowngradeIPIdentifiedWarnings="yes" *) +module aws_v1_0_2_top # + ( + parameter integer C_MODE = 0, + // 0 = AWS HLS (IPI) flow: All interfaces are available. + // 1 = SDx Unified flow Memory-only mode: Only DDR interfaces and related ports are available. + // 2 = SDx Unified flow Non-memory mode: All interfaces except DDR-related are available. + parameter integer C_DDR_A_PRESENT = 0, + parameter integer C_DDR_B_PRESENT = 0, + parameter integer C_DDR_D_PRESENT = 0, + parameter integer C_NUM_A_CLOCKS = 1, + parameter integer C_NUM_B_CLOCKS = 0, + parameter integer C_NUM_C_CLOCKS = 0, + parameter [15:0] C_VENDOR_ID = 16'h1D0F, + parameter [15:0] C_DEVICE_ID = 16'hF010, + parameter [15:0] C_SUBSYSTEM_VENDOR_ID = 16'hFEDD, + parameter [15:0] C_SUBSYSTEM_ID = 16'h1D51, + parameter C_CLOCK_A0_PERIOD = "4.0", + parameter C_CLOCK_A1_PERIOD = "8.0", + parameter C_CLOCK_B0_PERIOD = "4.0", + parameter C_CLOCK_C0_PERIOD = "3.333333", + parameter integer C_CLOCK_A_RECIPE = 1, + parameter integer C_CLOCK_B_RECIPE = 0, + parameter integer C_CLOCK_C_RECIPE = 0, + parameter integer C_NUM_STAGES_STATS = 1, + parameter integer C_PCIM_PRESENT = 0 + ) + ( + //-------------------------------- + // S_SH bus-interface ports + //-------------------------------- + `include "aws_v1_0_2_ports.vh" // Subset of Amazon-provided port definitions (without Debug Bridge) + , + + //-------------------------------- + // Globals + //-------------------------------- + output wire clk_main_a0_out, //Main clock. This is the clock for all of the interfaces of AWS + output wire clk_extra_a1_out, //Extra clock A1 (phase aligned to "A" clock group) + output wire clk_extra_a2_out, //Extra clock A2 (phase aligned to "A" clock group) + output wire clk_extra_a3_out, //Extra clock A3 (phase aligned to "A" clock group) + output wire clk_extra_b0_out, //Extra clock B0 (phase aligned to "B" clock group) + output wire clk_extra_b1_out, //Extra clock B1 (phase aligned to "B" clock group) + output wire clk_extra_c0_out, //Extra clock C0 (phase aligned to "C" clock group) + output wire clk_extra_c1_out, //Extra clock C1 (phase aligned to "C" clock group) + + output wire rst_main_n_out, //Reset sync to main clock. + output wire kernel_rst_n_out, //Kernel_reset. + + output wire flr_assert, //Function level reset assertion. + input wire flr_done, //Function level reset done acknowledge + + output wire [15:0] status_vdip, //Virtual DIP switches. + input wire [15:0] status_vled, //Virtual LEDs + + input wire [15:0] irq_req, // User-defined interrupt request + output wire [15:0] irq_ack, // User-defined interrupt acknowledge + + output wire [63:0] glcount0, //Global counter 0 + output wire [63:0] glcount1, //Global counter 1 + + //-------------------------------- + // S_AXI_DDRA bus-interface ports + //-------------------------------- + input wire [15:0] s_axi_ddra_awid, + input wire [63:0] s_axi_ddra_awaddr, + input wire [7:0] s_axi_ddra_awlen, + input wire [2:0] s_axi_ddra_awsize, + input wire s_axi_ddra_awvalid, + output wire s_axi_ddra_awready, + input wire [511:0] s_axi_ddra_wdata, + input wire [63:0] s_axi_ddra_wstrb, + input wire s_axi_ddra_wlast, + input wire s_axi_ddra_wvalid, + output wire s_axi_ddra_wready, + output wire [15:0] s_axi_ddra_bid, + output wire [1:0] s_axi_ddra_bresp, + output wire s_axi_ddra_bvalid, + input wire s_axi_ddra_bready, + input wire [15:0] s_axi_ddra_arid, + input wire [63:0] s_axi_ddra_araddr, + input wire [7:0] s_axi_ddra_arlen, + input wire [2:0] s_axi_ddra_arsize, + input wire s_axi_ddra_arvalid, + output wire s_axi_ddra_arready, + output wire [15:0] s_axi_ddra_rid, + output wire [511:0] s_axi_ddra_rdata, + output wire [1:0] s_axi_ddra_rresp, + output wire s_axi_ddra_rlast, + output wire s_axi_ddra_rvalid, + input wire s_axi_ddra_rready, + + output wire ddra_is_ready, + + //-------------------------------- + // S_AXI_DDRB bus-interface ports + //-------------------------------- + input wire [15:0] s_axi_ddrb_awid, + input wire [63:0] s_axi_ddrb_awaddr, + input wire [7:0] s_axi_ddrb_awlen, + input wire [2:0] s_axi_ddrb_awsize, + input wire s_axi_ddrb_awvalid, + output wire s_axi_ddrb_awready, + input wire [511:0] s_axi_ddrb_wdata, + input wire [63:0] s_axi_ddrb_wstrb, + input wire s_axi_ddrb_wlast, + input wire s_axi_ddrb_wvalid, + output wire s_axi_ddrb_wready, + output wire [15:0] s_axi_ddrb_bid, + output wire [1:0] s_axi_ddrb_bresp, + output wire s_axi_ddrb_bvalid, + input wire s_axi_ddrb_bready, + input wire [15:0] s_axi_ddrb_arid, + input wire [63:0] s_axi_ddrb_araddr, + input wire [7:0] s_axi_ddrb_arlen, + input wire [2:0] s_axi_ddrb_arsize, + input wire s_axi_ddrb_arvalid, + output wire s_axi_ddrb_arready, + output wire [15:0] s_axi_ddrb_rid, + output wire [511:0] s_axi_ddrb_rdata, + output wire [1:0] s_axi_ddrb_rresp, + output wire s_axi_ddrb_rlast, + output wire s_axi_ddrb_rvalid, + input wire s_axi_ddrb_rready, + + output wire ddrb_is_ready, + + //-------------------------------- + // S_AXI_DDRC bus-interface ports + //-------------------------------- + input wire [15:0] s_axi_ddrc_awid, + input wire [63:0] s_axi_ddrc_awaddr, + input wire [7:0] s_axi_ddrc_awlen, + input wire [2:0] s_axi_ddrc_awsize, + input wire s_axi_ddrc_awvalid, + output wire s_axi_ddrc_awready, + input wire [511:0] s_axi_ddrc_wdata, + input wire [63:0] s_axi_ddrc_wstrb, + input wire s_axi_ddrc_wlast, + input wire s_axi_ddrc_wvalid, + output wire s_axi_ddrc_wready, + output wire [15:0] s_axi_ddrc_bid, + output wire [1:0] s_axi_ddrc_bresp, + output wire s_axi_ddrc_bvalid, + input wire s_axi_ddrc_bready, + input wire [15:0] s_axi_ddrc_arid, + input wire [63:0] s_axi_ddrc_araddr, + input wire [7:0] s_axi_ddrc_arlen, + input wire [2:0] s_axi_ddrc_arsize, + input wire s_axi_ddrc_arvalid, + output wire s_axi_ddrc_arready, + output wire [15:0] s_axi_ddrc_rid, + output wire [511:0] s_axi_ddrc_rdata, + output wire [1:0] s_axi_ddrc_rresp, + output wire s_axi_ddrc_rlast, + output wire s_axi_ddrc_rvalid, + input wire s_axi_ddrc_rready, + + output wire ddrc_is_ready, + + //-------------------------------- + // S_AXI_DDRD bus-interface ports + //-------------------------------- + input wire [15:0] s_axi_ddrd_awid, + input wire [63:0] s_axi_ddrd_awaddr, + input wire [7:0] s_axi_ddrd_awlen, + input wire [2:0] s_axi_ddrd_awsize, + input wire s_axi_ddrd_awvalid, + output wire s_axi_ddrd_awready, + input wire [511:0] s_axi_ddrd_wdata, + input wire [63:0] s_axi_ddrd_wstrb, + input wire s_axi_ddrd_wlast, + input wire s_axi_ddrd_wvalid, + output wire s_axi_ddrd_wready, + output wire [15:0] s_axi_ddrd_bid, + output wire [1:0] s_axi_ddrd_bresp, + output wire s_axi_ddrd_bvalid, + input wire s_axi_ddrd_bready, + input wire [15:0] s_axi_ddrd_arid, + input wire [63:0] s_axi_ddrd_araddr, + input wire [7:0] s_axi_ddrd_arlen, + input wire [2:0] s_axi_ddrd_arsize, + input wire s_axi_ddrd_arvalid, + output wire s_axi_ddrd_arready, + output wire [15:0] s_axi_ddrd_rid, + output wire [511:0] s_axi_ddrd_rdata, + output wire [1:0] s_axi_ddrd_rresp, + output wire s_axi_ddrd_rlast, + output wire s_axi_ddrd_rvalid, + input wire s_axi_ddrd_rready, + + output wire ddrd_is_ready, + + //-------------------------------- + // M_AXI_SDA bus-interface ports + //-------------------------------- + output wire [31:0] m_axi_sda_awaddr, + output wire m_axi_sda_awvalid, + input wire m_axi_sda_awready, + output wire [31:0] m_axi_sda_wdata, + output wire [3:0] m_axi_sda_wstrb, + output wire m_axi_sda_wvalid, + input wire m_axi_sda_wready, + input wire [1:0] m_axi_sda_bresp, + input wire m_axi_sda_bvalid, + output wire m_axi_sda_bready, + output wire [31:0] m_axi_sda_araddr, + output wire m_axi_sda_arvalid, + input wire m_axi_sda_arready, + input wire [31:0] m_axi_sda_rdata, + input wire [1:0] m_axi_sda_rresp, + input wire m_axi_sda_rvalid, + output wire m_axi_sda_rready, + + //-------------------------------- + // M_AXI_OCL bus-interface ports + //-------------------------------- + output wire [31:0] m_axi_ocl_awaddr, + output wire m_axi_ocl_awvalid, + input wire m_axi_ocl_awready, + output wire [31:0] m_axi_ocl_wdata, + output wire [3:0] m_axi_ocl_wstrb, + output wire m_axi_ocl_wvalid, + input wire m_axi_ocl_wready, + input wire [1:0] m_axi_ocl_bresp, + input wire m_axi_ocl_bvalid, + output wire m_axi_ocl_bready, + output wire [31:0] m_axi_ocl_araddr, + output wire m_axi_ocl_arvalid, + input wire m_axi_ocl_arready, + input wire [31:0] m_axi_ocl_rdata, + input wire [1:0] m_axi_ocl_rresp, + input wire m_axi_ocl_rvalid, + output wire m_axi_ocl_rready, + + //-------------------------------- + // M_AXI_BAR1 bus-interface ports + //-------------------------------- + output wire [31:0] m_axi_bar1_awaddr, + output wire m_axi_bar1_awvalid, + input wire m_axi_bar1_awready, + output wire [31:0] m_axi_bar1_wdata, + output wire [3:0] m_axi_bar1_wstrb, + output wire m_axi_bar1_wvalid, + input wire m_axi_bar1_wready, + input wire [1:0] m_axi_bar1_bresp, + input wire m_axi_bar1_bvalid, + output wire m_axi_bar1_bready, + output wire [31:0] m_axi_bar1_araddr, + output wire m_axi_bar1_arvalid, + input wire m_axi_bar1_arready, + input wire [31:0] m_axi_bar1_rdata, + input wire [1:0] m_axi_bar1_rresp, + input wire m_axi_bar1_rvalid, + output wire m_axi_bar1_rready, + + //-------------------------------- + // M_AXI_PCIS bus-interface ports (SH transactions to CL) + //-------------------------------- + output wire [5:0] m_axi_pcis_awid, + output wire [63:0] m_axi_pcis_awaddr, + output wire [7:0] m_axi_pcis_awlen, + output wire [2:0] m_axi_pcis_awsize, + output wire m_axi_pcis_awvalid, + input wire m_axi_pcis_awready, + output wire [511:0] m_axi_pcis_wdata, + output wire [63:0] m_axi_pcis_wstrb, + output wire m_axi_pcis_wlast, + output wire m_axi_pcis_wvalid, + input wire m_axi_pcis_wready, + input wire [5:0] m_axi_pcis_bid, + input wire [1:0] m_axi_pcis_bresp, + input wire m_axi_pcis_bvalid, + output wire m_axi_pcis_bready, + output wire [5:0] m_axi_pcis_arid, + output wire [63:0] m_axi_pcis_araddr, + output wire [7:0] m_axi_pcis_arlen, + output wire [2:0] m_axi_pcis_arsize, + output wire m_axi_pcis_arvalid, + input wire m_axi_pcis_arready, + input wire [5:0] m_axi_pcis_rid, + input wire [511:0] m_axi_pcis_rdata, + input wire [1:0] m_axi_pcis_rresp, + input wire m_axi_pcis_rlast, + input wire m_axi_pcis_rvalid, + output wire m_axi_pcis_rready, + output wire [1:0] m_axi_pcis_awburst, + output wire [1:0] m_axi_pcis_arburst, + + //-------------------------------- + // S_AXI_PCIM bus-interface ports (CL transactions to SH) + //-------------------------------- + input wire [15:0] s_axi_pcim_awid, + input wire [63:0] s_axi_pcim_awaddr, + input wire [7:0] s_axi_pcim_awlen, + input wire [2:0] s_axi_pcim_awsize, + input wire [18:0] s_axi_pcim_awuser, + input wire s_axi_pcim_awvalid, + output wire s_axi_pcim_awready, + input wire [511:0] s_axi_pcim_wdata, + input wire [63:0] s_axi_pcim_wstrb, + input wire s_axi_pcim_wlast, + input wire s_axi_pcim_wvalid, + output wire s_axi_pcim_wready, + output wire [15:0] s_axi_pcim_bid, + output wire [1:0] s_axi_pcim_bresp, + output wire s_axi_pcim_bvalid, + input wire s_axi_pcim_bready, + input wire [15:0] s_axi_pcim_arid, + input wire [63:0] s_axi_pcim_araddr, + input wire [7:0] s_axi_pcim_arlen, + input wire [2:0] s_axi_pcim_arsize, + input wire [18:0] s_axi_pcim_aruser, + input wire s_axi_pcim_arvalid, + output wire s_axi_pcim_arready, + output wire [15:0] s_axi_pcim_rid, + output wire [511:0] s_axi_pcim_rdata, + output wire [1:0] s_axi_pcim_rresp, + output wire s_axi_pcim_rlast, + output wire s_axi_pcim_rvalid, + input wire s_axi_pcim_rready, + + output wire [1:0] cfg_max_payload_out, //Max payload size - 00:128B, 01:256B, 10:512B + output wire [2:0] cfg_max_read_req_out //Max read requst size - 000b:128B, 001b:256B, 010b:512B, 011b:1024B + ); + + generate + + assign clk_main_a0_out = clk_main_a0 ; + assign clk_extra_a1_out = C_NUM_A_CLOCKS>1 ? clk_extra_a1 : 1'b0 ; + assign clk_extra_a2_out = C_NUM_A_CLOCKS>2 ? clk_extra_a2 : 1'b0 ; + assign clk_extra_a3_out = C_NUM_A_CLOCKS>3 ? clk_extra_a3 : 1'b0 ; + assign clk_extra_b0_out = C_NUM_B_CLOCKS>0 ? clk_extra_b0 : 1'b0 ; + assign clk_extra_b1_out = C_NUM_B_CLOCKS>1 ? clk_extra_b1 : 1'b0 ; + assign clk_extra_c0_out = C_NUM_C_CLOCKS>0 ? clk_extra_c0 : 1'b0 ; + assign clk_extra_c1_out = C_NUM_C_CLOCKS>1 ? clk_extra_c1 : 1'b0 ; + assign rst_main_n_out = rst_main_n ; + assign kernel_rst_n_out = kernel_rst_n ; + assign flr_assert = sh_cl_flr_assert ; + assign status_vdip = sh_cl_status_vdip ; + assign irq_ack = sh_cl_apppf_irq_ack ; + assign glcount0 = sh_cl_glcount0 ; + assign glcount1 = sh_cl_glcount1 ; + + assign cl_sh_flr_done = flr_done ; + assign cl_sh_status_vled = status_vled ; + assign cl_sh_apppf_irq_req = irq_req ; + + assign cl_sh_status0 = 0 ; + assign cl_sh_status1 = 0 ; + assign cl_sh_id0 = {C_DEVICE_ID, C_VENDOR_ID} ; + assign cl_sh_id1 = {C_SUBSYSTEM_ID, C_SUBSYSTEM_VENDOR_ID} ; + + assign cl_sh_dma_wr_full = 1'b0; + assign cl_sh_dma_rd_full = 1'b0; + + assign cl_sh_ddr_awid = s_axi_ddrc_awid ; + assign cl_sh_ddr_awaddr = s_axi_ddrc_awaddr ; + assign cl_sh_ddr_awlen = s_axi_ddrc_awlen ; + assign cl_sh_ddr_awsize = s_axi_ddrc_awsize ; + assign cl_sh_ddr_awburst = 2'b01 ; + assign cl_sh_ddr_awvalid = s_axi_ddrc_awvalid ; + assign cl_sh_ddr_wdata = s_axi_ddrc_wdata ; + assign cl_sh_ddr_wstrb = s_axi_ddrc_wstrb ; + assign cl_sh_ddr_wlast = s_axi_ddrc_wlast ; + assign cl_sh_ddr_wvalid = s_axi_ddrc_wvalid ; + assign cl_sh_ddr_bready = s_axi_ddrc_bready ; + assign cl_sh_ddr_arid = s_axi_ddrc_arid ; + assign cl_sh_ddr_araddr = s_axi_ddrc_araddr ; + assign cl_sh_ddr_arlen = s_axi_ddrc_arlen ; + assign cl_sh_ddr_arsize = s_axi_ddrc_arsize ; + assign cl_sh_ddr_arburst = 2'b01 ; + assign cl_sh_ddr_arvalid = s_axi_ddrc_arvalid ; + assign cl_sh_ddr_rready = s_axi_ddrc_rready ; + + assign s_axi_ddrc_awready = sh_cl_ddr_awready ; + assign s_axi_ddrc_wready = sh_cl_ddr_wready ; + assign s_axi_ddrc_bid = sh_cl_ddr_bid ; + assign s_axi_ddrc_bresp = sh_cl_ddr_bresp ; + assign s_axi_ddrc_bvalid = sh_cl_ddr_bvalid ; + assign s_axi_ddrc_arready = sh_cl_ddr_arready ; + assign s_axi_ddrc_rid = sh_cl_ddr_rid ; + assign s_axi_ddrc_rdata = sh_cl_ddr_rdata ; + assign s_axi_ddrc_rresp = sh_cl_ddr_rresp ; + assign s_axi_ddrc_rlast = sh_cl_ddr_rlast ; + assign s_axi_ddrc_rvalid = sh_cl_ddr_rvalid ; + assign ddrc_is_ready = sh_cl_ddr_is_ready ; + + assign cl_sh_ddr_wid = 0 ; + + assign cl_sda_awready = m_axi_sda_awready ; + assign cl_sda_wready = m_axi_sda_wready ; + assign cl_sda_bresp = m_axi_sda_bresp ; + assign cl_sda_bvalid = m_axi_sda_bvalid ; + assign cl_sda_arready = m_axi_sda_arready ; + assign cl_sda_rdata = m_axi_sda_rdata ; + assign cl_sda_rresp = m_axi_sda_rresp ; + assign cl_sda_rvalid = m_axi_sda_rvalid ; + + assign m_axi_sda_awaddr = sda_cl_awaddr ; + assign m_axi_sda_awvalid = sda_cl_awvalid ; + assign m_axi_sda_wdata = sda_cl_wdata ; + assign m_axi_sda_wstrb = sda_cl_wstrb ; + assign m_axi_sda_wvalid = sda_cl_wvalid ; + assign m_axi_sda_bready = sda_cl_bready ; + assign m_axi_sda_araddr = sda_cl_araddr ; + assign m_axi_sda_arvalid = sda_cl_arvalid ; + assign m_axi_sda_rready = sda_cl_rready ; + + assign ocl_sh_awready = m_axi_ocl_awready ; + assign ocl_sh_wready = m_axi_ocl_wready ; + assign ocl_sh_bresp = m_axi_ocl_bresp ; + assign ocl_sh_bvalid = m_axi_ocl_bvalid ; + assign ocl_sh_arready = m_axi_ocl_arready ; + assign ocl_sh_rdata = m_axi_ocl_rdata ; + assign ocl_sh_rresp = m_axi_ocl_rresp ; + assign ocl_sh_rvalid = m_axi_ocl_rvalid ; + + assign m_axi_ocl_awaddr = sh_ocl_awaddr ; + assign m_axi_ocl_awvalid = sh_ocl_awvalid ; + assign m_axi_ocl_wdata = sh_ocl_wdata ; + assign m_axi_ocl_wstrb = sh_ocl_wstrb ; + assign m_axi_ocl_wvalid = sh_ocl_wvalid ; + assign m_axi_ocl_bready = sh_ocl_bready ; + assign m_axi_ocl_araddr = sh_ocl_araddr ; + assign m_axi_ocl_arvalid = sh_ocl_arvalid ; + assign m_axi_ocl_rready = sh_ocl_rready ; + + assign bar1_sh_awready = m_axi_bar1_awready ; + assign bar1_sh_wready = m_axi_bar1_wready ; + assign bar1_sh_bresp = m_axi_bar1_bresp ; + assign bar1_sh_bvalid = m_axi_bar1_bvalid ; + assign bar1_sh_arready = m_axi_bar1_arready ; + assign bar1_sh_rdata = m_axi_bar1_rdata ; + assign bar1_sh_rresp = m_axi_bar1_rresp ; + assign bar1_sh_rvalid = m_axi_bar1_rvalid ; + + assign m_axi_bar1_awaddr = sh_bar1_awaddr ; + assign m_axi_bar1_awvalid = sh_bar1_awvalid ; + assign m_axi_bar1_wdata = sh_bar1_wdata ; + assign m_axi_bar1_wstrb = sh_bar1_wstrb ; + assign m_axi_bar1_wvalid = sh_bar1_wvalid ; + assign m_axi_bar1_bready = sh_bar1_bready ; + assign m_axi_bar1_araddr = sh_bar1_araddr ; + assign m_axi_bar1_arvalid = sh_bar1_arvalid ; + assign m_axi_bar1_rready = sh_bar1_rready ; + + assign cl_sh_dma_pcis_awready = m_axi_pcis_awready ; + assign cl_sh_dma_pcis_wready = m_axi_pcis_wready ; + assign cl_sh_dma_pcis_bid = m_axi_pcis_bid ; + assign cl_sh_dma_pcis_bresp = m_axi_pcis_bresp ; + assign cl_sh_dma_pcis_bvalid = m_axi_pcis_bvalid ; + assign cl_sh_dma_pcis_arready = m_axi_pcis_arready ; + assign cl_sh_dma_pcis_rid = m_axi_pcis_rid ; + assign cl_sh_dma_pcis_rdata = m_axi_pcis_rdata ; + assign cl_sh_dma_pcis_rresp = m_axi_pcis_rresp ; + assign cl_sh_dma_pcis_rlast = m_axi_pcis_rlast ; + assign cl_sh_dma_pcis_rvalid = m_axi_pcis_rvalid ; + + assign m_axi_pcis_awid = sh_cl_dma_pcis_awid ; + assign m_axi_pcis_awaddr = sh_cl_dma_pcis_awaddr ; + assign m_axi_pcis_awlen = sh_cl_dma_pcis_awlen ; + assign m_axi_pcis_awsize = sh_cl_dma_pcis_awsize ; + assign m_axi_pcis_awvalid = sh_cl_dma_pcis_awvalid ; + assign m_axi_pcis_wdata = sh_cl_dma_pcis_wdata ; + assign m_axi_pcis_wstrb = sh_cl_dma_pcis_wstrb ; + assign m_axi_pcis_wlast = sh_cl_dma_pcis_wlast ; + assign m_axi_pcis_wvalid = sh_cl_dma_pcis_wvalid ; + assign m_axi_pcis_bready = sh_cl_dma_pcis_bready ; + assign m_axi_pcis_arid = sh_cl_dma_pcis_arid ; + assign m_axi_pcis_araddr = sh_cl_dma_pcis_araddr ; + assign m_axi_pcis_arlen = sh_cl_dma_pcis_arlen ; + assign m_axi_pcis_arsize = sh_cl_dma_pcis_arsize ; + assign m_axi_pcis_arvalid = sh_cl_dma_pcis_arvalid ; + assign m_axi_pcis_rready = sh_cl_dma_pcis_rready ; + assign m_axi_pcis_awburst = 2'b01 ; + assign m_axi_pcis_arburst = 2'b01 ; + + assign cl_sh_pcim_awid = s_axi_pcim_awid ; + assign cl_sh_pcim_awaddr = s_axi_pcim_awaddr ; + assign cl_sh_pcim_awlen = s_axi_pcim_awlen ; + assign cl_sh_pcim_awsize = s_axi_pcim_awsize ; + assign cl_sh_pcim_awuser = s_axi_pcim_awuser ; + assign cl_sh_pcim_awvalid = s_axi_pcim_awvalid ; + assign cl_sh_pcim_wdata = s_axi_pcim_wdata ; + assign cl_sh_pcim_wstrb = s_axi_pcim_wstrb ; + assign cl_sh_pcim_wlast = s_axi_pcim_wlast ; + assign cl_sh_pcim_wvalid = s_axi_pcim_wvalid ; + assign cl_sh_pcim_bready = s_axi_pcim_bready ; + assign cl_sh_pcim_arid = s_axi_pcim_arid ; + assign cl_sh_pcim_araddr = s_axi_pcim_araddr ; + assign cl_sh_pcim_arlen = s_axi_pcim_arlen ; + assign cl_sh_pcim_arsize = s_axi_pcim_arsize ; + assign cl_sh_pcim_aruser = s_axi_pcim_aruser ; + assign cl_sh_pcim_arvalid = s_axi_pcim_arvalid ; + assign cl_sh_pcim_rready = s_axi_pcim_rready ; + + assign s_axi_pcim_awready = sh_cl_pcim_awready ; + assign s_axi_pcim_wready = sh_cl_pcim_wready ; + assign s_axi_pcim_bid = sh_cl_pcim_bid ; + assign s_axi_pcim_bresp = sh_cl_pcim_bresp ; + assign s_axi_pcim_bvalid = sh_cl_pcim_bvalid ; + assign s_axi_pcim_arready = sh_cl_pcim_arready ; + assign s_axi_pcim_rid = sh_cl_pcim_rid ; + assign s_axi_pcim_rdata = sh_cl_pcim_rdata ; + assign s_axi_pcim_rresp = sh_cl_pcim_rresp ; + assign s_axi_pcim_rlast = sh_cl_pcim_rlast ; + assign s_axi_pcim_rvalid = sh_cl_pcim_rvalid ; + assign cfg_max_payload_out = cfg_max_payload ; + assign cfg_max_read_req_out = cfg_max_read_req ; + + if ((C_MODE == 0) || (C_MODE == 1)) begin : gen_mem + + logic [15:0] cl_sh_ddr_awid_2d[2:0]; + logic [63:0] cl_sh_ddr_awaddr_2d[2:0]; + logic [7:0] cl_sh_ddr_awlen_2d[2:0]; + logic [2:0] cl_sh_ddr_awsize_2d[2:0]; + logic [1:0] cl_sh_ddr_awburst_2d[2:0]; + logic cl_sh_ddr_awvalid_2d[2:0]; + logic [2:0] sh_cl_ddr_awready_2d; + logic [15:0] cl_sh_ddr_wid_2d[2:0]; + logic [511:0] cl_sh_ddr_wdata_2d[2:0]; + logic [63:0] cl_sh_ddr_wstrb_2d[2:0]; + logic [2:0] cl_sh_ddr_wlast_2d; + logic [2:0] cl_sh_ddr_wvalid_2d; + logic [2:0] sh_cl_ddr_wready_2d; + logic [15:0] sh_cl_ddr_bid_2d[2:0]; + logic [1:0] sh_cl_ddr_bresp_2d[2:0]; + logic [2:0] sh_cl_ddr_bvalid_2d; + logic [2:0] cl_sh_ddr_bready_2d; + logic [15:0] cl_sh_ddr_arid_2d[2:0]; + logic [63:0] cl_sh_ddr_araddr_2d[2:0]; + logic [7:0] cl_sh_ddr_arlen_2d[2:0]; + logic [2:0] cl_sh_ddr_arsize_2d[2:0]; + logic [1:0] cl_sh_ddr_arburst_2d[2:0]; + logic [2:0] cl_sh_ddr_arvalid_2d; + logic [2:0] sh_cl_ddr_arready_2d; + logic [15:0] sh_cl_ddr_rid_2d[2:0]; + logic [511:0] sh_cl_ddr_rdata_2d[2:0]; + logic [1:0] sh_cl_ddr_rresp_2d[2:0]; + logic [2:0] sh_cl_ddr_rlast_2d; + logic [2:0] sh_cl_ddr_rvalid_2d; + logic [2:0] cl_sh_ddr_rready_2d; + logic [2:0] sh_cl_ddr_is_ready_2d; + + assign cl_sh_ddr_awid_2d[0] = s_axi_ddra_awid ; + assign cl_sh_ddr_awaddr_2d[0] = s_axi_ddra_awaddr ; + assign cl_sh_ddr_awlen_2d[0] = s_axi_ddra_awlen ; + assign cl_sh_ddr_awsize_2d[0] = s_axi_ddra_awsize ; + assign cl_sh_ddr_awburst_2d[0] = 2'b01 ; + assign cl_sh_ddr_awvalid_2d[0] = s_axi_ddra_awvalid ; + assign cl_sh_ddr_wid_2d[0] = 0 ; + assign cl_sh_ddr_wdata_2d[0] = s_axi_ddra_wdata ; + assign cl_sh_ddr_wstrb_2d[0] = s_axi_ddra_wstrb ; + assign cl_sh_ddr_wlast_2d[0] = s_axi_ddra_wlast ; + assign cl_sh_ddr_wvalid_2d[0] = s_axi_ddra_wvalid ; + assign cl_sh_ddr_bready_2d[0] = s_axi_ddra_bready ; + assign cl_sh_ddr_arid_2d[0] = s_axi_ddra_arid ; + assign cl_sh_ddr_araddr_2d[0] = s_axi_ddra_araddr ; + assign cl_sh_ddr_arlen_2d[0] = s_axi_ddra_arlen ; + assign cl_sh_ddr_arsize_2d[0] = s_axi_ddra_arsize ; + assign cl_sh_ddr_arburst_2d[0] = 2'b01 ; + assign cl_sh_ddr_arvalid_2d[0] = s_axi_ddra_arvalid ; + assign cl_sh_ddr_rready_2d[0] = s_axi_ddra_rready ; + + assign s_axi_ddra_awready = sh_cl_ddr_awready_2d[0] ; + assign s_axi_ddra_wready = sh_cl_ddr_wready_2d[0] ; + assign s_axi_ddra_bid = sh_cl_ddr_bid_2d[0] ; + assign s_axi_ddra_bresp = sh_cl_ddr_bresp_2d[0] ; + assign s_axi_ddra_bvalid = sh_cl_ddr_bvalid_2d[0] ; + assign s_axi_ddra_arready = sh_cl_ddr_arready_2d[0] ; + assign s_axi_ddra_rid = sh_cl_ddr_rid_2d[0] ; + assign s_axi_ddra_rdata = sh_cl_ddr_rdata_2d[0] ; + assign s_axi_ddra_rresp = sh_cl_ddr_rresp_2d[0] ; + assign s_axi_ddra_rlast = sh_cl_ddr_rlast_2d[0] ; + assign s_axi_ddra_rvalid = sh_cl_ddr_rvalid_2d[0] ; + assign ddra_is_ready = sh_cl_ddr_is_ready_2d[0]; + + assign cl_sh_ddr_awid_2d[1] = s_axi_ddrb_awid ; + assign cl_sh_ddr_awaddr_2d[1] = s_axi_ddrb_awaddr ; + assign cl_sh_ddr_awlen_2d[1] = s_axi_ddrb_awlen ; + assign cl_sh_ddr_awsize_2d[1] = s_axi_ddrb_awsize ; + assign cl_sh_ddr_awburst_2d[1] = 2'b01 ; + assign cl_sh_ddr_awvalid_2d[1] = s_axi_ddrb_awvalid ; + assign cl_sh_ddr_wid_2d[1] = 0 ; + assign cl_sh_ddr_wdata_2d[1] = s_axi_ddrb_wdata ; + assign cl_sh_ddr_wstrb_2d[1] = s_axi_ddrb_wstrb ; + assign cl_sh_ddr_wlast_2d[1] = s_axi_ddrb_wlast ; + assign cl_sh_ddr_wvalid_2d[1] = s_axi_ddrb_wvalid ; + assign cl_sh_ddr_bready_2d[1] = s_axi_ddrb_bready ; + assign cl_sh_ddr_arid_2d[1] = s_axi_ddrb_arid ; + assign cl_sh_ddr_araddr_2d[1] = s_axi_ddrb_araddr ; + assign cl_sh_ddr_arlen_2d[1] = s_axi_ddrb_arlen ; + assign cl_sh_ddr_arsize_2d[1] = s_axi_ddrb_arsize ; + assign cl_sh_ddr_arburst_2d[1] = 2'b01 ; + assign cl_sh_ddr_arvalid_2d[1] = s_axi_ddrb_arvalid ; + assign cl_sh_ddr_rready_2d[1] = s_axi_ddrb_rready ; + + assign s_axi_ddrb_awready = sh_cl_ddr_awready_2d[1] ; + assign s_axi_ddrb_wready = sh_cl_ddr_wready_2d[1] ; + assign s_axi_ddrb_bid = sh_cl_ddr_bid_2d[1] ; + assign s_axi_ddrb_bresp = sh_cl_ddr_bresp_2d[1] ; + assign s_axi_ddrb_bvalid = sh_cl_ddr_bvalid_2d[1] ; + assign s_axi_ddrb_arready = sh_cl_ddr_arready_2d[1] ; + assign s_axi_ddrb_rid = sh_cl_ddr_rid_2d[1] ; + assign s_axi_ddrb_rdata = sh_cl_ddr_rdata_2d[1] ; + assign s_axi_ddrb_rresp = sh_cl_ddr_rresp_2d[1] ; + assign s_axi_ddrb_rlast = sh_cl_ddr_rlast_2d[1] ; + assign s_axi_ddrb_rvalid = sh_cl_ddr_rvalid_2d[1] ; + assign ddrb_is_ready = sh_cl_ddr_is_ready_2d[1]; + + assign cl_sh_ddr_awid_2d[2] = s_axi_ddrd_awid ; + assign cl_sh_ddr_awaddr_2d[2] = s_axi_ddrd_awaddr ; + assign cl_sh_ddr_awlen_2d[2] = s_axi_ddrd_awlen ; + assign cl_sh_ddr_awsize_2d[2] = s_axi_ddrd_awsize ; + assign cl_sh_ddr_awburst_2d[2] = 2'b01 ; + assign cl_sh_ddr_awvalid_2d[2] = s_axi_ddrd_awvalid ; + assign cl_sh_ddr_wid_2d[2] = 0 ; + assign cl_sh_ddr_wdata_2d[2] = s_axi_ddrd_wdata ; + assign cl_sh_ddr_wstrb_2d[2] = s_axi_ddrd_wstrb ; + assign cl_sh_ddr_wlast_2d[2] = s_axi_ddrd_wlast ; + assign cl_sh_ddr_wvalid_2d[2] = s_axi_ddrd_wvalid ; + assign cl_sh_ddr_bready_2d[2] = s_axi_ddrd_bready ; + assign cl_sh_ddr_arid_2d[2] = s_axi_ddrd_arid ; + assign cl_sh_ddr_araddr_2d[2] = s_axi_ddrd_araddr ; + assign cl_sh_ddr_arlen_2d[2] = s_axi_ddrd_arlen ; + assign cl_sh_ddr_arsize_2d[2] = s_axi_ddrd_arsize ; + assign cl_sh_ddr_arburst_2d[2] = 2'b01 ; + assign cl_sh_ddr_arvalid_2d[2] = s_axi_ddrd_arvalid ; + assign cl_sh_ddr_rready_2d[2] = s_axi_ddrd_rready ; + + assign s_axi_ddrd_awready = sh_cl_ddr_awready_2d[2] ; + assign s_axi_ddrd_wready = sh_cl_ddr_wready_2d[2] ; + assign s_axi_ddrd_bid = sh_cl_ddr_bid_2d[2] ; + assign s_axi_ddrd_bresp = sh_cl_ddr_bresp_2d[2] ; + assign s_axi_ddrd_bvalid = sh_cl_ddr_bvalid_2d[2] ; + assign s_axi_ddrd_arready = sh_cl_ddr_arready_2d[2] ; + assign s_axi_ddrd_rid = sh_cl_ddr_rid_2d[2] ; + assign s_axi_ddrd_rdata = sh_cl_ddr_rdata_2d[2] ; + assign s_axi_ddrd_rresp = sh_cl_ddr_rresp_2d[2] ; + assign s_axi_ddrd_rlast = sh_cl_ddr_rlast_2d[2] ; + assign s_axi_ddrd_rvalid = sh_cl_ddr_rvalid_2d[2] ; + assign ddrd_is_ready = sh_cl_ddr_is_ready_2d[2]; + + logic ddr_aws_stat_ack0; + logic [31:0] ddr_aws_stat_rdata0; + logic [7:0] ddr_aws_stat_int0; + logic ddr_aws_stat_ack1; + logic [31:0] ddr_aws_stat_rdata1; + logic [7:0] ddr_aws_stat_int1; + logic ddr_aws_stat_ack2; + logic [31:0] ddr_aws_stat_rdata2; + logic [7:0] ddr_aws_stat_int2; + + logic [7:0] pipe_ddr_stat_addr0; + logic pipe_ddr_stat_wr0; + logic pipe_ddr_stat_rd0; + logic [31:0] pipe_ddr_stat_wdata0; + logic ddr_pipe_stat_ack0; + logic [31:0] ddr_pipe_stat_rdata0; + logic [7:0] ddr_pipe_stat_int0; + + logic [7:0] pipe_ddr_stat_addr1; + logic pipe_ddr_stat_wr1; + logic pipe_ddr_stat_rd1; + logic [31:0] pipe_ddr_stat_wdata1; + logic ddr_pipe_stat_ack1; + logic [31:0] ddr_pipe_stat_rdata1; + logic [7:0] ddr_pipe_stat_int1; + + logic [7:0] pipe_ddr_stat_addr2; + logic pipe_ddr_stat_wr2; + logic pipe_ddr_stat_rd2; + logic [31:0] pipe_ddr_stat_wdata2; + logic ddr_pipe_stat_ack2; + logic [31:0] ddr_pipe_stat_rdata2; + logic [7:0] ddr_pipe_stat_int2; + +//------------------------------------------------- +// Tie-offs when DDRs are disabled +//------------------------------------------------- + assign ddr_sh_stat_ack0 = (C_DDR_A_PRESENT!=0) ? ddr_aws_stat_ack0 : 1'b1; + assign ddr_sh_stat_rdata0 = (C_DDR_A_PRESENT!=0) ? ddr_aws_stat_rdata0 : 0; + assign ddr_sh_stat_int0 = (C_DDR_A_PRESENT!=0) ? ddr_aws_stat_int0 : 8'b0; + assign ddr_sh_stat_ack1 = (C_DDR_B_PRESENT!=0) ? ddr_aws_stat_ack1 : 1'b1; + assign ddr_sh_stat_rdata1 = (C_DDR_B_PRESENT!=0) ? ddr_aws_stat_rdata1 : 0; + assign ddr_sh_stat_int1 = (C_DDR_B_PRESENT!=0) ? ddr_aws_stat_int1 : 8'b0; + assign ddr_sh_stat_ack2 = (C_DDR_D_PRESENT!=0) ? ddr_aws_stat_ack2 : 1'b1; + assign ddr_sh_stat_rdata2 = (C_DDR_D_PRESENT!=0) ? ddr_aws_stat_rdata2 : 0; + assign ddr_sh_stat_int2 = (C_DDR_D_PRESENT!=0) ? ddr_aws_stat_int2 : 8'b0; + +//------------------------------------------------- +// Reset Synchronization +//------------------------------------------------- + logic pre_sync_rst_n; + logic sync_rst_n; + + always @(negedge rst_main_n or posedge clk_main_a0) begin + if (!rst_main_n) begin + pre_sync_rst_n <= 1'b0; + sync_rst_n <= 1'b0; + end else begin + pre_sync_rst_n <= 1'b1; + sync_rst_n <= pre_sync_rst_n; + end + end + + `ifdef FPGA_LESS_RST + `undef FPGA_LESS_RST + `endif + + lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wdata0 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_wdata0), .out_bus(pipe_ddr_stat_wdata0)); + lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_addr0 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_addr0), .out_bus(pipe_ddr_stat_addr0)); + lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wr0 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_wr0), .out_bus(pipe_ddr_stat_wr0)); + lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rd0 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_rd0), .out_bus(pipe_ddr_stat_rd0)); + lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rdata0 (.clk(clk_main_a0), .rst_n(1'b1), .out_bus(ddr_aws_stat_rdata0), .in_bus(ddr_pipe_stat_rdata0)); + lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_ack0 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_ack0), .in_bus(ddr_pipe_stat_ack0)); + lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_int0 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_int0), .in_bus(ddr_pipe_stat_int0)); + + lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wdata1 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_wdata1), .out_bus(pipe_ddr_stat_wdata1)); + lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_addr1 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_addr1), .out_bus(pipe_ddr_stat_addr1)); + lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wr1 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_wr1), .out_bus(pipe_ddr_stat_wr1)); + lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rd1 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_rd1), .out_bus(pipe_ddr_stat_rd1)); + lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rdata1 (.clk(clk_main_a0), .rst_n(1'b1), .out_bus(ddr_aws_stat_rdata1), .in_bus(ddr_pipe_stat_rdata1)); + lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_ack1 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_ack1), .in_bus(ddr_pipe_stat_ack1)); + lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_int1 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_int1), .in_bus(ddr_pipe_stat_int1)); + + lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wdata2 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_wdata2), .out_bus(pipe_ddr_stat_wdata2)); + lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_addr2 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_addr2), .out_bus(pipe_ddr_stat_addr2)); + lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wr2 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_wr2), .out_bus(pipe_ddr_stat_wr2)); + lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rd2 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_rd2), .out_bus(pipe_ddr_stat_rd2)); + lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rdata2 (.clk(clk_main_a0), .rst_n(1'b1), .out_bus(ddr_aws_stat_rdata2), .in_bus(ddr_pipe_stat_rdata2)); + lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_ack2 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_ack2), .in_bus(ddr_pipe_stat_ack2)); + lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_int2 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_int2), .in_bus(ddr_pipe_stat_int2)); + + sh_ddr #( + .DDR_A_PRESENT(C_DDR_A_PRESENT), + .DDR_B_PRESENT(C_DDR_B_PRESENT), + .DDR_D_PRESENT(C_DDR_D_PRESENT) + ) sh_ddr_0 + ( + .clk(clk_main_a0), + .rst_n(sync_rst_n), + + .stat_clk(clk_main_a0), + .stat_rst_n(sync_rst_n), + + .CLK_300M_DIMM0_DP(CLK_300M_DIMM0_DP), + .CLK_300M_DIMM0_DN(CLK_300M_DIMM0_DN), + .M_A_ACT_N(M_A_ACT_N), + .M_A_MA(M_A_MA), + .M_A_BA(M_A_BA), + .M_A_BG(M_A_BG), + .M_A_CKE(M_A_CKE), + .M_A_ODT(M_A_ODT), + .M_A_CS_N(M_A_CS_N), + .M_A_CLK_DN(M_A_CLK_DN), + .M_A_CLK_DP(M_A_CLK_DP), + .M_A_PAR(M_A_PAR), + .M_A_DQ(M_A_DQ), + .M_A_ECC(M_A_ECC), + .M_A_DQS_DP(M_A_DQS_DP), + .M_A_DQS_DN(M_A_DQS_DN), + .cl_RST_DIMM_A_N(cl_RST_DIMM_A_N), + + .CLK_300M_DIMM1_DP(CLK_300M_DIMM1_DP), + .CLK_300M_DIMM1_DN(CLK_300M_DIMM1_DN), + .M_B_ACT_N(M_B_ACT_N), + .M_B_MA(M_B_MA), + .M_B_BA(M_B_BA), + .M_B_BG(M_B_BG), + .M_B_CKE(M_B_CKE), + .M_B_ODT(M_B_ODT), + .M_B_CS_N(M_B_CS_N), + .M_B_CLK_DN(M_B_CLK_DN), + .M_B_CLK_DP(M_B_CLK_DP), + .M_B_PAR(M_B_PAR), + .M_B_DQ(M_B_DQ), + .M_B_ECC(M_B_ECC), + .M_B_DQS_DP(M_B_DQS_DP), + .M_B_DQS_DN(M_B_DQS_DN), + .cl_RST_DIMM_B_N(cl_RST_DIMM_B_N), + + .CLK_300M_DIMM3_DP(CLK_300M_DIMM3_DP), + .CLK_300M_DIMM3_DN(CLK_300M_DIMM3_DN), + .M_D_ACT_N(M_D_ACT_N), + .M_D_MA(M_D_MA), + .M_D_BA(M_D_BA), + .M_D_BG(M_D_BG), + .M_D_CKE(M_D_CKE), + .M_D_ODT(M_D_ODT), + .M_D_CS_N(M_D_CS_N), + .M_D_CLK_DN(M_D_CLK_DN), + .M_D_CLK_DP(M_D_CLK_DP), + .M_D_PAR(M_D_PAR), + .M_D_DQ(M_D_DQ), + .M_D_ECC(M_D_ECC), + .M_D_DQS_DP(M_D_DQS_DP), + .M_D_DQS_DN(M_D_DQS_DN), + .cl_RST_DIMM_D_N(cl_RST_DIMM_D_N), + + //------------------------------------------------------ + // AXI Slave Interfaces + //------------------------------------------------------ + .cl_sh_ddr_awid(cl_sh_ddr_awid_2d), + .cl_sh_ddr_awaddr(cl_sh_ddr_awaddr_2d), + .cl_sh_ddr_awlen(cl_sh_ddr_awlen_2d), + .cl_sh_ddr_awsize(cl_sh_ddr_awsize_2d), + .cl_sh_ddr_awburst(cl_sh_ddr_awburst_2d), + .cl_sh_ddr_awvalid(cl_sh_ddr_awvalid_2d), + .sh_cl_ddr_awready(sh_cl_ddr_awready_2d), + + .cl_sh_ddr_wid(cl_sh_ddr_wid_2d), + .cl_sh_ddr_wdata(cl_sh_ddr_wdata_2d), + .cl_sh_ddr_wstrb(cl_sh_ddr_wstrb_2d), + .cl_sh_ddr_wlast(cl_sh_ddr_wlast_2d), + .cl_sh_ddr_wvalid(cl_sh_ddr_wvalid_2d), + .sh_cl_ddr_wready(sh_cl_ddr_wready_2d), + + .sh_cl_ddr_bid(sh_cl_ddr_bid_2d), + .sh_cl_ddr_bresp(sh_cl_ddr_bresp_2d), + .sh_cl_ddr_bvalid(sh_cl_ddr_bvalid_2d), + .cl_sh_ddr_bready(cl_sh_ddr_bready_2d), + + .cl_sh_ddr_arid(cl_sh_ddr_arid_2d), + .cl_sh_ddr_araddr(cl_sh_ddr_araddr_2d), + .cl_sh_ddr_arlen(cl_sh_ddr_arlen_2d), + .cl_sh_ddr_arsize(cl_sh_ddr_arsize_2d), + .cl_sh_ddr_arburst(cl_sh_ddr_arburst_2d), + .cl_sh_ddr_arvalid(cl_sh_ddr_arvalid_2d), + .sh_cl_ddr_arready(sh_cl_ddr_arready_2d), + + .sh_cl_ddr_rid(sh_cl_ddr_rid_2d), + .sh_cl_ddr_rdata(sh_cl_ddr_rdata_2d), + .sh_cl_ddr_rresp(sh_cl_ddr_rresp_2d), + .sh_cl_ddr_rlast(sh_cl_ddr_rlast_2d), + .sh_cl_ddr_rvalid(sh_cl_ddr_rvalid_2d), + .cl_sh_ddr_rready(cl_sh_ddr_rready_2d), + + .sh_cl_ddr_is_ready(sh_cl_ddr_is_ready_2d), + + .sh_ddr_stat_addr0 (pipe_ddr_stat_addr0 ), + .sh_ddr_stat_wr0 (pipe_ddr_stat_wr0 ), + .sh_ddr_stat_rd0 (pipe_ddr_stat_rd0 ), + .sh_ddr_stat_wdata0 (pipe_ddr_stat_wdata0), + .ddr_sh_stat_ack0 (ddr_pipe_stat_ack0 ), + .ddr_sh_stat_rdata0 (ddr_pipe_stat_rdata0), + .ddr_sh_stat_int0 (ddr_pipe_stat_int0 ), + + .sh_ddr_stat_addr1 (pipe_ddr_stat_addr1 ), + .sh_ddr_stat_wr1 (pipe_ddr_stat_wr1 ), + .sh_ddr_stat_rd1 (pipe_ddr_stat_rd1 ), + .sh_ddr_stat_wdata1 (pipe_ddr_stat_wdata1), + .ddr_sh_stat_ack1 (ddr_pipe_stat_ack1 ), + .ddr_sh_stat_rdata1 (ddr_pipe_stat_rdata1), + .ddr_sh_stat_int1 (ddr_pipe_stat_int1 ), + + .sh_ddr_stat_addr2 (pipe_ddr_stat_addr2 ), + .sh_ddr_stat_wr2 (pipe_ddr_stat_wr2 ), + .sh_ddr_stat_rd2 (pipe_ddr_stat_rd2 ), + .sh_ddr_stat_wdata2 (pipe_ddr_stat_wdata2), + .ddr_sh_stat_ack2 (ddr_pipe_stat_ack2 ), + .ddr_sh_stat_rdata2 (ddr_pipe_stat_rdata2), + .ddr_sh_stat_int2 (ddr_pipe_stat_int2 ) + + ); + + end else begin : gen_non_mem + + assign s_axi_ddra_awready = 0; + assign s_axi_ddra_wready = 0; + assign s_axi_ddra_bid = 0; + assign s_axi_ddra_bresp = 0; + assign s_axi_ddra_bvalid = 0; + assign s_axi_ddra_arready = 0; + assign s_axi_ddra_rid = 0; + assign s_axi_ddra_rdata = 0; + assign s_axi_ddra_rresp = 0; + assign s_axi_ddra_rlast = 1'b1; + assign s_axi_ddra_rvalid = 0; + assign ddra_is_ready = 0; + + assign s_axi_ddrb_awready = 0; + assign s_axi_ddrb_wready = 0; + assign s_axi_ddrb_bid = 0; + assign s_axi_ddrb_bresp = 0; + assign s_axi_ddrb_bvalid = 0; + assign s_axi_ddrb_arready = 0; + assign s_axi_ddrb_rid = 0; + assign s_axi_ddrb_rdata = 0; + assign s_axi_ddrb_rresp = 0; + assign s_axi_ddrb_rlast = 1'b1; + assign s_axi_ddrb_rvalid = 0; + assign ddrb_is_ready = 0; + + assign s_axi_ddrd_awready = 0; + assign s_axi_ddrd_wready = 0; + assign s_axi_ddrd_bid = 0; + assign s_axi_ddrd_bresp = 0; + assign s_axi_ddrd_bvalid = 0; + assign s_axi_ddrd_arready = 0; + assign s_axi_ddrd_rid = 0; + assign s_axi_ddrd_rdata = 0; + assign s_axi_ddrd_rresp = 0; + assign s_axi_ddrd_rlast = 1'b1; + assign s_axi_ddrd_rvalid = 0; + assign ddrd_is_ready = 0; + + assign ddr_sh_stat_ack0 = 1'b1; + assign ddr_sh_stat_rdata0 = 0; + assign ddr_sh_stat_int0 = 8'b0; + assign ddr_sh_stat_ack1 = 1'b1; + assign ddr_sh_stat_rdata1 = 0; + assign ddr_sh_stat_int1 = 8'b0; + assign ddr_sh_stat_ack2 = 1'b1; + assign ddr_sh_stat_rdata2 = 0; + assign ddr_sh_stat_int2 = 8'b0; + + assign M_A_ACT_N = 0; + assign M_A_MA = 0; + assign M_A_BA = 0; + assign M_A_BG = 0; + assign M_A_CKE = 0; + assign M_A_ODT = 0; + assign M_A_CS_N = 0; + assign M_A_CLK_DN = 0; + assign M_A_CLK_DP = 0; + assign M_A_PAR = 0; + assign cl_RST_DIMM_A_N = 0; + + assign M_B_ACT_N = 0; + assign M_B_MA = 0; + assign M_B_BA = 0; + assign M_B_BG = 0; + assign M_B_CKE = 0; + assign M_B_ODT = 0; + assign M_B_CS_N = 0; + assign M_B_CLK_DN = 0; + assign M_B_CLK_DP = 0; + assign M_B_PAR = 0; + assign cl_RST_DIMM_B_N = 0; + + assign M_D_ACT_N = 0; + assign M_D_MA = 0; + assign M_D_BA = 0; + assign M_D_BG = 0; + assign M_D_CKE = 0; + assign M_D_ODT = 0; + assign M_D_CS_N = 0; + assign M_D_CLK_DN = 0; + assign M_D_CLK_DP = 0; + assign M_D_PAR = 0; + assign cl_RST_DIMM_D_N = 0; + + end // gen_mem + endgenerate + +endmodule diff --git a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/aws_v1_0_vl_rfs.sv b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/aws_v1_0_vl_rfs.sv deleted file mode 100755 index edf00b8c..00000000 --- a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/aws_v1_0_vl_rfs.sv +++ /dev/null @@ -1,3076 +0,0 @@ -//---------------------------------------------------------------------------------- -//Copyright (c) 2014 -// -//Permission is hereby granted, free of charge, to any person obtaining a copy -//of this software and associated documentation files (the "Software"), to deal -//in the Software without restriction, including without limitation the rights -//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -//copies of the Software, and to permit persons to whom the Software is -//furnished to do so, subject to the following conditions: -// -//The above copyright notice and this permission notice shall be included in -//all copies or substantial portions of the Software. -// -//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -//THE SOFTWARE. -//---------------------------------------------------------------------------------- - -//simple pipeline - -//WIDTH is the width of the DATA -//STAGES is the number of stages (flops in the pipeline) -module lib_pipe #(parameter WIDTH=8, parameter STAGES=1) ( - input clk, - input rst_n, - - input[WIDTH-1:0] in_bus, - - output [WIDTH-1:0] out_bus - ); - -//Note the shreg_extract=no directs Xilinx to not infer shift registers which -// defeats using this as a pipeline - - -`ifdef FPGA_LESS_RST - (*shreg_extract="no"*) logic [WIDTH-1:0] pipe[STAGES-1:0] = '{default:'0}; -`else - (*shreg_extract="no"*) logic [WIDTH-1:0] pipe[STAGES-1:0]; -`endif - -//(*srl_style="register"*) logic [WIDTH-1:0] pipe [STAGES-1:0]; -// logic [WIDTH-1:0] pipe [STAGES-1:0]; - - integer i; - -`ifdef FPGA_LESS_RST - always @(posedge clk) -`else - always @(negedge rst_n or posedge clk) - if (!rst_n) - begin - for (i=0; i1) - begin - for (i=1; i1 ? clk_extra_a1 : 1'b0 ; - assign clk_extra_a2_out = C_NUM_A_CLOCKS>2 ? clk_extra_a2 : 1'b0 ; - assign clk_extra_a3_out = C_NUM_A_CLOCKS>3 ? clk_extra_a3 : 1'b0 ; - assign clk_extra_b0_out = C_NUM_B_CLOCKS>0 ? clk_extra_b0 : 1'b0 ; - assign clk_extra_b1_out = C_NUM_B_CLOCKS>1 ? clk_extra_b1 : 1'b0 ; - assign clk_extra_c0_out = C_NUM_C_CLOCKS>0 ? clk_extra_c0 : 1'b0 ; - assign clk_extra_c1_out = C_NUM_C_CLOCKS>1 ? clk_extra_c1 : 1'b0 ; - assign rst_main_n_out = rst_main_n ; - assign kernel_rst_n_out = kernel_rst_n ; - assign flr_assert = sh_cl_flr_assert ; - assign status_vdip = sh_cl_status_vdip ; - assign irq_ack = sh_cl_apppf_irq_ack ; - assign glcount0 = sh_cl_glcount0 ; - assign glcount1 = sh_cl_glcount1 ; - - assign cl_sh_flr_done = flr_done ; - assign cl_sh_status_vled = status_vled ; - assign cl_sh_apppf_irq_req = irq_req ; - - assign cl_sh_status0 = 0 ; - assign cl_sh_status1 = 0 ; - assign cl_sh_id0 = {C_DEVICE_ID, C_VENDOR_ID} ; - assign cl_sh_id1 = {C_SUBSYSTEM_ID, C_SUBSYSTEM_VENDOR_ID} ; - - assign cl_sh_dma_wr_full = 1'b0; - assign cl_sh_dma_rd_full = 1'b0; - - assign cl_sh_ddr_awid = s_axi_ddrc_awid ; - assign cl_sh_ddr_awaddr = s_axi_ddrc_awaddr ; - assign cl_sh_ddr_awlen = s_axi_ddrc_awlen ; - assign cl_sh_ddr_awsize = s_axi_ddrc_awsize ; - assign cl_sh_ddr_awburst = 2'b01 ; - assign cl_sh_ddr_awvalid = s_axi_ddrc_awvalid ; - assign cl_sh_ddr_wdata = s_axi_ddrc_wdata ; - assign cl_sh_ddr_wstrb = s_axi_ddrc_wstrb ; - assign cl_sh_ddr_wlast = s_axi_ddrc_wlast ; - assign cl_sh_ddr_wvalid = s_axi_ddrc_wvalid ; - assign cl_sh_ddr_bready = s_axi_ddrc_bready ; - assign cl_sh_ddr_arid = s_axi_ddrc_arid ; - assign cl_sh_ddr_araddr = s_axi_ddrc_araddr ; - assign cl_sh_ddr_arlen = s_axi_ddrc_arlen ; - assign cl_sh_ddr_arsize = s_axi_ddrc_arsize ; - assign cl_sh_ddr_arburst = 2'b01 ; - assign cl_sh_ddr_arvalid = s_axi_ddrc_arvalid ; - assign cl_sh_ddr_rready = s_axi_ddrc_rready ; - - assign s_axi_ddrc_awready = sh_cl_ddr_awready ; - assign s_axi_ddrc_wready = sh_cl_ddr_wready ; - assign s_axi_ddrc_bid = sh_cl_ddr_bid ; - assign s_axi_ddrc_bresp = sh_cl_ddr_bresp ; - assign s_axi_ddrc_bvalid = sh_cl_ddr_bvalid ; - assign s_axi_ddrc_arready = sh_cl_ddr_arready ; - assign s_axi_ddrc_rid = sh_cl_ddr_rid ; - assign s_axi_ddrc_rdata = sh_cl_ddr_rdata ; - assign s_axi_ddrc_rresp = sh_cl_ddr_rresp ; - assign s_axi_ddrc_rlast = sh_cl_ddr_rlast ; - assign s_axi_ddrc_rvalid = sh_cl_ddr_rvalid ; - assign ddrc_is_ready = sh_cl_ddr_is_ready ; - - assign cl_sh_ddr_wid = 0 ; - - assign cl_sda_awready = m_axi_sda_awready ; - assign cl_sda_wready = m_axi_sda_wready ; - assign cl_sda_bresp = m_axi_sda_bresp ; - assign cl_sda_bvalid = m_axi_sda_bvalid ; - assign cl_sda_arready = m_axi_sda_arready ; - assign cl_sda_rdata = m_axi_sda_rdata ; - assign cl_sda_rresp = m_axi_sda_rresp ; - assign cl_sda_rvalid = m_axi_sda_rvalid ; - - assign m_axi_sda_awaddr = sda_cl_awaddr ; - assign m_axi_sda_awvalid = sda_cl_awvalid ; - assign m_axi_sda_wdata = sda_cl_wdata ; - assign m_axi_sda_wstrb = sda_cl_wstrb ; - assign m_axi_sda_wvalid = sda_cl_wvalid ; - assign m_axi_sda_bready = sda_cl_bready ; - assign m_axi_sda_araddr = sda_cl_araddr ; - assign m_axi_sda_arvalid = sda_cl_arvalid ; - assign m_axi_sda_rready = sda_cl_rready ; - - assign ocl_sh_awready = m_axi_ocl_awready ; - assign ocl_sh_wready = m_axi_ocl_wready ; - assign ocl_sh_bresp = m_axi_ocl_bresp ; - assign ocl_sh_bvalid = m_axi_ocl_bvalid ; - assign ocl_sh_arready = m_axi_ocl_arready ; - assign ocl_sh_rdata = m_axi_ocl_rdata ; - assign ocl_sh_rresp = m_axi_ocl_rresp ; - assign ocl_sh_rvalid = m_axi_ocl_rvalid ; - - assign m_axi_ocl_awaddr = sh_ocl_awaddr ; - assign m_axi_ocl_awvalid = sh_ocl_awvalid ; - assign m_axi_ocl_wdata = sh_ocl_wdata ; - assign m_axi_ocl_wstrb = sh_ocl_wstrb ; - assign m_axi_ocl_wvalid = sh_ocl_wvalid ; - assign m_axi_ocl_bready = sh_ocl_bready ; - assign m_axi_ocl_araddr = sh_ocl_araddr ; - assign m_axi_ocl_arvalid = sh_ocl_arvalid ; - assign m_axi_ocl_rready = sh_ocl_rready ; - - assign bar1_sh_awready = m_axi_bar1_awready ; - assign bar1_sh_wready = m_axi_bar1_wready ; - assign bar1_sh_bresp = m_axi_bar1_bresp ; - assign bar1_sh_bvalid = m_axi_bar1_bvalid ; - assign bar1_sh_arready = m_axi_bar1_arready ; - assign bar1_sh_rdata = m_axi_bar1_rdata ; - assign bar1_sh_rresp = m_axi_bar1_rresp ; - assign bar1_sh_rvalid = m_axi_bar1_rvalid ; - - assign m_axi_bar1_awaddr = sh_bar1_awaddr ; - assign m_axi_bar1_awvalid = sh_bar1_awvalid ; - assign m_axi_bar1_wdata = sh_bar1_wdata ; - assign m_axi_bar1_wstrb = sh_bar1_wstrb ; - assign m_axi_bar1_wvalid = sh_bar1_wvalid ; - assign m_axi_bar1_bready = sh_bar1_bready ; - assign m_axi_bar1_araddr = sh_bar1_araddr ; - assign m_axi_bar1_arvalid = sh_bar1_arvalid ; - assign m_axi_bar1_rready = sh_bar1_rready ; - - assign cl_sh_dma_pcis_awready = m_axi_pcis_awready ; - assign cl_sh_dma_pcis_wready = m_axi_pcis_wready ; - assign cl_sh_dma_pcis_bid = m_axi_pcis_bid ; - assign cl_sh_dma_pcis_bresp = m_axi_pcis_bresp ; - assign cl_sh_dma_pcis_bvalid = m_axi_pcis_bvalid ; - assign cl_sh_dma_pcis_arready = m_axi_pcis_arready ; - assign cl_sh_dma_pcis_rid = m_axi_pcis_rid ; - assign cl_sh_dma_pcis_rdata = m_axi_pcis_rdata ; - assign cl_sh_dma_pcis_rresp = m_axi_pcis_rresp ; - assign cl_sh_dma_pcis_rlast = m_axi_pcis_rlast ; - assign cl_sh_dma_pcis_rvalid = m_axi_pcis_rvalid ; - - assign m_axi_pcis_awid = sh_cl_dma_pcis_awid ; - assign m_axi_pcis_awaddr = sh_cl_dma_pcis_awaddr ; - assign m_axi_pcis_awlen = sh_cl_dma_pcis_awlen ; - assign m_axi_pcis_awsize = sh_cl_dma_pcis_awsize ; - assign m_axi_pcis_awvalid = sh_cl_dma_pcis_awvalid ; - assign m_axi_pcis_wdata = sh_cl_dma_pcis_wdata ; - assign m_axi_pcis_wstrb = sh_cl_dma_pcis_wstrb ; - assign m_axi_pcis_wlast = sh_cl_dma_pcis_wlast ; - assign m_axi_pcis_wvalid = sh_cl_dma_pcis_wvalid ; - assign m_axi_pcis_bready = sh_cl_dma_pcis_bready ; - assign m_axi_pcis_arid = sh_cl_dma_pcis_arid ; - assign m_axi_pcis_araddr = sh_cl_dma_pcis_araddr ; - assign m_axi_pcis_arlen = sh_cl_dma_pcis_arlen ; - assign m_axi_pcis_arsize = sh_cl_dma_pcis_arsize ; - assign m_axi_pcis_arvalid = sh_cl_dma_pcis_arvalid ; - assign m_axi_pcis_rready = sh_cl_dma_pcis_rready ; - assign m_axi_pcis_awburst = 2'b01 ; - assign m_axi_pcis_arburst = 2'b01 ; - - assign cl_sh_pcim_awid = s_axi_pcim_awid ; - assign cl_sh_pcim_awaddr = s_axi_pcim_awaddr ; - assign cl_sh_pcim_awlen = s_axi_pcim_awlen ; - assign cl_sh_pcim_awsize = s_axi_pcim_awsize ; - assign cl_sh_pcim_awuser = s_axi_pcim_awuser ; - assign cl_sh_pcim_awvalid = s_axi_pcim_awvalid ; - assign cl_sh_pcim_wdata = s_axi_pcim_wdata ; - assign cl_sh_pcim_wstrb = s_axi_pcim_wstrb ; - assign cl_sh_pcim_wlast = s_axi_pcim_wlast ; - assign cl_sh_pcim_wvalid = s_axi_pcim_wvalid ; - assign cl_sh_pcim_bready = s_axi_pcim_bready ; - assign cl_sh_pcim_arid = s_axi_pcim_arid ; - assign cl_sh_pcim_araddr = s_axi_pcim_araddr ; - assign cl_sh_pcim_arlen = s_axi_pcim_arlen ; - assign cl_sh_pcim_arsize = s_axi_pcim_arsize ; - assign cl_sh_pcim_aruser = s_axi_pcim_aruser ; - assign cl_sh_pcim_arvalid = s_axi_pcim_arvalid ; - assign cl_sh_pcim_rready = s_axi_pcim_rready ; - - assign s_axi_pcim_awready = sh_cl_pcim_awready ; - assign s_axi_pcim_wready = sh_cl_pcim_wready ; - assign s_axi_pcim_bid = sh_cl_pcim_bid ; - assign s_axi_pcim_bresp = sh_cl_pcim_bresp ; - assign s_axi_pcim_bvalid = sh_cl_pcim_bvalid ; - assign s_axi_pcim_arready = sh_cl_pcim_arready ; - assign s_axi_pcim_rid = sh_cl_pcim_rid ; - assign s_axi_pcim_rdata = sh_cl_pcim_rdata ; - assign s_axi_pcim_rresp = sh_cl_pcim_rresp ; - assign s_axi_pcim_rlast = sh_cl_pcim_rlast ; - assign s_axi_pcim_rvalid = sh_cl_pcim_rvalid ; - assign cfg_max_payload_out = cfg_max_payload ; - assign cfg_max_read_req_out = cfg_max_read_req ; - - if ((C_MODE == 0) || (C_MODE == 1)) begin : gen_mem - - logic [15:0] cl_sh_ddr_awid_2d[2:0]; - logic [63:0] cl_sh_ddr_awaddr_2d[2:0]; - logic [7:0] cl_sh_ddr_awlen_2d[2:0]; - logic [2:0] cl_sh_ddr_awsize_2d[2:0]; - logic [1:0] cl_sh_ddr_awburst_2d[2:0]; - logic cl_sh_ddr_awvalid_2d[2:0]; - logic [2:0] sh_cl_ddr_awready_2d; - logic [15:0] cl_sh_ddr_wid_2d[2:0]; - logic [511:0] cl_sh_ddr_wdata_2d[2:0]; - logic [63:0] cl_sh_ddr_wstrb_2d[2:0]; - logic [2:0] cl_sh_ddr_wlast_2d; - logic [2:0] cl_sh_ddr_wvalid_2d; - logic [2:0] sh_cl_ddr_wready_2d; - logic [15:0] sh_cl_ddr_bid_2d[2:0]; - logic [1:0] sh_cl_ddr_bresp_2d[2:0]; - logic [2:0] sh_cl_ddr_bvalid_2d; - logic [2:0] cl_sh_ddr_bready_2d; - logic [15:0] cl_sh_ddr_arid_2d[2:0]; - logic [63:0] cl_sh_ddr_araddr_2d[2:0]; - logic [7:0] cl_sh_ddr_arlen_2d[2:0]; - logic [2:0] cl_sh_ddr_arsize_2d[2:0]; - logic [1:0] cl_sh_ddr_arburst_2d[2:0]; - logic [2:0] cl_sh_ddr_arvalid_2d; - logic [2:0] sh_cl_ddr_arready_2d; - logic [15:0] sh_cl_ddr_rid_2d[2:0]; - logic [511:0] sh_cl_ddr_rdata_2d[2:0]; - logic [1:0] sh_cl_ddr_rresp_2d[2:0]; - logic [2:0] sh_cl_ddr_rlast_2d; - logic [2:0] sh_cl_ddr_rvalid_2d; - logic [2:0] cl_sh_ddr_rready_2d; - logic [2:0] sh_cl_ddr_is_ready_2d; - - assign cl_sh_ddr_awid_2d[0] = s_axi_ddra_awid ; - assign cl_sh_ddr_awaddr_2d[0] = s_axi_ddra_awaddr ; - assign cl_sh_ddr_awlen_2d[0] = s_axi_ddra_awlen ; - assign cl_sh_ddr_awsize_2d[0] = s_axi_ddra_awsize ; - assign cl_sh_ddr_awburst_2d[0] = 2'b01 ; - assign cl_sh_ddr_awvalid_2d[0] = s_axi_ddra_awvalid ; - assign cl_sh_ddr_wid_2d[0] = 0 ; - assign cl_sh_ddr_wdata_2d[0] = s_axi_ddra_wdata ; - assign cl_sh_ddr_wstrb_2d[0] = s_axi_ddra_wstrb ; - assign cl_sh_ddr_wlast_2d[0] = s_axi_ddra_wlast ; - assign cl_sh_ddr_wvalid_2d[0] = s_axi_ddra_wvalid ; - assign cl_sh_ddr_bready_2d[0] = s_axi_ddra_bready ; - assign cl_sh_ddr_arid_2d[0] = s_axi_ddra_arid ; - assign cl_sh_ddr_araddr_2d[0] = s_axi_ddra_araddr ; - assign cl_sh_ddr_arlen_2d[0] = s_axi_ddra_arlen ; - assign cl_sh_ddr_arsize_2d[0] = s_axi_ddra_arsize ; - assign cl_sh_ddr_arburst_2d[0] = 2'b01 ; - assign cl_sh_ddr_arvalid_2d[0] = s_axi_ddra_arvalid ; - assign cl_sh_ddr_rready_2d[0] = s_axi_ddra_rready ; - - assign s_axi_ddra_awready = sh_cl_ddr_awready_2d[0] ; - assign s_axi_ddra_wready = sh_cl_ddr_wready_2d[0] ; - assign s_axi_ddra_bid = sh_cl_ddr_bid_2d[0] ; - assign s_axi_ddra_bresp = sh_cl_ddr_bresp_2d[0] ; - assign s_axi_ddra_bvalid = sh_cl_ddr_bvalid_2d[0] ; - assign s_axi_ddra_arready = sh_cl_ddr_arready_2d[0] ; - assign s_axi_ddra_rid = sh_cl_ddr_rid_2d[0] ; - assign s_axi_ddra_rdata = sh_cl_ddr_rdata_2d[0] ; - assign s_axi_ddra_rresp = sh_cl_ddr_rresp_2d[0] ; - assign s_axi_ddra_rlast = sh_cl_ddr_rlast_2d[0] ; - assign s_axi_ddra_rvalid = sh_cl_ddr_rvalid_2d[0] ; - assign ddra_is_ready = sh_cl_ddr_is_ready_2d[0]; - - assign cl_sh_ddr_awid_2d[1] = s_axi_ddrb_awid ; - assign cl_sh_ddr_awaddr_2d[1] = s_axi_ddrb_awaddr ; - assign cl_sh_ddr_awlen_2d[1] = s_axi_ddrb_awlen ; - assign cl_sh_ddr_awsize_2d[1] = s_axi_ddrb_awsize ; - assign cl_sh_ddr_awburst_2d[1] = 2'b01 ; - assign cl_sh_ddr_awvalid_2d[1] = s_axi_ddrb_awvalid ; - assign cl_sh_ddr_wid_2d[1] = 0 ; - assign cl_sh_ddr_wdata_2d[1] = s_axi_ddrb_wdata ; - assign cl_sh_ddr_wstrb_2d[1] = s_axi_ddrb_wstrb ; - assign cl_sh_ddr_wlast_2d[1] = s_axi_ddrb_wlast ; - assign cl_sh_ddr_wvalid_2d[1] = s_axi_ddrb_wvalid ; - assign cl_sh_ddr_bready_2d[1] = s_axi_ddrb_bready ; - assign cl_sh_ddr_arid_2d[1] = s_axi_ddrb_arid ; - assign cl_sh_ddr_araddr_2d[1] = s_axi_ddrb_araddr ; - assign cl_sh_ddr_arlen_2d[1] = s_axi_ddrb_arlen ; - assign cl_sh_ddr_arsize_2d[1] = s_axi_ddrb_arsize ; - assign cl_sh_ddr_arburst_2d[1] = 2'b01 ; - assign cl_sh_ddr_arvalid_2d[1] = s_axi_ddrb_arvalid ; - assign cl_sh_ddr_rready_2d[1] = s_axi_ddrb_rready ; - - assign s_axi_ddrb_awready = sh_cl_ddr_awready_2d[1] ; - assign s_axi_ddrb_wready = sh_cl_ddr_wready_2d[1] ; - assign s_axi_ddrb_bid = sh_cl_ddr_bid_2d[1] ; - assign s_axi_ddrb_bresp = sh_cl_ddr_bresp_2d[1] ; - assign s_axi_ddrb_bvalid = sh_cl_ddr_bvalid_2d[1] ; - assign s_axi_ddrb_arready = sh_cl_ddr_arready_2d[1] ; - assign s_axi_ddrb_rid = sh_cl_ddr_rid_2d[1] ; - assign s_axi_ddrb_rdata = sh_cl_ddr_rdata_2d[1] ; - assign s_axi_ddrb_rresp = sh_cl_ddr_rresp_2d[1] ; - assign s_axi_ddrb_rlast = sh_cl_ddr_rlast_2d[1] ; - assign s_axi_ddrb_rvalid = sh_cl_ddr_rvalid_2d[1] ; - assign ddrb_is_ready = sh_cl_ddr_is_ready_2d[1]; - - assign cl_sh_ddr_awid_2d[2] = s_axi_ddrd_awid ; - assign cl_sh_ddr_awaddr_2d[2] = s_axi_ddrd_awaddr ; - assign cl_sh_ddr_awlen_2d[2] = s_axi_ddrd_awlen ; - assign cl_sh_ddr_awsize_2d[2] = s_axi_ddrd_awsize ; - assign cl_sh_ddr_awburst_2d[2] = 2'b01 ; - assign cl_sh_ddr_awvalid_2d[2] = s_axi_ddrd_awvalid ; - assign cl_sh_ddr_wid_2d[2] = 0 ; - assign cl_sh_ddr_wdata_2d[2] = s_axi_ddrd_wdata ; - assign cl_sh_ddr_wstrb_2d[2] = s_axi_ddrd_wstrb ; - assign cl_sh_ddr_wlast_2d[2] = s_axi_ddrd_wlast ; - assign cl_sh_ddr_wvalid_2d[2] = s_axi_ddrd_wvalid ; - assign cl_sh_ddr_bready_2d[2] = s_axi_ddrd_bready ; - assign cl_sh_ddr_arid_2d[2] = s_axi_ddrd_arid ; - assign cl_sh_ddr_araddr_2d[2] = s_axi_ddrd_araddr ; - assign cl_sh_ddr_arlen_2d[2] = s_axi_ddrd_arlen ; - assign cl_sh_ddr_arsize_2d[2] = s_axi_ddrd_arsize ; - assign cl_sh_ddr_arburst_2d[2] = 2'b01 ; - assign cl_sh_ddr_arvalid_2d[2] = s_axi_ddrd_arvalid ; - assign cl_sh_ddr_rready_2d[2] = s_axi_ddrd_rready ; - - assign s_axi_ddrd_awready = sh_cl_ddr_awready_2d[2] ; - assign s_axi_ddrd_wready = sh_cl_ddr_wready_2d[2] ; - assign s_axi_ddrd_bid = sh_cl_ddr_bid_2d[2] ; - assign s_axi_ddrd_bresp = sh_cl_ddr_bresp_2d[2] ; - assign s_axi_ddrd_bvalid = sh_cl_ddr_bvalid_2d[2] ; - assign s_axi_ddrd_arready = sh_cl_ddr_arready_2d[2] ; - assign s_axi_ddrd_rid = sh_cl_ddr_rid_2d[2] ; - assign s_axi_ddrd_rdata = sh_cl_ddr_rdata_2d[2] ; - assign s_axi_ddrd_rresp = sh_cl_ddr_rresp_2d[2] ; - assign s_axi_ddrd_rlast = sh_cl_ddr_rlast_2d[2] ; - assign s_axi_ddrd_rvalid = sh_cl_ddr_rvalid_2d[2] ; - assign ddrd_is_ready = sh_cl_ddr_is_ready_2d[2]; - - logic ddr_aws_stat_ack0; - logic [31:0] ddr_aws_stat_rdata0; - logic [7:0] ddr_aws_stat_int0; - logic ddr_aws_stat_ack1; - logic [31:0] ddr_aws_stat_rdata1; - logic [7:0] ddr_aws_stat_int1; - logic ddr_aws_stat_ack2; - logic [31:0] ddr_aws_stat_rdata2; - logic [7:0] ddr_aws_stat_int2; - - logic [7:0] pipe_ddr_stat_addr0; - logic pipe_ddr_stat_wr0; - logic pipe_ddr_stat_rd0; - logic [31:0] pipe_ddr_stat_wdata0; - logic ddr_pipe_stat_ack0; - logic [31:0] ddr_pipe_stat_rdata0; - logic [7:0] ddr_pipe_stat_int0; - - logic [7:0] pipe_ddr_stat_addr1; - logic pipe_ddr_stat_wr1; - logic pipe_ddr_stat_rd1; - logic [31:0] pipe_ddr_stat_wdata1; - logic ddr_pipe_stat_ack1; - logic [31:0] ddr_pipe_stat_rdata1; - logic [7:0] ddr_pipe_stat_int1; - - logic [7:0] pipe_ddr_stat_addr2; - logic pipe_ddr_stat_wr2; - logic pipe_ddr_stat_rd2; - logic [31:0] pipe_ddr_stat_wdata2; - logic ddr_pipe_stat_ack2; - logic [31:0] ddr_pipe_stat_rdata2; - logic [7:0] ddr_pipe_stat_int2; - -//------------------------------------------------- -// Tie-offs when DDRs are disabled -//------------------------------------------------- - assign ddr_sh_stat_ack0 = (C_DDR_A_PRESENT!=0) ? ddr_aws_stat_ack0 : 1'b1; - assign ddr_sh_stat_rdata0 = (C_DDR_A_PRESENT!=0) ? ddr_aws_stat_rdata0 : 0; - assign ddr_sh_stat_int0 = (C_DDR_A_PRESENT!=0) ? ddr_aws_stat_int0 : 8'b0; - assign ddr_sh_stat_ack1 = (C_DDR_B_PRESENT!=0) ? ddr_aws_stat_ack1 : 1'b1; - assign ddr_sh_stat_rdata1 = (C_DDR_B_PRESENT!=0) ? ddr_aws_stat_rdata1 : 0; - assign ddr_sh_stat_int1 = (C_DDR_B_PRESENT!=0) ? ddr_aws_stat_int1 : 8'b0; - assign ddr_sh_stat_ack2 = (C_DDR_D_PRESENT!=0) ? ddr_aws_stat_ack2 : 1'b1; - assign ddr_sh_stat_rdata2 = (C_DDR_D_PRESENT!=0) ? ddr_aws_stat_rdata2 : 0; - assign ddr_sh_stat_int2 = (C_DDR_D_PRESENT!=0) ? ddr_aws_stat_int2 : 8'b0; - -//------------------------------------------------- -// Reset Synchronization -//------------------------------------------------- - logic pre_sync_rst_n; - logic sync_rst_n; - - always @(negedge rst_main_n or posedge clk_main_a0) begin - if (!rst_main_n) begin - pre_sync_rst_n <= 1'b0; - sync_rst_n <= 1'b0; - end else begin - pre_sync_rst_n <= 1'b1; - sync_rst_n <= pre_sync_rst_n; - end - end - - `ifdef FPGA_LESS_RST - `undef FPGA_LESS_RST - `endif - - lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wdata0 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_wdata0), .out_bus(pipe_ddr_stat_wdata0)); - lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_addr0 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_addr0), .out_bus(pipe_ddr_stat_addr0)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wr0 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_wr0), .out_bus(pipe_ddr_stat_wr0)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rd0 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_rd0), .out_bus(pipe_ddr_stat_rd0)); - lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rdata0 (.clk(clk_main_a0), .rst_n(1'b1), .out_bus(ddr_aws_stat_rdata0), .in_bus(ddr_pipe_stat_rdata0)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_ack0 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_ack0), .in_bus(ddr_pipe_stat_ack0)); - lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_int0 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_int0), .in_bus(ddr_pipe_stat_int0)); - - lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wdata1 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_wdata1), .out_bus(pipe_ddr_stat_wdata1)); - lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_addr1 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_addr1), .out_bus(pipe_ddr_stat_addr1)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wr1 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_wr1), .out_bus(pipe_ddr_stat_wr1)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rd1 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_rd1), .out_bus(pipe_ddr_stat_rd1)); - lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rdata1 (.clk(clk_main_a0), .rst_n(1'b1), .out_bus(ddr_aws_stat_rdata1), .in_bus(ddr_pipe_stat_rdata1)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_ack1 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_ack1), .in_bus(ddr_pipe_stat_ack1)); - lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_int1 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_int1), .in_bus(ddr_pipe_stat_int1)); - - lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wdata2 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_wdata2), .out_bus(pipe_ddr_stat_wdata2)); - lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_addr2 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_addr2), .out_bus(pipe_ddr_stat_addr2)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wr2 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_wr2), .out_bus(pipe_ddr_stat_wr2)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rd2 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_rd2), .out_bus(pipe_ddr_stat_rd2)); - lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rdata2 (.clk(clk_main_a0), .rst_n(1'b1), .out_bus(ddr_aws_stat_rdata2), .in_bus(ddr_pipe_stat_rdata2)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_ack2 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_ack2), .in_bus(ddr_pipe_stat_ack2)); - lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_int2 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_int2), .in_bus(ddr_pipe_stat_int2)); - - sh_ddr #( - .DDR_A_PRESENT(C_DDR_A_PRESENT), - .DDR_B_PRESENT(C_DDR_B_PRESENT), - .DDR_D_PRESENT(C_DDR_D_PRESENT) - ) sh_ddr_0 - ( - .clk(clk_main_a0), - .rst_n(sync_rst_n), - - .stat_clk(clk_main_a0), - .stat_rst_n(sync_rst_n), - - .CLK_300M_DIMM0_DP(CLK_300M_DIMM0_DP), - .CLK_300M_DIMM0_DN(CLK_300M_DIMM0_DN), - .M_A_ACT_N(M_A_ACT_N), - .M_A_MA(M_A_MA), - .M_A_BA(M_A_BA), - .M_A_BG(M_A_BG), - .M_A_CKE(M_A_CKE), - .M_A_ODT(M_A_ODT), - .M_A_CS_N(M_A_CS_N), - .M_A_CLK_DN(M_A_CLK_DN), - .M_A_CLK_DP(M_A_CLK_DP), - .M_A_PAR(M_A_PAR), - .M_A_DQ(M_A_DQ), - .M_A_ECC(M_A_ECC), - .M_A_DQS_DP(M_A_DQS_DP), - .M_A_DQS_DN(M_A_DQS_DN), - .cl_RST_DIMM_A_N(cl_RST_DIMM_A_N), - - .CLK_300M_DIMM1_DP(CLK_300M_DIMM1_DP), - .CLK_300M_DIMM1_DN(CLK_300M_DIMM1_DN), - .M_B_ACT_N(M_B_ACT_N), - .M_B_MA(M_B_MA), - .M_B_BA(M_B_BA), - .M_B_BG(M_B_BG), - .M_B_CKE(M_B_CKE), - .M_B_ODT(M_B_ODT), - .M_B_CS_N(M_B_CS_N), - .M_B_CLK_DN(M_B_CLK_DN), - .M_B_CLK_DP(M_B_CLK_DP), - .M_B_PAR(M_B_PAR), - .M_B_DQ(M_B_DQ), - .M_B_ECC(M_B_ECC), - .M_B_DQS_DP(M_B_DQS_DP), - .M_B_DQS_DN(M_B_DQS_DN), - .cl_RST_DIMM_B_N(cl_RST_DIMM_B_N), - - .CLK_300M_DIMM3_DP(CLK_300M_DIMM3_DP), - .CLK_300M_DIMM3_DN(CLK_300M_DIMM3_DN), - .M_D_ACT_N(M_D_ACT_N), - .M_D_MA(M_D_MA), - .M_D_BA(M_D_BA), - .M_D_BG(M_D_BG), - .M_D_CKE(M_D_CKE), - .M_D_ODT(M_D_ODT), - .M_D_CS_N(M_D_CS_N), - .M_D_CLK_DN(M_D_CLK_DN), - .M_D_CLK_DP(M_D_CLK_DP), - .M_D_PAR(M_D_PAR), - .M_D_DQ(M_D_DQ), - .M_D_ECC(M_D_ECC), - .M_D_DQS_DP(M_D_DQS_DP), - .M_D_DQS_DN(M_D_DQS_DN), - .cl_RST_DIMM_D_N(cl_RST_DIMM_D_N), - - //------------------------------------------------------ - // AXI Slave Interfaces - //------------------------------------------------------ - .cl_sh_ddr_awid(cl_sh_ddr_awid_2d), - .cl_sh_ddr_awaddr(cl_sh_ddr_awaddr_2d), - .cl_sh_ddr_awlen(cl_sh_ddr_awlen_2d), - .cl_sh_ddr_awsize(cl_sh_ddr_awsize_2d), - .cl_sh_ddr_awburst(cl_sh_ddr_awburst_2d), - .cl_sh_ddr_awvalid(cl_sh_ddr_awvalid_2d), - .sh_cl_ddr_awready(sh_cl_ddr_awready_2d), - - .cl_sh_ddr_wid(cl_sh_ddr_wid_2d), - .cl_sh_ddr_wdata(cl_sh_ddr_wdata_2d), - .cl_sh_ddr_wstrb(cl_sh_ddr_wstrb_2d), - .cl_sh_ddr_wlast(cl_sh_ddr_wlast_2d), - .cl_sh_ddr_wvalid(cl_sh_ddr_wvalid_2d), - .sh_cl_ddr_wready(sh_cl_ddr_wready_2d), - - .sh_cl_ddr_bid(sh_cl_ddr_bid_2d), - .sh_cl_ddr_bresp(sh_cl_ddr_bresp_2d), - .sh_cl_ddr_bvalid(sh_cl_ddr_bvalid_2d), - .cl_sh_ddr_bready(cl_sh_ddr_bready_2d), - - .cl_sh_ddr_arid(cl_sh_ddr_arid_2d), - .cl_sh_ddr_araddr(cl_sh_ddr_araddr_2d), - .cl_sh_ddr_arlen(cl_sh_ddr_arlen_2d), - .cl_sh_ddr_arsize(cl_sh_ddr_arsize_2d), - .cl_sh_ddr_arburst(cl_sh_ddr_arburst_2d), - .cl_sh_ddr_arvalid(cl_sh_ddr_arvalid_2d), - .sh_cl_ddr_arready(sh_cl_ddr_arready_2d), - - .sh_cl_ddr_rid(sh_cl_ddr_rid_2d), - .sh_cl_ddr_rdata(sh_cl_ddr_rdata_2d), - .sh_cl_ddr_rresp(sh_cl_ddr_rresp_2d), - .sh_cl_ddr_rlast(sh_cl_ddr_rlast_2d), - .sh_cl_ddr_rvalid(sh_cl_ddr_rvalid_2d), - .cl_sh_ddr_rready(cl_sh_ddr_rready_2d), - - .sh_cl_ddr_is_ready(sh_cl_ddr_is_ready_2d), - - .sh_ddr_stat_addr0 (pipe_ddr_stat_addr0 ), - .sh_ddr_stat_wr0 (pipe_ddr_stat_wr0 ), - .sh_ddr_stat_rd0 (pipe_ddr_stat_rd0 ), - .sh_ddr_stat_wdata0 (pipe_ddr_stat_wdata0), - .ddr_sh_stat_ack0 (ddr_pipe_stat_ack0 ), - .ddr_sh_stat_rdata0 (ddr_pipe_stat_rdata0), - .ddr_sh_stat_int0 (ddr_pipe_stat_int0 ), - - .sh_ddr_stat_addr1 (pipe_ddr_stat_addr1 ), - .sh_ddr_stat_wr1 (pipe_ddr_stat_wr1 ), - .sh_ddr_stat_rd1 (pipe_ddr_stat_rd1 ), - .sh_ddr_stat_wdata1 (pipe_ddr_stat_wdata1), - .ddr_sh_stat_ack1 (ddr_pipe_stat_ack1 ), - .ddr_sh_stat_rdata1 (ddr_pipe_stat_rdata1), - .ddr_sh_stat_int1 (ddr_pipe_stat_int1 ), - - .sh_ddr_stat_addr2 (pipe_ddr_stat_addr2 ), - .sh_ddr_stat_wr2 (pipe_ddr_stat_wr2 ), - .sh_ddr_stat_rd2 (pipe_ddr_stat_rd2 ), - .sh_ddr_stat_wdata2 (pipe_ddr_stat_wdata2), - .ddr_sh_stat_ack2 (ddr_pipe_stat_ack2 ), - .ddr_sh_stat_rdata2 (ddr_pipe_stat_rdata2), - .ddr_sh_stat_int2 (ddr_pipe_stat_int2 ) - - ); - - end else begin : gen_non_mem - - assign s_axi_ddra_awready = 0; - assign s_axi_ddra_wready = 0; - assign s_axi_ddra_bid = 0; - assign s_axi_ddra_bresp = 0; - assign s_axi_ddra_bvalid = 0; - assign s_axi_ddra_arready = 0; - assign s_axi_ddra_rid = 0; - assign s_axi_ddra_rdata = 0; - assign s_axi_ddra_rresp = 0; - assign s_axi_ddra_rlast = 1'b1; - assign s_axi_ddra_rvalid = 0; - assign ddra_is_ready = 0; - - assign s_axi_ddrb_awready = 0; - assign s_axi_ddrb_wready = 0; - assign s_axi_ddrb_bid = 0; - assign s_axi_ddrb_bresp = 0; - assign s_axi_ddrb_bvalid = 0; - assign s_axi_ddrb_arready = 0; - assign s_axi_ddrb_rid = 0; - assign s_axi_ddrb_rdata = 0; - assign s_axi_ddrb_rresp = 0; - assign s_axi_ddrb_rlast = 1'b1; - assign s_axi_ddrb_rvalid = 0; - assign ddrb_is_ready = 0; - - assign s_axi_ddrd_awready = 0; - assign s_axi_ddrd_wready = 0; - assign s_axi_ddrd_bid = 0; - assign s_axi_ddrd_bresp = 0; - assign s_axi_ddrd_bvalid = 0; - assign s_axi_ddrd_arready = 0; - assign s_axi_ddrd_rid = 0; - assign s_axi_ddrd_rdata = 0; - assign s_axi_ddrd_rresp = 0; - assign s_axi_ddrd_rlast = 1'b1; - assign s_axi_ddrd_rvalid = 0; - assign ddrd_is_ready = 0; - - assign ddr_sh_stat_ack0 = 1'b1; - assign ddr_sh_stat_rdata0 = 0; - assign ddr_sh_stat_int0 = 8'b0; - assign ddr_sh_stat_ack1 = 1'b1; - assign ddr_sh_stat_rdata1 = 0; - assign ddr_sh_stat_int1 = 8'b0; - assign ddr_sh_stat_ack2 = 1'b1; - assign ddr_sh_stat_rdata2 = 0; - assign ddr_sh_stat_int2 = 8'b0; - - assign M_A_ACT_N = 0; - assign M_A_MA = 0; - assign M_A_BA = 0; - assign M_A_BG = 0; - assign M_A_CKE = 0; - assign M_A_ODT = 0; - assign M_A_CS_N = 0; - assign M_A_CLK_DN = 0; - assign M_A_CLK_DP = 0; - assign M_A_PAR = 0; - assign cl_RST_DIMM_A_N = 0; - - assign M_B_ACT_N = 0; - assign M_B_MA = 0; - assign M_B_BA = 0; - assign M_B_BG = 0; - assign M_B_CKE = 0; - assign M_B_ODT = 0; - assign M_B_CS_N = 0; - assign M_B_CLK_DN = 0; - assign M_B_CLK_DP = 0; - assign M_B_PAR = 0; - assign cl_RST_DIMM_B_N = 0; - - assign M_D_ACT_N = 0; - assign M_D_MA = 0; - assign M_D_BA = 0; - assign M_D_BG = 0; - assign M_D_CKE = 0; - assign M_D_ODT = 0; - assign M_D_CS_N = 0; - assign M_D_CLK_DN = 0; - assign M_D_CLK_DP = 0; - assign M_D_PAR = 0; - assign cl_RST_DIMM_D_N = 0; - - end // gen_mem - endgenerate - -endmodule - - diff --git a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/aws_v1_0_vlsyn_rfs.sv b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/aws_v1_0_vlsyn_rfs.sv deleted file mode 100755 index f2122cce..00000000 --- a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/aws_v1_0_vlsyn_rfs.sv +++ /dev/null @@ -1,3099 +0,0 @@ -//---------------------------------------------------------------------------------- -//Copyright (c) 2014 -// -//Permission is hereby granted, free of charge, to any person obtaining a copy -//of this software and associated documentation files (the "Software"), to deal -//in the Software without restriction, including without limitation the rights -//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -//copies of the Software, and to permit persons to whom the Software is -//furnished to do so, subject to the following conditions: -// -//The above copyright notice and this permission notice shall be included in -//all copies or substantial portions of the Software. -// -//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -//THE SOFTWARE. -//---------------------------------------------------------------------------------- - -//simple pipeline - -//WIDTH is the width of the DATA -//STAGES is the number of stages (flops in the pipeline) -module lib_pipe #(parameter WIDTH=8, parameter STAGES=1) ( - input clk, - input rst_n, - - input[WIDTH-1:0] in_bus, - - output [WIDTH-1:0] out_bus - ); - -//Note the shreg_extract=no directs Xilinx to not infer shift registers which -// defeats using this as a pipeline - - -`ifdef FPGA_LESS_RST - (*shreg_extract="no"*) logic [WIDTH-1:0] pipe[STAGES-1:0] = '{default:'0}; -`else - (*shreg_extract="no"*) logic [WIDTH-1:0] pipe[STAGES-1:0]; -`endif - -//(*srl_style="register"*) logic [WIDTH-1:0] pipe [STAGES-1:0]; -// logic [WIDTH-1:0] pipe [STAGES-1:0]; - - integer i; - -`ifdef FPGA_LESS_RST - always @(posedge clk) -`else - always @(negedge rst_n or posedge clk) - if (!rst_n) - begin - for (i=0; i1) - begin - for (i=1; i1 ? clk_extra_a1 : 1'b0 ; - assign clk_extra_a2_out = C_NUM_A_CLOCKS>2 ? clk_extra_a2 : 1'b0 ; - assign clk_extra_a3_out = C_NUM_A_CLOCKS>3 ? clk_extra_a3 : 1'b0 ; - assign clk_extra_b0_out = C_NUM_B_CLOCKS>0 ? clk_extra_b0 : 1'b0 ; - assign clk_extra_b1_out = C_NUM_B_CLOCKS>1 ? clk_extra_b1 : 1'b0 ; - assign clk_extra_c0_out = C_NUM_C_CLOCKS>0 ? clk_extra_c0 : 1'b0 ; - assign clk_extra_c1_out = C_NUM_C_CLOCKS>1 ? clk_extra_c1 : 1'b0 ; - assign rst_main_n_out = rst_main_n ; - assign kernel_rst_n_out = kernel_rst_n ; - assign flr_assert = sh_cl_flr_assert ; - assign status_vdip = sh_cl_status_vdip ; - assign irq_ack = sh_cl_apppf_irq_ack ; - assign glcount0 = sh_cl_glcount0 ; - assign glcount1 = sh_cl_glcount1 ; - - assign cl_sh_flr_done = flr_done ; - assign cl_sh_status_vled = status_vled ; - assign cl_sh_apppf_irq_req = irq_req ; - - assign cl_sh_status0 = 0 ; - assign cl_sh_status1 = 0 ; - assign cl_sh_id0 = {C_DEVICE_ID, C_VENDOR_ID} ; - assign cl_sh_id1 = {C_SUBSYSTEM_ID, C_SUBSYSTEM_VENDOR_ID} ; - - assign cl_sh_dma_wr_full = 1'b0; - assign cl_sh_dma_rd_full = 1'b0; - - assign cl_sh_ddr_awid = s_axi_ddrc_awid ; - assign cl_sh_ddr_awaddr = s_axi_ddrc_awaddr ; - assign cl_sh_ddr_awlen = s_axi_ddrc_awlen ; - assign cl_sh_ddr_awsize = s_axi_ddrc_awsize ; - assign cl_sh_ddr_awburst = 2'b01 ; - assign cl_sh_ddr_awvalid = s_axi_ddrc_awvalid ; - assign cl_sh_ddr_wdata = s_axi_ddrc_wdata ; - assign cl_sh_ddr_wstrb = s_axi_ddrc_wstrb ; - assign cl_sh_ddr_wlast = s_axi_ddrc_wlast ; - assign cl_sh_ddr_wvalid = s_axi_ddrc_wvalid ; - assign cl_sh_ddr_bready = s_axi_ddrc_bready ; - assign cl_sh_ddr_arid = s_axi_ddrc_arid ; - assign cl_sh_ddr_araddr = s_axi_ddrc_araddr ; - assign cl_sh_ddr_arlen = s_axi_ddrc_arlen ; - assign cl_sh_ddr_arsize = s_axi_ddrc_arsize ; - assign cl_sh_ddr_arburst = 2'b01 ; - assign cl_sh_ddr_arvalid = s_axi_ddrc_arvalid ; - assign cl_sh_ddr_rready = s_axi_ddrc_rready ; - - assign s_axi_ddrc_awready = sh_cl_ddr_awready ; - assign s_axi_ddrc_wready = sh_cl_ddr_wready ; - assign s_axi_ddrc_bid = sh_cl_ddr_bid ; - assign s_axi_ddrc_bresp = sh_cl_ddr_bresp ; - assign s_axi_ddrc_bvalid = sh_cl_ddr_bvalid ; - assign s_axi_ddrc_arready = sh_cl_ddr_arready ; - assign s_axi_ddrc_rid = sh_cl_ddr_rid ; - assign s_axi_ddrc_rdata = sh_cl_ddr_rdata ; - assign s_axi_ddrc_rresp = sh_cl_ddr_rresp ; - assign s_axi_ddrc_rlast = sh_cl_ddr_rlast ; - assign s_axi_ddrc_rvalid = sh_cl_ddr_rvalid ; - assign ddrc_is_ready = sh_cl_ddr_is_ready ; - - assign cl_sh_ddr_wid = 0 ; - - assign cl_sda_awready = m_axi_sda_awready ; - assign cl_sda_wready = m_axi_sda_wready ; - assign cl_sda_bresp = m_axi_sda_bresp ; - assign cl_sda_bvalid = m_axi_sda_bvalid ; - assign cl_sda_arready = m_axi_sda_arready ; - assign cl_sda_rdata = m_axi_sda_rdata ; - assign cl_sda_rresp = m_axi_sda_rresp ; - assign cl_sda_rvalid = m_axi_sda_rvalid ; - - assign m_axi_sda_awaddr = sda_cl_awaddr ; - assign m_axi_sda_awvalid = sda_cl_awvalid ; - assign m_axi_sda_wdata = sda_cl_wdata ; - assign m_axi_sda_wstrb = sda_cl_wstrb ; - assign m_axi_sda_wvalid = sda_cl_wvalid ; - assign m_axi_sda_bready = sda_cl_bready ; - assign m_axi_sda_araddr = sda_cl_araddr ; - assign m_axi_sda_arvalid = sda_cl_arvalid ; - assign m_axi_sda_rready = sda_cl_rready ; - - assign ocl_sh_awready = m_axi_ocl_awready ; - assign ocl_sh_wready = m_axi_ocl_wready ; - assign ocl_sh_bresp = m_axi_ocl_bresp ; - assign ocl_sh_bvalid = m_axi_ocl_bvalid ; - assign ocl_sh_arready = m_axi_ocl_arready ; - assign ocl_sh_rdata = m_axi_ocl_rdata ; - assign ocl_sh_rresp = m_axi_ocl_rresp ; - assign ocl_sh_rvalid = m_axi_ocl_rvalid ; - - assign m_axi_ocl_awaddr = sh_ocl_awaddr ; - assign m_axi_ocl_awvalid = sh_ocl_awvalid ; - assign m_axi_ocl_wdata = sh_ocl_wdata ; - assign m_axi_ocl_wstrb = sh_ocl_wstrb ; - assign m_axi_ocl_wvalid = sh_ocl_wvalid ; - assign m_axi_ocl_bready = sh_ocl_bready ; - assign m_axi_ocl_araddr = sh_ocl_araddr ; - assign m_axi_ocl_arvalid = sh_ocl_arvalid ; - assign m_axi_ocl_rready = sh_ocl_rready ; - - assign bar1_sh_awready = m_axi_bar1_awready ; - assign bar1_sh_wready = m_axi_bar1_wready ; - assign bar1_sh_bresp = m_axi_bar1_bresp ; - assign bar1_sh_bvalid = m_axi_bar1_bvalid ; - assign bar1_sh_arready = m_axi_bar1_arready ; - assign bar1_sh_rdata = m_axi_bar1_rdata ; - assign bar1_sh_rresp = m_axi_bar1_rresp ; - assign bar1_sh_rvalid = m_axi_bar1_rvalid ; - - assign m_axi_bar1_awaddr = sh_bar1_awaddr ; - assign m_axi_bar1_awvalid = sh_bar1_awvalid ; - assign m_axi_bar1_wdata = sh_bar1_wdata ; - assign m_axi_bar1_wstrb = sh_bar1_wstrb ; - assign m_axi_bar1_wvalid = sh_bar1_wvalid ; - assign m_axi_bar1_bready = sh_bar1_bready ; - assign m_axi_bar1_araddr = sh_bar1_araddr ; - assign m_axi_bar1_arvalid = sh_bar1_arvalid ; - assign m_axi_bar1_rready = sh_bar1_rready ; - - assign cl_sh_dma_pcis_awready = m_axi_pcis_awready ; - assign cl_sh_dma_pcis_wready = m_axi_pcis_wready ; - assign cl_sh_dma_pcis_bid = m_axi_pcis_bid ; - assign cl_sh_dma_pcis_bresp = m_axi_pcis_bresp ; - assign cl_sh_dma_pcis_bvalid = m_axi_pcis_bvalid ; - assign cl_sh_dma_pcis_arready = m_axi_pcis_arready ; - assign cl_sh_dma_pcis_rid = m_axi_pcis_rid ; - assign cl_sh_dma_pcis_rdata = m_axi_pcis_rdata ; - assign cl_sh_dma_pcis_rresp = m_axi_pcis_rresp ; - assign cl_sh_dma_pcis_rlast = m_axi_pcis_rlast ; - assign cl_sh_dma_pcis_rvalid = m_axi_pcis_rvalid ; - - assign m_axi_pcis_awid = sh_cl_dma_pcis_awid ; - assign m_axi_pcis_awaddr = sh_cl_dma_pcis_awaddr ; - assign m_axi_pcis_awlen = sh_cl_dma_pcis_awlen ; - assign m_axi_pcis_awsize = sh_cl_dma_pcis_awsize ; - assign m_axi_pcis_awvalid = sh_cl_dma_pcis_awvalid ; - assign m_axi_pcis_wdata = sh_cl_dma_pcis_wdata ; - assign m_axi_pcis_wstrb = sh_cl_dma_pcis_wstrb ; - assign m_axi_pcis_wlast = sh_cl_dma_pcis_wlast ; - assign m_axi_pcis_wvalid = sh_cl_dma_pcis_wvalid ; - assign m_axi_pcis_bready = sh_cl_dma_pcis_bready ; - assign m_axi_pcis_arid = sh_cl_dma_pcis_arid ; - assign m_axi_pcis_araddr = sh_cl_dma_pcis_araddr ; - assign m_axi_pcis_arlen = sh_cl_dma_pcis_arlen ; - assign m_axi_pcis_arsize = sh_cl_dma_pcis_arsize ; - assign m_axi_pcis_arvalid = sh_cl_dma_pcis_arvalid ; - assign m_axi_pcis_rready = sh_cl_dma_pcis_rready ; - assign m_axi_pcis_awburst = 2'b01 ; - assign m_axi_pcis_arburst = 2'b01 ; - - assign cl_sh_pcim_awid = s_axi_pcim_awid ; - assign cl_sh_pcim_awaddr = s_axi_pcim_awaddr ; - assign cl_sh_pcim_awlen = s_axi_pcim_awlen ; - assign cl_sh_pcim_awsize = s_axi_pcim_awsize ; - assign cl_sh_pcim_awuser = s_axi_pcim_awuser ; - assign cl_sh_pcim_awvalid = s_axi_pcim_awvalid ; - assign cl_sh_pcim_wdata = s_axi_pcim_wdata ; - assign cl_sh_pcim_wstrb = s_axi_pcim_wstrb ; - assign cl_sh_pcim_wlast = s_axi_pcim_wlast ; - assign cl_sh_pcim_wvalid = s_axi_pcim_wvalid ; - assign cl_sh_pcim_bready = s_axi_pcim_bready ; - assign cl_sh_pcim_arid = s_axi_pcim_arid ; - assign cl_sh_pcim_araddr = s_axi_pcim_araddr ; - assign cl_sh_pcim_arlen = s_axi_pcim_arlen ; - assign cl_sh_pcim_arsize = s_axi_pcim_arsize ; - assign cl_sh_pcim_aruser = s_axi_pcim_aruser ; - assign cl_sh_pcim_arvalid = s_axi_pcim_arvalid ; - assign cl_sh_pcim_rready = s_axi_pcim_rready ; - - assign s_axi_pcim_awready = sh_cl_pcim_awready ; - assign s_axi_pcim_wready = sh_cl_pcim_wready ; - assign s_axi_pcim_bid = sh_cl_pcim_bid ; - assign s_axi_pcim_bresp = sh_cl_pcim_bresp ; - assign s_axi_pcim_bvalid = sh_cl_pcim_bvalid ; - assign s_axi_pcim_arready = sh_cl_pcim_arready ; - assign s_axi_pcim_rid = sh_cl_pcim_rid ; - assign s_axi_pcim_rdata = sh_cl_pcim_rdata ; - assign s_axi_pcim_rresp = sh_cl_pcim_rresp ; - assign s_axi_pcim_rlast = sh_cl_pcim_rlast ; - assign s_axi_pcim_rvalid = sh_cl_pcim_rvalid ; - assign cfg_max_payload_out = cfg_max_payload ; - assign cfg_max_read_req_out = cfg_max_read_req ; - - if ((C_MODE == 0) || (C_MODE == 1)) begin : gen_mem - - logic [15:0] cl_sh_ddr_awid_2d[2:0]; - logic [63:0] cl_sh_ddr_awaddr_2d[2:0]; - logic [7:0] cl_sh_ddr_awlen_2d[2:0]; - logic [2:0] cl_sh_ddr_awsize_2d[2:0]; - logic [1:0] cl_sh_ddr_awburst_2d[2:0]; - logic cl_sh_ddr_awvalid_2d[2:0]; - logic [2:0] sh_cl_ddr_awready_2d; - logic [15:0] cl_sh_ddr_wid_2d[2:0]; - logic [511:0] cl_sh_ddr_wdata_2d[2:0]; - logic [63:0] cl_sh_ddr_wstrb_2d[2:0]; - logic [2:0] cl_sh_ddr_wlast_2d; - logic [2:0] cl_sh_ddr_wvalid_2d; - logic [2:0] sh_cl_ddr_wready_2d; - logic [15:0] sh_cl_ddr_bid_2d[2:0]; - logic [1:0] sh_cl_ddr_bresp_2d[2:0]; - logic [2:0] sh_cl_ddr_bvalid_2d; - logic [2:0] cl_sh_ddr_bready_2d; - logic [15:0] cl_sh_ddr_arid_2d[2:0]; - logic [63:0] cl_sh_ddr_araddr_2d[2:0]; - logic [7:0] cl_sh_ddr_arlen_2d[2:0]; - logic [2:0] cl_sh_ddr_arsize_2d[2:0]; - logic [1:0] cl_sh_ddr_arburst_2d[2:0]; - logic [2:0] cl_sh_ddr_arvalid_2d; - logic [2:0] sh_cl_ddr_arready_2d; - logic [15:0] sh_cl_ddr_rid_2d[2:0]; - logic [511:0] sh_cl_ddr_rdata_2d[2:0]; - logic [1:0] sh_cl_ddr_rresp_2d[2:0]; - logic [2:0] sh_cl_ddr_rlast_2d; - logic [2:0] sh_cl_ddr_rvalid_2d; - logic [2:0] cl_sh_ddr_rready_2d; - logic [2:0] sh_cl_ddr_is_ready_2d; - - assign cl_sh_ddr_awid_2d[0] = s_axi_ddra_awid ; - assign cl_sh_ddr_awaddr_2d[0] = s_axi_ddra_awaddr ; - assign cl_sh_ddr_awlen_2d[0] = s_axi_ddra_awlen ; - assign cl_sh_ddr_awsize_2d[0] = s_axi_ddra_awsize ; - assign cl_sh_ddr_awburst_2d[0] = 2'b01 ; - assign cl_sh_ddr_awvalid_2d[0] = s_axi_ddra_awvalid ; - assign cl_sh_ddr_wid_2d[0] = 0 ; - assign cl_sh_ddr_wdata_2d[0] = s_axi_ddra_wdata ; - assign cl_sh_ddr_wstrb_2d[0] = s_axi_ddra_wstrb ; - assign cl_sh_ddr_wlast_2d[0] = s_axi_ddra_wlast ; - assign cl_sh_ddr_wvalid_2d[0] = s_axi_ddra_wvalid ; - assign cl_sh_ddr_bready_2d[0] = s_axi_ddra_bready ; - assign cl_sh_ddr_arid_2d[0] = s_axi_ddra_arid ; - assign cl_sh_ddr_araddr_2d[0] = s_axi_ddra_araddr ; - assign cl_sh_ddr_arlen_2d[0] = s_axi_ddra_arlen ; - assign cl_sh_ddr_arsize_2d[0] = s_axi_ddra_arsize ; - assign cl_sh_ddr_arburst_2d[0] = 2'b01 ; - assign cl_sh_ddr_arvalid_2d[0] = s_axi_ddra_arvalid ; - assign cl_sh_ddr_rready_2d[0] = s_axi_ddra_rready ; - - assign s_axi_ddra_awready = sh_cl_ddr_awready_2d[0] ; - assign s_axi_ddra_wready = sh_cl_ddr_wready_2d[0] ; - assign s_axi_ddra_bid = sh_cl_ddr_bid_2d[0] ; - assign s_axi_ddra_bresp = sh_cl_ddr_bresp_2d[0] ; - assign s_axi_ddra_bvalid = sh_cl_ddr_bvalid_2d[0] ; - assign s_axi_ddra_arready = sh_cl_ddr_arready_2d[0] ; - assign s_axi_ddra_rid = sh_cl_ddr_rid_2d[0] ; - assign s_axi_ddra_rdata = sh_cl_ddr_rdata_2d[0] ; - assign s_axi_ddra_rresp = sh_cl_ddr_rresp_2d[0] ; - assign s_axi_ddra_rlast = sh_cl_ddr_rlast_2d[0] ; - assign s_axi_ddra_rvalid = sh_cl_ddr_rvalid_2d[0] ; - assign ddra_is_ready = sh_cl_ddr_is_ready_2d[0]; - - assign cl_sh_ddr_awid_2d[1] = s_axi_ddrb_awid ; - assign cl_sh_ddr_awaddr_2d[1] = s_axi_ddrb_awaddr ; - assign cl_sh_ddr_awlen_2d[1] = s_axi_ddrb_awlen ; - assign cl_sh_ddr_awsize_2d[1] = s_axi_ddrb_awsize ; - assign cl_sh_ddr_awburst_2d[1] = 2'b01 ; - assign cl_sh_ddr_awvalid_2d[1] = s_axi_ddrb_awvalid ; - assign cl_sh_ddr_wid_2d[1] = 0 ; - assign cl_sh_ddr_wdata_2d[1] = s_axi_ddrb_wdata ; - assign cl_sh_ddr_wstrb_2d[1] = s_axi_ddrb_wstrb ; - assign cl_sh_ddr_wlast_2d[1] = s_axi_ddrb_wlast ; - assign cl_sh_ddr_wvalid_2d[1] = s_axi_ddrb_wvalid ; - assign cl_sh_ddr_bready_2d[1] = s_axi_ddrb_bready ; - assign cl_sh_ddr_arid_2d[1] = s_axi_ddrb_arid ; - assign cl_sh_ddr_araddr_2d[1] = s_axi_ddrb_araddr ; - assign cl_sh_ddr_arlen_2d[1] = s_axi_ddrb_arlen ; - assign cl_sh_ddr_arsize_2d[1] = s_axi_ddrb_arsize ; - assign cl_sh_ddr_arburst_2d[1] = 2'b01 ; - assign cl_sh_ddr_arvalid_2d[1] = s_axi_ddrb_arvalid ; - assign cl_sh_ddr_rready_2d[1] = s_axi_ddrb_rready ; - - assign s_axi_ddrb_awready = sh_cl_ddr_awready_2d[1] ; - assign s_axi_ddrb_wready = sh_cl_ddr_wready_2d[1] ; - assign s_axi_ddrb_bid = sh_cl_ddr_bid_2d[1] ; - assign s_axi_ddrb_bresp = sh_cl_ddr_bresp_2d[1] ; - assign s_axi_ddrb_bvalid = sh_cl_ddr_bvalid_2d[1] ; - assign s_axi_ddrb_arready = sh_cl_ddr_arready_2d[1] ; - assign s_axi_ddrb_rid = sh_cl_ddr_rid_2d[1] ; - assign s_axi_ddrb_rdata = sh_cl_ddr_rdata_2d[1] ; - assign s_axi_ddrb_rresp = sh_cl_ddr_rresp_2d[1] ; - assign s_axi_ddrb_rlast = sh_cl_ddr_rlast_2d[1] ; - assign s_axi_ddrb_rvalid = sh_cl_ddr_rvalid_2d[1] ; - assign ddrb_is_ready = sh_cl_ddr_is_ready_2d[1]; - - assign cl_sh_ddr_awid_2d[2] = s_axi_ddrd_awid ; - assign cl_sh_ddr_awaddr_2d[2] = s_axi_ddrd_awaddr ; - assign cl_sh_ddr_awlen_2d[2] = s_axi_ddrd_awlen ; - assign cl_sh_ddr_awsize_2d[2] = s_axi_ddrd_awsize ; - assign cl_sh_ddr_awburst_2d[2] = 2'b01 ; - assign cl_sh_ddr_awvalid_2d[2] = s_axi_ddrd_awvalid ; - assign cl_sh_ddr_wid_2d[2] = 0 ; - assign cl_sh_ddr_wdata_2d[2] = s_axi_ddrd_wdata ; - assign cl_sh_ddr_wstrb_2d[2] = s_axi_ddrd_wstrb ; - assign cl_sh_ddr_wlast_2d[2] = s_axi_ddrd_wlast ; - assign cl_sh_ddr_wvalid_2d[2] = s_axi_ddrd_wvalid ; - assign cl_sh_ddr_bready_2d[2] = s_axi_ddrd_bready ; - assign cl_sh_ddr_arid_2d[2] = s_axi_ddrd_arid ; - assign cl_sh_ddr_araddr_2d[2] = s_axi_ddrd_araddr ; - assign cl_sh_ddr_arlen_2d[2] = s_axi_ddrd_arlen ; - assign cl_sh_ddr_arsize_2d[2] = s_axi_ddrd_arsize ; - assign cl_sh_ddr_arburst_2d[2] = 2'b01 ; - assign cl_sh_ddr_arvalid_2d[2] = s_axi_ddrd_arvalid ; - assign cl_sh_ddr_rready_2d[2] = s_axi_ddrd_rready ; - - assign s_axi_ddrd_awready = sh_cl_ddr_awready_2d[2] ; - assign s_axi_ddrd_wready = sh_cl_ddr_wready_2d[2] ; - assign s_axi_ddrd_bid = sh_cl_ddr_bid_2d[2] ; - assign s_axi_ddrd_bresp = sh_cl_ddr_bresp_2d[2] ; - assign s_axi_ddrd_bvalid = sh_cl_ddr_bvalid_2d[2] ; - assign s_axi_ddrd_arready = sh_cl_ddr_arready_2d[2] ; - assign s_axi_ddrd_rid = sh_cl_ddr_rid_2d[2] ; - assign s_axi_ddrd_rdata = sh_cl_ddr_rdata_2d[2] ; - assign s_axi_ddrd_rresp = sh_cl_ddr_rresp_2d[2] ; - assign s_axi_ddrd_rlast = sh_cl_ddr_rlast_2d[2] ; - assign s_axi_ddrd_rvalid = sh_cl_ddr_rvalid_2d[2] ; - assign ddrd_is_ready = sh_cl_ddr_is_ready_2d[2]; - - logic ddr_aws_stat_ack0; - logic [31:0] ddr_aws_stat_rdata0; - logic [7:0] ddr_aws_stat_int0; - logic ddr_aws_stat_ack1; - logic [31:0] ddr_aws_stat_rdata1; - logic [7:0] ddr_aws_stat_int1; - logic ddr_aws_stat_ack2; - logic [31:0] ddr_aws_stat_rdata2; - logic [7:0] ddr_aws_stat_int2; - - logic [7:0] pipe_ddr_stat_addr0; - logic pipe_ddr_stat_wr0; - logic pipe_ddr_stat_rd0; - logic [31:0] pipe_ddr_stat_wdata0; - logic ddr_pipe_stat_ack0; - logic [31:0] ddr_pipe_stat_rdata0; - logic [7:0] ddr_pipe_stat_int0; - - logic [7:0] pipe_ddr_stat_addr1; - logic pipe_ddr_stat_wr1; - logic pipe_ddr_stat_rd1; - logic [31:0] pipe_ddr_stat_wdata1; - logic ddr_pipe_stat_ack1; - logic [31:0] ddr_pipe_stat_rdata1; - logic [7:0] ddr_pipe_stat_int1; - - logic [7:0] pipe_ddr_stat_addr2; - logic pipe_ddr_stat_wr2; - logic pipe_ddr_stat_rd2; - logic [31:0] pipe_ddr_stat_wdata2; - logic ddr_pipe_stat_ack2; - logic [31:0] ddr_pipe_stat_rdata2; - logic [7:0] ddr_pipe_stat_int2; - -//------------------------------------------------- -// Tie-offs when DDRs are disabled -//------------------------------------------------- - assign ddr_sh_stat_ack0 = (C_DDR_A_PRESENT!=0) ? ddr_aws_stat_ack0 : 1'b1; - assign ddr_sh_stat_rdata0 = (C_DDR_A_PRESENT!=0) ? ddr_aws_stat_rdata0 : 0; - assign ddr_sh_stat_int0 = (C_DDR_A_PRESENT!=0) ? ddr_aws_stat_int0 : 8'b0; - assign ddr_sh_stat_ack1 = (C_DDR_B_PRESENT!=0) ? ddr_aws_stat_ack1 : 1'b1; - assign ddr_sh_stat_rdata1 = (C_DDR_B_PRESENT!=0) ? ddr_aws_stat_rdata1 : 0; - assign ddr_sh_stat_int1 = (C_DDR_B_PRESENT!=0) ? ddr_aws_stat_int1 : 8'b0; - assign ddr_sh_stat_ack2 = (C_DDR_D_PRESENT!=0) ? ddr_aws_stat_ack2 : 1'b1; - assign ddr_sh_stat_rdata2 = (C_DDR_D_PRESENT!=0) ? ddr_aws_stat_rdata2 : 0; - assign ddr_sh_stat_int2 = (C_DDR_D_PRESENT!=0) ? ddr_aws_stat_int2 : 8'b0; - -//------------------------------------------------- -// Reset Synchronization -//------------------------------------------------- - logic pre_sync_rst_n; - logic sync_rst_n; - - always @(negedge rst_main_n or posedge clk_main_a0) begin - if (!rst_main_n) begin - pre_sync_rst_n <= 1'b0; - sync_rst_n <= 1'b0; - end else begin - pre_sync_rst_n <= 1'b1; - sync_rst_n <= pre_sync_rst_n; - end - end - - `ifdef FPGA_LESS_RST - `undef FPGA_LESS_RST - `endif - - lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wdata0 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_wdata0), .out_bus(pipe_ddr_stat_wdata0)); - lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_addr0 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_addr0), .out_bus(pipe_ddr_stat_addr0)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wr0 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_wr0), .out_bus(pipe_ddr_stat_wr0)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rd0 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_rd0), .out_bus(pipe_ddr_stat_rd0)); - lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rdata0 (.clk(clk_main_a0), .rst_n(1'b1), .out_bus(ddr_aws_stat_rdata0), .in_bus(ddr_pipe_stat_rdata0)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_ack0 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_ack0), .in_bus(ddr_pipe_stat_ack0)); - lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_int0 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_int0), .in_bus(ddr_pipe_stat_int0)); - - lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wdata1 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_wdata1), .out_bus(pipe_ddr_stat_wdata1)); - lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_addr1 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_addr1), .out_bus(pipe_ddr_stat_addr1)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wr1 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_wr1), .out_bus(pipe_ddr_stat_wr1)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rd1 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_rd1), .out_bus(pipe_ddr_stat_rd1)); - lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rdata1 (.clk(clk_main_a0), .rst_n(1'b1), .out_bus(ddr_aws_stat_rdata1), .in_bus(ddr_pipe_stat_rdata1)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_ack1 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_ack1), .in_bus(ddr_pipe_stat_ack1)); - lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_int1 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_int1), .in_bus(ddr_pipe_stat_int1)); - - lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wdata2 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_wdata2), .out_bus(pipe_ddr_stat_wdata2)); - lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_addr2 (.clk(clk_main_a0), .rst_n(1'b1), .in_bus(sh_ddr_stat_addr2), .out_bus(pipe_ddr_stat_addr2)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_wr2 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_wr2), .out_bus(pipe_ddr_stat_wr2)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rd2 (.clk(clk_main_a0), .rst_n(sync_rst_n), .in_bus(sh_ddr_stat_rd2), .out_bus(pipe_ddr_stat_rd2)); - lib_pipe #(.WIDTH(32), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_rdata2 (.clk(clk_main_a0), .rst_n(1'b1), .out_bus(ddr_aws_stat_rdata2), .in_bus(ddr_pipe_stat_rdata2)); - lib_pipe #(.WIDTH(1), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_ack2 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_ack2), .in_bus(ddr_pipe_stat_ack2)); - lib_pipe #(.WIDTH(8), .STAGES(C_NUM_STAGES_STATS)) pipe_stat_int2 (.clk(clk_main_a0), .rst_n(sync_rst_n), .out_bus(ddr_aws_stat_int2), .in_bus(ddr_pipe_stat_int2)); - - sh_ddr #( - .DDR_A_PRESENT(C_DDR_A_PRESENT), - .DDR_B_PRESENT(C_DDR_B_PRESENT), - .DDR_D_PRESENT(C_DDR_D_PRESENT) - ) sh_ddr_0 - ( - .clk(clk_main_a0), - .rst_n(sync_rst_n), - - .stat_clk(clk_main_a0), - .stat_rst_n(sync_rst_n), - - .CLK_300M_DIMM0_DP(CLK_300M_DIMM0_DP), - .CLK_300M_DIMM0_DN(CLK_300M_DIMM0_DN), - .M_A_ACT_N(M_A_ACT_N), - .M_A_MA(M_A_MA), - .M_A_BA(M_A_BA), - .M_A_BG(M_A_BG), - .M_A_CKE(M_A_CKE), - .M_A_ODT(M_A_ODT), - .M_A_CS_N(M_A_CS_N), - .M_A_CLK_DN(M_A_CLK_DN), - .M_A_CLK_DP(M_A_CLK_DP), - .M_A_PAR(M_A_PAR), - .M_A_DQ(M_A_DQ), - .M_A_ECC(M_A_ECC), - .M_A_DQS_DP(M_A_DQS_DP), - .M_A_DQS_DN(M_A_DQS_DN), - .cl_RST_DIMM_A_N(cl_RST_DIMM_A_N), - - .CLK_300M_DIMM1_DP(CLK_300M_DIMM1_DP), - .CLK_300M_DIMM1_DN(CLK_300M_DIMM1_DN), - .M_B_ACT_N(M_B_ACT_N), - .M_B_MA(M_B_MA), - .M_B_BA(M_B_BA), - .M_B_BG(M_B_BG), - .M_B_CKE(M_B_CKE), - .M_B_ODT(M_B_ODT), - .M_B_CS_N(M_B_CS_N), - .M_B_CLK_DN(M_B_CLK_DN), - .M_B_CLK_DP(M_B_CLK_DP), - .M_B_PAR(M_B_PAR), - .M_B_DQ(M_B_DQ), - .M_B_ECC(M_B_ECC), - .M_B_DQS_DP(M_B_DQS_DP), - .M_B_DQS_DN(M_B_DQS_DN), - .cl_RST_DIMM_B_N(cl_RST_DIMM_B_N), - - .CLK_300M_DIMM3_DP(CLK_300M_DIMM3_DP), - .CLK_300M_DIMM3_DN(CLK_300M_DIMM3_DN), - .M_D_ACT_N(M_D_ACT_N), - .M_D_MA(M_D_MA), - .M_D_BA(M_D_BA), - .M_D_BG(M_D_BG), - .M_D_CKE(M_D_CKE), - .M_D_ODT(M_D_ODT), - .M_D_CS_N(M_D_CS_N), - .M_D_CLK_DN(M_D_CLK_DN), - .M_D_CLK_DP(M_D_CLK_DP), - .M_D_PAR(M_D_PAR), - .M_D_DQ(M_D_DQ), - .M_D_ECC(M_D_ECC), - .M_D_DQS_DP(M_D_DQS_DP), - .M_D_DQS_DN(M_D_DQS_DN), - .cl_RST_DIMM_D_N(cl_RST_DIMM_D_N), - - //------------------------------------------------------ - // AXI Slave Interfaces - //------------------------------------------------------ - .cl_sh_ddr_awid(cl_sh_ddr_awid_2d), - .cl_sh_ddr_awaddr(cl_sh_ddr_awaddr_2d), - .cl_sh_ddr_awlen(cl_sh_ddr_awlen_2d), - .cl_sh_ddr_awsize(cl_sh_ddr_awsize_2d), - .cl_sh_ddr_awburst(cl_sh_ddr_awburst_2d), - .cl_sh_ddr_awvalid(cl_sh_ddr_awvalid_2d), - .sh_cl_ddr_awready(sh_cl_ddr_awready_2d), - - .cl_sh_ddr_wid(cl_sh_ddr_wid_2d), - .cl_sh_ddr_wdata(cl_sh_ddr_wdata_2d), - .cl_sh_ddr_wstrb(cl_sh_ddr_wstrb_2d), - .cl_sh_ddr_wlast(cl_sh_ddr_wlast_2d), - .cl_sh_ddr_wvalid(cl_sh_ddr_wvalid_2d), - .sh_cl_ddr_wready(sh_cl_ddr_wready_2d), - - .sh_cl_ddr_bid(sh_cl_ddr_bid_2d), - .sh_cl_ddr_bresp(sh_cl_ddr_bresp_2d), - .sh_cl_ddr_bvalid(sh_cl_ddr_bvalid_2d), - .cl_sh_ddr_bready(cl_sh_ddr_bready_2d), - - .cl_sh_ddr_arid(cl_sh_ddr_arid_2d), - .cl_sh_ddr_araddr(cl_sh_ddr_araddr_2d), - .cl_sh_ddr_arlen(cl_sh_ddr_arlen_2d), - .cl_sh_ddr_arsize(cl_sh_ddr_arsize_2d), - .cl_sh_ddr_arburst(cl_sh_ddr_arburst_2d), - .cl_sh_ddr_arvalid(cl_sh_ddr_arvalid_2d), - .sh_cl_ddr_arready(sh_cl_ddr_arready_2d), - - .sh_cl_ddr_rid(sh_cl_ddr_rid_2d), - .sh_cl_ddr_rdata(sh_cl_ddr_rdata_2d), - .sh_cl_ddr_rresp(sh_cl_ddr_rresp_2d), - .sh_cl_ddr_rlast(sh_cl_ddr_rlast_2d), - .sh_cl_ddr_rvalid(sh_cl_ddr_rvalid_2d), - .cl_sh_ddr_rready(cl_sh_ddr_rready_2d), - - .sh_cl_ddr_is_ready(sh_cl_ddr_is_ready_2d), - - .sh_ddr_stat_addr0 (pipe_ddr_stat_addr0 ), - .sh_ddr_stat_wr0 (pipe_ddr_stat_wr0 ), - .sh_ddr_stat_rd0 (pipe_ddr_stat_rd0 ), - .sh_ddr_stat_wdata0 (pipe_ddr_stat_wdata0), - .ddr_sh_stat_ack0 (ddr_pipe_stat_ack0 ), - .ddr_sh_stat_rdata0 (ddr_pipe_stat_rdata0), - .ddr_sh_stat_int0 (ddr_pipe_stat_int0 ), - - .sh_ddr_stat_addr1 (pipe_ddr_stat_addr1 ), - .sh_ddr_stat_wr1 (pipe_ddr_stat_wr1 ), - .sh_ddr_stat_rd1 (pipe_ddr_stat_rd1 ), - .sh_ddr_stat_wdata1 (pipe_ddr_stat_wdata1), - .ddr_sh_stat_ack1 (ddr_pipe_stat_ack1 ), - .ddr_sh_stat_rdata1 (ddr_pipe_stat_rdata1), - .ddr_sh_stat_int1 (ddr_pipe_stat_int1 ), - - .sh_ddr_stat_addr2 (pipe_ddr_stat_addr2 ), - .sh_ddr_stat_wr2 (pipe_ddr_stat_wr2 ), - .sh_ddr_stat_rd2 (pipe_ddr_stat_rd2 ), - .sh_ddr_stat_wdata2 (pipe_ddr_stat_wdata2), - .ddr_sh_stat_ack2 (ddr_pipe_stat_ack2 ), - .ddr_sh_stat_rdata2 (ddr_pipe_stat_rdata2), - .ddr_sh_stat_int2 (ddr_pipe_stat_int2 ) - - ); - - end else begin : gen_non_mem - - assign s_axi_ddra_awready = 0; - assign s_axi_ddra_wready = 0; - assign s_axi_ddra_bid = 0; - assign s_axi_ddra_bresp = 0; - assign s_axi_ddra_bvalid = 0; - assign s_axi_ddra_arready = 0; - assign s_axi_ddra_rid = 0; - assign s_axi_ddra_rdata = 0; - assign s_axi_ddra_rresp = 0; - assign s_axi_ddra_rlast = 1'b1; - assign s_axi_ddra_rvalid = 0; - assign ddra_is_ready = 0; - - assign s_axi_ddrb_awready = 0; - assign s_axi_ddrb_wready = 0; - assign s_axi_ddrb_bid = 0; - assign s_axi_ddrb_bresp = 0; - assign s_axi_ddrb_bvalid = 0; - assign s_axi_ddrb_arready = 0; - assign s_axi_ddrb_rid = 0; - assign s_axi_ddrb_rdata = 0; - assign s_axi_ddrb_rresp = 0; - assign s_axi_ddrb_rlast = 1'b1; - assign s_axi_ddrb_rvalid = 0; - assign ddrb_is_ready = 0; - - assign s_axi_ddrd_awready = 0; - assign s_axi_ddrd_wready = 0; - assign s_axi_ddrd_bid = 0; - assign s_axi_ddrd_bresp = 0; - assign s_axi_ddrd_bvalid = 0; - assign s_axi_ddrd_arready = 0; - assign s_axi_ddrd_rid = 0; - assign s_axi_ddrd_rdata = 0; - assign s_axi_ddrd_rresp = 0; - assign s_axi_ddrd_rlast = 1'b1; - assign s_axi_ddrd_rvalid = 0; - assign ddrd_is_ready = 0; - - assign ddr_sh_stat_ack0 = 1'b1; - assign ddr_sh_stat_rdata0 = 0; - assign ddr_sh_stat_int0 = 8'b0; - assign ddr_sh_stat_ack1 = 1'b1; - assign ddr_sh_stat_rdata1 = 0; - assign ddr_sh_stat_int1 = 8'b0; - assign ddr_sh_stat_ack2 = 1'b1; - assign ddr_sh_stat_rdata2 = 0; - assign ddr_sh_stat_int2 = 8'b0; - - assign M_A_ACT_N = 0; - assign M_A_MA = 0; - assign M_A_BA = 0; - assign M_A_BG = 0; - assign M_A_CKE = 0; - assign M_A_ODT = 0; - assign M_A_CS_N = 0; - assign M_A_CLK_DN = 0; - assign M_A_CLK_DP = 0; - assign M_A_PAR = 0; - assign cl_RST_DIMM_A_N = 0; - - assign M_B_ACT_N = 0; - assign M_B_MA = 0; - assign M_B_BA = 0; - assign M_B_BG = 0; - assign M_B_CKE = 0; - assign M_B_ODT = 0; - assign M_B_CS_N = 0; - assign M_B_CLK_DN = 0; - assign M_B_CLK_DP = 0; - assign M_B_PAR = 0; - assign cl_RST_DIMM_B_N = 0; - - assign M_D_ACT_N = 0; - assign M_D_MA = 0; - assign M_D_BA = 0; - assign M_D_BG = 0; - assign M_D_CKE = 0; - assign M_D_ODT = 0; - assign M_D_CS_N = 0; - assign M_D_CLK_DN = 0; - assign M_D_CLK_DP = 0; - assign M_D_PAR = 0; - assign cl_RST_DIMM_D_N = 0; - - end // gen_mem - endgenerate - -endmodule - - diff --git a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/lib_pipe.sv b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/lib_pipe.sv new file mode 120000 index 00000000..c55fd543 --- /dev/null +++ b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/lib_pipe.sv @@ -0,0 +1 @@ +../../../../../design/lib/lib_pipe.sv \ No newline at end of file diff --git a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/sim b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/sim new file mode 120000 index 00000000..4eb7f5ae --- /dev/null +++ b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/sim @@ -0,0 +1 @@ +../../../../../design/sh_ddr/sim \ No newline at end of file diff --git a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/sim/gray.inc b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/sim/gray.inc deleted file mode 100755 index 35e3b5ac..00000000 --- a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/sim/gray.inc +++ /dev/null @@ -1,54 +0,0 @@ -// SHA: bddf8457046b3a64e63d28d7e334020b6f1d09ee -`pragma protect begin_protected -`pragma protect version = 1 -`pragma protect encrypt_agent = "XILINX" -`pragma protect encrypt_agent_info = "Xilinx Encryption Tool 2015" -`pragma protect key_keyowner = "Xilinx", key_keyname = "xilinxt_2017_05", key_method = "rsa" -`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 256) -`pragma protect key_block -iWZCE953hJCDyIc+ne+gwzh8qXsoHncv0uZD9mD+v5fx+PEpRYsrUwVcqY8NGks/8KrnC1SNztDZ -curQivQImMnSoAGPeG2bNV8bmkBS1rhgCF+dM7tLc6A2UDWpvGzLUBwtZEoYGo9qI/brjagfJ4AB -rEXslIMBpU4DM78ZslW+HuM6LGQaxRCRc5YmcX9lULqKp4gcYejmK7bNBZVoMQPaxbOJKJ6Shm8B -OwZERFn7ecS2YTdmKNHaXgTG11pozaLBWmvQ9dAoBbjBP2u9av9r72qQ/x/sB/rBhukAV1tbxMRT -N5VdaW8njTW1/BmqfN0EYNrisu9/VrhCD8CpOw== - -`pragma protect data_method = "AES128-CBC" -`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 2048) -`pragma protect data_block -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 -`pragma protect end_protected diff --git a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/synth b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/synth new file mode 120000 index 00000000..85198b6a --- /dev/null +++ b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/synth @@ -0,0 +1 @@ +../../../../../design/sh_ddr/synth \ No newline at end of file diff --git a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/synth/gray.inc b/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/synth/gray.inc deleted file mode 100755 index d1576016..00000000 --- a/hdk/common/shell_v04261818/hlx/design/ip/aws_v1_0/hdl/synth/gray.inc +++ /dev/null @@ -1,61 +0,0 @@ -// SHA: bddf8457046b3a64e63d28d7e334020b6f1d09ee -`pragma protect begin_protected -`pragma protect version = 2 -`pragma protect encrypt_agent = "XILINX" -`pragma protect encrypt_agent_info = "Xilinx Encryption Tool 2015" -`pragma protect begin_commonblock -`pragma protect control error_handling="delegated" -`pragma protect end_commonblock -`pragma protect begin_toolblock -`pragma protect rights_digest_method="sha256" -`pragma protect key_keyowner = "Xilinx", key_keyname= "xilinxt_2017_05", key_method = "rsa", key_block -GQ3cf/VGHY0xKfRLLTPQZDazEA3OyQ5p2SCdrSlmdPjCM7yE2VcditpKLLWOfn5+0jtL5Uy85K3Z -RJNHMY3ze7jXvEClcJ2Vzp4fwkFCOlM/vh4YGp9wET1CUY56wndycOW/RlHrhiqDq2bXfR7NoD8w -aUaWced9KaFJ122f3nIBhocYiGlY/mHq0LOkoyK9v0rxbrTOm4QTm9WMLhpFX5+pN2RWspU3lhH4 -4c0N26aRVupP7gBcHGRqsMPfRxZ8cjR5JDjSAuOQjPsOBwlBb2C6oraqRKgBy/u0d80adeVoucHF -MEe7jM34roCrBZ0ebqJX8uHjLcNKZfzAt+w65g== - -`pragma protect control xilinx_configuration_visible = "false" -`pragma protect control xilinx_enable_modification = "false" -`pragma protect control xilinx_enable_probing = "false" -`pragma protect end_toolblock="+F6HPoNYthaGX52y+5DOhQmlp8k/oolHCsFRV36MRR8=" -`pragma protect data_method = "AES128-CBC" -`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 2048) -`pragma protect data_block -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 -`pragma protect end_protected diff --git a/hdk/common/shell_v04261818/hlx/hlx_examples/build/IPI/cl_hls_dds/software/test_cl.c b/hdk/common/shell_v04261818/hlx/hlx_examples/build/IPI/cl_hls_dds/software/test_cl.c index 86a70410..605d3094 100755 --- a/hdk/common/shell_v04261818/hlx/hlx_examples/build/IPI/cl_hls_dds/software/test_cl.c +++ b/hdk/common/shell_v04261818/hlx/hlx_examples/build/IPI/cl_hls_dds/software/test_cl.c @@ -67,8 +67,8 @@ int main(int argc, char **argv) { int slot_id; /* initialize the fpga_pci library so we could have access to FPGA PCIe from this applications */ - rc = fpga_pci_init(); - fail_on(rc, out, "Unable to initialize the fpga_pci library"); + rc = fpga_mgmt_init(); + fail_on(rc, out, "Unable to initialize the fpga_mgmt library"); /* This demo works with single FPGA slot, we pick slot #0 as it works for both f1.2xl and f1.16xl */ diff --git a/hdk/common/shell_v04261818/hlx/hlx_examples/build/IPI/cl_ipi_cdma_test/software/test_cl.c b/hdk/common/shell_v04261818/hlx/hlx_examples/build/IPI/cl_ipi_cdma_test/software/test_cl.c index d8ca274c..afe30616 100644 --- a/hdk/common/shell_v04261818/hlx/hlx_examples/build/IPI/cl_ipi_cdma_test/software/test_cl.c +++ b/hdk/common/shell_v04261818/hlx/hlx_examples/build/IPI/cl_ipi_cdma_test/software/test_cl.c @@ -69,9 +69,9 @@ int main(int argc, char **argv) { int rc; int slot_id; - /* initialize the fpga_pci library so we could have access to FPGA PCIe from this applications */ - rc = fpga_pci_init(); - fail_on(rc, out, "Unable to initialize the fpga_pci library"); + /* initialize the fpga_mgmt library so we could have access to FPGA PCIe from this applications */ + rc = fpga_mgmt_init(); + fail_on(rc, out, "Unable to initialize the fpga_mgmt library"); /* This demo works with single FPGA slot, we pick slot #0 as it works for both f1.2xl and f1.16xl */ diff --git a/hdk/common/shell_v04261818/hlx/hlx_examples/build/IPI/hello_world/software/test_cl.c b/hdk/common/shell_v04261818/hlx/hlx_examples/build/IPI/hello_world/software/test_cl.c index a6f57084..41454624 100755 --- a/hdk/common/shell_v04261818/hlx/hlx_examples/build/IPI/hello_world/software/test_cl.c +++ b/hdk/common/shell_v04261818/hlx/hlx_examples/build/IPI/hello_world/software/test_cl.c @@ -55,8 +55,8 @@ int main(int argc, char **argv) { int rc; int slot_id; - /* initialize the fpga_pci library so we could have access to FPGA PCIe from this applications */ - rc = fpga_pci_init(); + /* initialize the fpga_mgmt library */ + rc = fpga_mgmt_init(); fail_on(rc, out, "Unable to initialize the fpga_pci library"); /* This demo works with single FPGA slot, we pick slot #0 as it works for both f1.2xl and f1.16xl */ @@ -66,19 +66,14 @@ int main(int argc, char **argv) { rc = check_afi_ready(slot_id); fail_on(rc, out, "AFI not ready"); - printf("\n"); printf("===== Hello World Example =====\n"); rc = peek_poke_example(slot_id, FPGA_APP_PF, APP_PF_BAR1); fail_on(rc, out, "peek-poke example failed"); - - - return rc; - out: return 1; } diff --git a/hdk/docs/AFI_Manifest.md b/hdk/docs/AFI_Manifest.md index 1e030854..40588cb3 100644 --- a/hdk/docs/AFI_Manifest.md +++ b/hdk/docs/AFI_Manifest.md @@ -40,6 +40,7 @@ The manifest file is a text file formatted with key=value pairs. Some keys are m | vivado tool version | field value | |------------------- | -----------| +| 2019.1 | tool_version=v2019.1 | | 2018.3 | tool_version=v2018.3 | | 2018.2 | tool_version=v2018.2 | | 2017.4 | tool_version=v2017.4 | diff --git a/hdk/docs/AWS_Shell_Interface_Specification.md b/hdk/docs/AWS_Shell_Interface_Specification.md index 827e9964..99be458a 100644 --- a/hdk/docs/AWS_Shell_Interface_Specification.md +++ b/hdk/docs/AWS_Shell_Interface_Specification.md @@ -316,7 +316,8 @@ Each DRAM interface is accessed via an AXI-4 interface: There is a single status signal that the DRAM interface is trained and ready for access. DDR access should be gated when the DRAM interface is not ready. The addressing uses ROW/COLUMN/BANK (Interleaved) mapping of AXI address to DRAM Row/Col/BankGroup. The Read and Write channels are serviced with round-robin arbitration (i.e. equal priority). -The DRAM interface uses the Xilinx DDR-4 Interface controller. The AXI-4 interface adheres to the Xilinx specification. Uncorrectable ECC errors are signaled with RRESP. ECC error status can be read using AWS Management Software APIs. +The DRAM interface uses the Xilinx DDR-4 Interface controller. The AXI-4 interface adheres to the Xilinx specification. Uncorrectable ECC errors are signaled with RRESP. A CL can be designed to handle ECC errors by monitoring RRESP on the DDR AXI interfaces. The CL will receive a SLVERR RRESP on an uncorrectable ECC error. +**NOTE:** Writing to a DDR location is required before reading the DDR location to initialize the ECC. False ECC errors may occur when un-initialized DDR locations are read. Additionally, there are three statistics interfaces between the Shell and CL (one for each CL DDR controller). If the DDR controllers are being used by the CL, then the interfaces must be connected between the Shell and the DRAM interface controller modules. diff --git a/hdk/docs/IPI_GUI_Vivado_Setup.md b/hdk/docs/IPI_GUI_Vivado_Setup.md index 0d1d628d..5888256c 100644 --- a/hdk/docs/IPI_GUI_Vivado_Setup.md +++ b/hdk/docs/IPI_GUI_Vivado_Setup.md @@ -46,7 +46,7 @@ In init.tcl or Vivado\_init.tcl, add the following line based upon the $HDK\_SHE # Windows Install -Download, install, and configure the license for Vivado SDx 2017.4 or Vivado 2018.2 or Vivado 2018.3 for Windows. More information is provided at: +Download, install, and configure the license for Vivado SDx 2017.4, 2018.2, 2018.3 or 2019.1 for Windows. More information is provided at: [On-Premises Licensing Help](./on_premise_licensing_help.md) diff --git a/hdk/docs/RTL_Simulating_CL_Designs.md b/hdk/docs/RTL_Simulating_CL_Designs.md index 39540f1f..957d79a6 100644 --- a/hdk/docs/RTL_Simulating_CL_Designs.md +++ b/hdk/docs/RTL_Simulating_CL_Designs.md @@ -4,12 +4,12 @@ Developers tend to simulate their designs to validate the RTL design and functionality, before hitting the build stage and registering it with AWS EC2 as Amazon FPGA Image (AFI). AWS FPGA HDK comes with a shell simulation model that supports RTL-level simulation using Xilinx' Vivado XSIM, MentorGraphics' Questa, Cadence Incisive and Synopsys' VCS RTL simulators. See table below for supported simulator versions. -| 3rd party simulator Tool | 2017.4 Vivado tool | 2018.2 Vivado tool | 2018.3 Vivado tool | -|--------------------------|--------------------|--------------------|--------------------| -| Xilinx Vivado XSIM | Vivado v2017.4.op (64-bit) | Vivado v2018.2_AR71275_op (64-bit) | Vivado v2018.3.op (64-bit) | -| Synopsys VCS | vcs-mx/M-2017.03-SP2-11 | vcs-mx/N-2017.12-SP1-1 | vcs-mx/N-2017.12-SP2 | -| Mentor Graphics Questa | 10.6b | 10.6c_1 | 10.6c_1 | -| Cadence Incisive Enterprise Simulator(IES) | 15.20.063 | 15.20.063 | 15.20.063 | +| Simulator | Vivado 2017.4 | Vivado 2018.2 | Vivado 2018.3 | Vivado 2019.1 | +|--------------------------|--------------------|--------------------|--------------------|---| +| Xilinx Vivado XSIM | Vivado v2017.4 | Vivado v2018.2 | Vivado v2018.3 |Vivado v2019.1 | +| Synopsys VCS | M-2017.03-SP2-11 | N-2017.12-SP1-1 | N-2017.12-SP2 | O-2018.09 | +| Mentor Graphics Questa | 10.6b | 10.6c_1 | 10.6c_1 | 10.7c | +| Cadence Incisive Enterprise Simulator(IES) | 15.20.063 | 15.20.063 | 15.20.063 | 15.20.065 | Developers can write their tests in SystemVerilog and/or C languages. If a developer chooses to use the supplied C framework, he/she can use the same C code for simulation and for runtime on your FPGA-enabled instance like F1. diff --git a/hdk/docs/on_premise_licensing_help.md b/hdk/docs/on_premise_licensing_help.md index 06059c9b..cab84d18 100644 --- a/hdk/docs/on_premise_licensing_help.md +++ b/hdk/docs/on_premise_licensing_help.md @@ -5,6 +5,14 @@ This document helps developers who choose to develop on-premises with specifying and licensing AWS-compatible Xilinx tools for use with the AWS FPGA HDK. +## Requirements for AWS HDK 1.4.11+ (2019.1) + * Xilinx Vivado v2019.1 or v2019.1.op (64-bit) + * License: EF-VIVADO-SDX-VU9P-OP + * SW Build 2552052 on Fri May 24 14:47:09 MDT 2019 + * IP Build 2548770 on Fri May 24 18:01:18 MDT 2019 + * URL: https://www.xilinx.com/member/forms/download/xef.html?filename=Xilinx_SDAccel_2019.1_0524_1430_Lin64.bin + * MD5 SUM Value: aa20eba36ebe480ec7ae59a4a8c85896 + ## Requirements for AWS HDK 1.4.8+ (2018.3) * Xilinx Vivado v2018.3 or v2018.3.op (64-bit) * License: EF-VIVADO-SDX-VU9P-OP diff --git a/hdk/hdk_version.txt b/hdk/hdk_version.txt index ed64e996..e05658b5 100644 --- a/hdk/hdk_version.txt +++ b/hdk/hdk_version.txt @@ -1 +1 @@ -HDK_VERSION=1.4.10 \ No newline at end of file +HDK_VERSION=1.4.11 diff --git a/hdk/tests/test_gen_dcp.py b/hdk/tests/test_gen_dcp.py index d2ccd22d..0a995623 100644 --- a/hdk/tests/test_gen_dcp.py +++ b/hdk/tests/test_gen_dcp.py @@ -93,12 +93,15 @@ def set_allowed_warnings(cls): (('.*',), r'WARNING: \[Place 30-640\] Place Check.*'), (('.*',), r'WARNING: \[BD 41-2180\] Resetting the memory initialization file.*'), (('.*',), r'WARNING: \[Synth 8-689\] .*'), + (('.*',), r'WARNING: \[Synth 8-6896\] .*'), + (('.*',), r'WARNING: \[Synth 8-7023\] .*'), (('cl_sde_*',), r'WARNING: \[Vivado 12-180\] No cells matched .*'), (('cl_sde_*',), r'WARNING: \[Vivado 12-1008\] No clocks found for command.*'), (('cl_sde_*',), r'CRITICAL WARNING: \[Designutils 20-1280\] .*'), (('cl_sde_*',), r'^CRITICAL WARNING: \[Constraints 18-952\] .*'), (('cl_sde_*',), r'^CRITICAL WARNING: \[Vivado 12-1039\] .*'), (('cl_sde_*',), r'^CRITICAL WARNING: \[Vivado 12-1433\] .*'), + (('cl_sde.*',), r'WARNING: \[Synth 8-6057\] Memory.*'), (('cl_dram_dma_A1_B2_C0_2_(CONGESTION|BASIC)',), r'^CRITICAL WARNING: \[Route 35-39\] The design did not meet timing requirements'), (('cl_dram_dma_A1_B2_C0_2_(CONGESTION|TIMING)',), r'WARNING: \[Vivado 12-180\] No cells matched \'CL/CL_DMA_PCIS_SLV/CL_TST_DDR_B/CL_TST/sync_rst_n_reg\''), (('cl_dram_dma_*',), r'CRITICAL WARNING: \[Designutils 20-1280\] Could not find module \'bd_bf3f_microblaze_I_0\''), diff --git a/hdk/tests/test_hdk_scripts.py b/hdk/tests/test_hdk_scripts.py index d6b49de2..cfa2c8a2 100644 --- a/hdk/tests/test_hdk_scripts.py +++ b/hdk/tests/test_hdk_scripts.py @@ -58,12 +58,6 @@ def test_create_fpga_image(self): def test_wait_for_afi(self): self.run_cmd("{}/shared/bin/scripts/wait_for_afi.py --afi {}".format(self.WORKSPACE, self.afi)) - def test_wait_for_afi_python27(self): - self.run_cmd("python2.7 {}/shared/bin/scripts/wait_for_afi.py --afi {}".format(self.WORKSPACE, self.afi)) - - def test_wait_for_afi_python34(self): - self.run_cmd("python3.4 {}/shared/bin/scripts/wait_for_afi.py --afi {}".format(self.WORKSPACE, self.afi)) - @pytest.mark.skip(reason="Not implemented") def test_notify_via_sns(self): assert False diff --git a/sdaccel_runtime_setup.sh b/sdaccel_runtime_setup.sh index 4f3b4346..bc735cd1 100644 --- a/sdaccel_runtime_setup.sh +++ b/sdaccel_runtime_setup.sh @@ -117,8 +117,8 @@ function check_kernel_ver { cat $AWS_FPGA_REPO_DIR/SDAccel/kernel_version.txt warn_msg "Xilinx Runtime not validated against your installed kernel version." fi - } + # Process command line args args=( "$@" ) for (( i = 0; i < ${#args[@]}; i++ )); do @@ -144,11 +144,13 @@ done if ! exists vivado; then if [[ -z "${VIVADO_TOOL_VERSION}" ]]; then - err_msg " You are not using FPGA Developer AMI and VIVADO_TOOL_VERSION ENV variable is Empty. " - err_msg " ENV Variable VIVADO_TOOL_VERSION is required to be set for runtime " + err_msg " VIVADO_TOOL_VERSION ENV variable is not set." + err_msg " ENV Variable VIVADO_TOOL_VERSION needs to be set for runtime usage. " + err_msg " If AFI was generated using V2019.1 tools use the command : export VIVADO_TOOL_VERSION=2019.1 " + err_msg " If AFI was generated using V2018.3 tools use the command : export VIVADO_TOOL_VERSION=2018.3 " err_msg " If AFI was generated using V2018.2 tools use the command : export VIVADO_TOOL_VERSION=2018.2 " err_msg " If AFI was generated using V2017.4 tools use the command : export VIVADO_TOOL_VERSION=2017.4 " - err_msg " If you are using the FPGA Developer AMI then please request support on AWS FPGA Developers Forum." + err_msg " Please set VIVADO_TOOL_VERSION to the correct value and re-run script." return 1 else info_msg " VIVADO tools not found. Reading VIVADO_TOOL_VERSION ENV variable to determine runtime version... " @@ -167,7 +169,7 @@ check_kernel_ver check_xdma_driver check_edma_driver -if [[ "$VIVADO_TOOL_VERSION" =~ .*2018\.2.* || "$VIVADO_TOOL_VERSION" =~ .*2018\.3.* ]]; then +if [[ "$VIVADO_TOOL_VERSION" =~ .*2018\.2.* || "$VIVADO_TOOL_VERSION" =~ .*2018\.3.* || "$VIVADO_TOOL_VERSION" =~ .*2019\.1.* ]]; then info_msg "Xilinx Vivado version is $VIVADO_TOOL_VERSION" if [ $override == 1 ]; then @@ -190,12 +192,12 @@ if [[ "$VIVADO_TOOL_VERSION" =~ .*2018\.2.* || "$VIVADO_TOOL_VERSION" =~ .*2018\ if [ -f "/opt/xilinx/xrt/setup.sh" ]; then source /opt/xilinx/xrt/setup.sh else - err_msg " Cannot find /opt/xilinx/xrt/setup.sh " - err_msg " Please check XRT is installed correctly " - err_msg "Please Refer $AWS_FPGA_REPO/SDAccel/doc/XRT_installation_instructions.md for XRT installation instructions" + err_msg " Cannot find /opt/xilinx/xrt/setup.sh" + err_msg " Please check XRT is installed correctly" + err_msg " Please Refer to $AWS_FPGA_REPO/SDAccel/doc/XRT_installation_instructions.md for XRT installation instructions" return 1 fi - info_msg " XRT Runtime setup Done " + info_msg " XRT Runtime setup Done" else err_msg "$xrt_build_ver does not match recommended versions" cat $AWS_FPGA_REPO_DIR/SDAccel/sdaccel_xrt_version.txt @@ -209,7 +211,6 @@ if [[ "$VIVADO_TOOL_VERSION" =~ .*2018\.2.* || "$VIVADO_TOOL_VERSION" =~ .*2018\ fi else info_msg "Xilinx Vivado version is $VIVADO_TOOL_VERSION " - #info_msg " checking for file: /opt/Xilinx/SDx/${VIVADO_TOOL_VERSION}.rte.dyn/setup.sh" info_msg " Now checking XOCL driver..." check_xocl_driver if [ -f "/opt/Xilinx/SDx/${VIVADO_TOOL_VERSION}.rte.dyn/setup.sh" ]; then diff --git a/sdaccel_setup.sh b/sdaccel_setup.sh index a5d00445..2d17953e 100644 --- a/sdaccel_setup.sh +++ b/sdaccel_setup.sh @@ -171,7 +171,7 @@ setup_patches # Update Xilinx SDAccel Examples from GitHub info_msg "Using SDx $RELEASE_VER" -if [[ $RELEASE_VER =~ .*2017\.4.* || $RELEASE_VER =~ .*2018\.2.* || $RELEASE_VER =~ .*2018\.3.* ]]; then +if [[ $RELEASE_VER =~ .*2017\.4.* || $RELEASE_VER =~ .*2018\.2.* || $RELEASE_VER =~ .*2018\.3.* || $RELEASE_VER =~ .*2019\.1.* ]]; then info_msg "Updating Xilinx SDAccel Examples $RELEASE_VER" git submodule update --init -- SDAccel/examples/xilinx_$RELEASE_VER export VIVADO_TOOL_VER=$RELEASE_VER @@ -183,8 +183,8 @@ if [[ $RELEASE_VER =~ .*2017\.4.* || $RELEASE_VER =~ .*2018\.2.* || $RELEASE_VER fi ln -sf $SDACCEL_DIR/examples/xilinx_$RELEASE_VER $SDACCEL_DIR/examples/xilinx else - echo " $RELEASE_VER is not supported (2017.4, 2018.2 & 2018.3 are supported).\n" - exit 2 + echo " $RELEASE_VER is not supported (2017.4, 2018.2, 2018.3 and 2019.1 are supported).\n" + return 2 fi # settings64 removal - once we put this in the AMI, we will add a check diff --git a/sdk/linux_kernel_drivers/xdma/xdma_install.md b/sdk/linux_kernel_drivers/xdma/xdma_install.md index db2aaef1..b0803b3f 100644 --- a/sdk/linux_kernel_drivers/xdma/xdma_install.md +++ b/sdk/linux_kernel_drivers/xdma/xdma_install.md @@ -66,7 +66,7 @@ __*For Suse*__ __**Step 2**__: Clone the git repo locally under my_fpga_dir for example: ``` - $ mkdir -p + $ mkdir -p $ cd $ git clone https://github.com/aws/aws-fpga ``` diff --git a/sdk/tests/test_fpga_tools.py b/sdk/tests/test_fpga_tools.py index 53a5805d..ff2629a4 100644 --- a/sdk/tests/test_fpga_tools.py +++ b/sdk/tests/test_fpga_tools.py @@ -48,6 +48,7 @@ class TestFpgaTools(BaseSdkTools): Test FPGA AFI Management tools described in ../userspace/fpga_mgmt_tools/README.md ''' + @pytest.mark.flaky(reruns=2, reruns_delay=5) def test_describe_local_image_slots(self): for slot in range(self.num_slots): self.fpga_clear_local_image(slot) @@ -88,6 +89,7 @@ def test_describe_local_image_slots(self): assert stdout[slot * 3 + 1] == 'AFIDEVICE {} 0x1d0f 0x1042 {}'.format(slot, self.slot2device[slot]), "slot={}\n{}".format(slot, "\n".join(stdout)) assert stdout[slot * 3 + 2] == 'AFIDEVICE {} 0x1d0f 0x1041 {}'.format(slot, self.slot2mbox_device[slot]), "slot={}\n{}".format(slot, "\n".join(stdout)) + @pytest.mark.flaky(reruns=2, reruns_delay=5) def test_describe_local_image(self): for slot in range(self.num_slots): self.fpga_clear_local_image(slot) @@ -127,6 +129,7 @@ def test_describe_local_image(self): assert stdout[50] == 'Clock Group C Frequency (Mhz)' assert stdout[51] == '0 0 ' + @pytest.mark.flaky(reruns=2, reruns_delay=5) def test_load_local_image(self): for slot in range(self.num_slots): (rc, stdout, stderr) = self.run_cmd("sudo fpga-load-local-image --request-timeout {} -S {} -I {}".format(self.DEFAULT_REQUEST_TIMEOUT, slot, self.cl_hello_world_agfi), echo=True) @@ -173,6 +176,7 @@ def test_load_local_image(self): assert stdout[1] == 'AFIDEVICE {} 0x1d0f 0xf000 {}'.format(slot, self.slot2device[slot]) self.fpga_clear_local_image(slot) + @pytest.mark.flaky(reruns=2, reruns_delay=5) def test_clear_local_image(self): for slot in range(self.num_slots): # Test clearing already cleared @@ -230,6 +234,7 @@ def test_start_virtual_jtag(self): assert stdout[0] == 'AFI {} none cleared 1 ok 0 {}'.format(slot, self.shell_version) assert stdout[1] == 'AFIDEVICE {} 0x1d0f 0x1042 {}'.format(self.slot2device[slot]) + @pytest.mark.flaky(reruns=2, reruns_delay=5) def test_get_virtual_led(self): # This is tested in the cl_hello_world example for slot in range(self.num_slots): @@ -241,6 +246,7 @@ def test_get_virtual_led(self): assert stdout[0] == 'FPGA slot id {} have the following Virtual LED:'.format(slot) assert re.match('[01]{4}-[01]{4}-[01]{4}-[01]{4}', stdout[1]) + @pytest.mark.flaky(reruns=2, reruns_delay=5) def test_virtual_dip_switch(self): for slot in range(self.num_slots): # Start it on an empty slot @@ -260,6 +266,8 @@ def test_virtual_dip_switch(self): assert stdout[0] == 'FPGA slot id {} has the following Virtual DIP Switches:'.format(slot) assert stdout[1] == '1111-1111-1111-1111' + # Add extra delay in case we have a lot of slot loads + @pytest.mark.flaky(reruns=2, reruns_delay=10) def test_parallel_slot_loads(self): def run_slot(slot): for afi in [self.cl_dram_dma_agfi, self.cl_hello_world_agfi, self.cl_dram_dma_agfi]: diff --git a/sdk/tests/test_non_root_access.py b/sdk/tests/test_non_root_access.py index 09482b0b..df3303f7 100755 --- a/sdk/tests/test_non_root_access.py +++ b/sdk/tests/test_non_root_access.py @@ -78,6 +78,6 @@ def test_hello_world_as_non_root_user(self): for slot in range(AwsFpgaTestBase.num_slots): (rc, out, err) = self.run_cmd("bash -x {}/sdk/tests/non_root_log_into_group.sh {}".format(os.environ['WORKSPACE'], slot)) logger.info("{}\n{}".format(out, err)) - assert rc == 0 + assert rc == 0 AwsFpgaTestBase.fpga_set_virtual_dip_switch("1111111111111111", slot, as_root=False) - assert AwsFpgaTestBase.fpga_get_virtual_led(slot, as_root=False) == "1010-1101-1101-1110" + assert AwsFpgaTestBase.fpga_get_virtual_led(slot, as_root=False) == "1010-1101-1101-1110" diff --git a/sdk/tests/test_sdk_scripts.py b/sdk/tests/test_sdk_scripts.py index c6964d87..2d5738cf 100644 --- a/sdk/tests/test_sdk_scripts.py +++ b/sdk/tests/test_sdk_scripts.py @@ -54,8 +54,5 @@ def test_sdk_setup(self): logger.info(self) assert False - def test_fio_tools_setup_python27(self): - self.setup_fio_tools(python_version=2.7) - - def test_fio_tools_setup_python34(self): - self.setup_fio_tools(python_version=3.4) + def test_fio_tools_setup(self): + self.setup_fio_tools() diff --git a/sdk/userspace/fpga_mgmt_tools/README.md b/sdk/userspace/fpga_mgmt_tools/README.md index f59bc9f6..6f21b393 100644 --- a/sdk/userspace/fpga_mgmt_tools/README.md +++ b/sdk/userspace/fpga_mgmt_tools/README.md @@ -144,7 +144,7 @@ The following command displays the current state for the given FPGA slot number. ### Looking at Metrics -The `fpga-describe-local-image` **`metrics`** option may be used to display FPGA image hardware metrics including FPGA PCI and DDR ECC metrics. +The `fpga-describe-local-image` **`metrics`** option may be used to display FPGA image hardware metrics including FPGA PCI and DDR metrics. Additionally, the `fpga-describe-local-image` **`clear-metrics`** option may be used to display and clear FPGA image hardware metrics (clear on read). diff --git a/sdk/userspace/install_fpga_mgmt_tools.sh b/sdk/userspace/install_fpga_mgmt_tools.sh index e929bc44..740665ca 100755 --- a/sdk/userspace/install_fpga_mgmt_tools.sh +++ b/sdk/userspace/install_fpga_mgmt_tools.sh @@ -68,6 +68,7 @@ echo "AWS FPGA: Copying Amazon FPGA Image (AFI) Management Tools to $AFI_MGMT_TO cp -f $AFI_MGMT_TOOLS_SRC_DIR/fpga-* $AFI_MGMT_TOOLS_DST_DIR cp -f $AFI_MGMT_TOOLS_LIB_DIR/libfpga_mgmt.so.1.0.0 $AFI_MGMT_LIBS_DST_DIR ln -sf libfpga_mgmt.so.1 $AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so +ln -sf libfpga_mgmt.so.1.0.0 $AFI_MGMT_LIBS_DST_DIR/libfpga_mgmt.so.1 source /tmp/sdk_root_env.exp if allow_non_root ; then diff --git a/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py b/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py index c2183725..be82b060 100644 --- a/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py +++ b/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py @@ -301,9 +301,10 @@ def get_sdaccel_example_s3_afi_tag(examplePath, target, rteName, xilinxVersion): return "{}/create-afi/afi-ids.txt".format(root_tag) @staticmethod - def get_sdaccel_example_run_cmd(examplePath): + def get_sdaccel_example_run_cmd(examplePath, xilinxVersion): ''' @param examplePath: Path of the Xilinx SDAccel example + @param xilinxVersion: The Xilinx tool version ''' description = AwsFpgaTestBase.get_sdaccel_example_description(examplePath) if description.get("em_cmd", None): @@ -313,9 +314,15 @@ def get_sdaccel_example_run_cmd(examplePath): run_cmd = "./{}".format(description.get("host_exe", None)) if description.get("cmd_args", None): if "PROJECT" not in description.get("cmd_args", None) and "BUILD" not in description.get("cmd_args", None): - run_cmd += " {}".format(description.get("cmd_args", None)) + if "2019.1" not in xilinxVersion: + run_cmd += " {}".format(description.get("cmd_args", None)) + else: + run_cmd += " {}".format(description.get("cmd_args", None).replace(".xclbin",".hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.xclbin")) else: - run_cmd += " {}".format((description.get("cmd_args", None).replace("PROJECT",".")).replace("BUILD","./xclbin")) + if "2019.1" not in xilinxVersion: + run_cmd += " {}".format((description.get("cmd_args", None).replace("PROJECT",".")).replace("BUILD","./xclbin")) + else: + run_cmd += " {}".format(((description.get("cmd_args", None).replace(".xclbin",".hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin")).replace("PROJECT",".")).replace("BUILD","./xclbin")) assert run_cmd is not None, "Could not find run_cmd(em_cmd) or (host_exe) in the example description here {}".format(examplePath) @@ -518,7 +525,7 @@ def get_fio_write_benchmark_script(driver='xdma'): return os.path.join(AwsFpgaTestBase.get_fio_tool_root(), "scripts/{}_4-ch_4-1M_write.fio".format(driver)) @staticmethod - def setup_fio_tools(python_version=2.7): + def setup_fio_tools(): '''Install and setup fio tools''' # If downloaded repo already, exists, delete it so we can fetch again if os.path.exists(AwsFpgaTestBase.get_fio_tool_install_path()): @@ -526,7 +533,7 @@ def setup_fio_tools(python_version=2.7): logger.info("Installing fio_dma_tools") - (rc, stdout_lines, stderr_lines) = AwsFpgaTestBase.run_cmd("python{} {} {}".format(python_version, AwsFpgaTestBase.get_fio_tool_install_script(), AwsFpgaTestBase.get_fio_tool_install_path()), echo=True) + (rc, stdout_lines, stderr_lines) = AwsFpgaTestBase.run_cmd("python {} {}".format(AwsFpgaTestBase.get_fio_tool_install_script(), AwsFpgaTestBase.get_fio_tool_install_path()), echo=True) assert rc == 0 assert os.path.exists("{}".format(AwsFpgaTestBase.get_fio_tool_run_script())) diff --git a/shared/lib/check_src_headers.py b/shared/lib/check_src_headers.py index d3c229ed..7249bb36 100755 --- a/shared/lib/check_src_headers.py +++ b/shared/lib/check_src_headers.py @@ -560,9 +560,9 @@ def check_headers(dir): "SDAccel/examples/aws/helloworld_ocl_runtime/helloworld", "SDAccel/examples/aws/helloworld_ocl_runtime/sdaccel.ini", "SDAccel/examples/aws/helloworld_ocl_runtime/vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin", - "SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/helloworld", - "SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/sdaccel.ini", - "SDAccel/examples/aws/helloworld_ocl_runtime/2018.3/vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin" + "SDAccel/examples/aws/helloworld_ocl_runtime/2018.3_2019.1/helloworld", + "SDAccel/examples/aws/helloworld_ocl_runtime/2018.3_2019.1/sdaccel.ini", + "SDAccel/examples/aws/helloworld_ocl_runtime/2018.3_2019.1/vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin" ]) file_provider.set_exclude_paths([ diff --git a/shared/tests/bin/install_python_venv.sh b/shared/tests/bin/install_python_venv.sh new file mode 100755 index 00000000..98f83473 --- /dev/null +++ b/shared/tests/bin/install_python_venv.sh @@ -0,0 +1,89 @@ +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + +# Script must be sourced from a bash shell or it will not work +# When being sourced $0 will be the interactive shell and $BASH_SOURCE_ will contain the script being sourced +# When being run $0 and $_ will be the same. + +os_uname=`uname -r` + +script=${BASH_SOURCE[0]} +full_script=$(readlink -f $script) +script_name=$(basename $full_script) +script_dir=$(dirname $full_script) + +python_versions=(3.6 2.7) + +# First install python if it is not installed. +for python_version in ${python_versions[@]}; do + if [[ $os_uname =~ (amzn2) ]]; then + python_version = ${python_version:0:1} + fi + + python=python$python_version + pip=pip$python_version + yum_python_package=${python/./} + if [ ! -e /usr/bin/$python ]; then + if ! sudo yum -y install $yum_python_package; then + echo "Error: Install of $yum_python_package failed" + exit 1 + fi + fi +done + +# Python2 pip is common between OS's. We can use that to install other +if [ ! -e /usr/bin/pip2 ]; then + if ! sudo yum -y install python2-pip; then + echo "Error: Install of $yum_python_package failed" + exit 1 + fi +fi + +# Install virtualenv +if [ ! -e /usr/bin/virtualenv ]; then + if ! sudo pip install virtualenv; then + echo "Error: Install of virtualenv failed" + exit 1 + fi +fi + +# Install virtualenvwrapper +if [ ! -e /usr/bin/virtualenvwrapper.sh ]; then + if ! sudo pip install virtualenvwrapper; then + echo "Error: Install of virtualenvwrapper failed" + exit 1 + fi +fi + +source virtualenvwrapper.sh + +# Create virtualenv environments +for python_version in ${python_versions[@]}; do + + if [[ $os_uname =~ (amzn2) ]] + then + site_packages=/usr/lib64/python$python_version/site-packages/ + + python=python${python_version:0:1} + + mkvirtualenv -r $script_dir/requirements.txt -p $(which $python) --system-site-packages python${python_version:0:1} + + # Adding the python bindings site packages to path + add2virtualenv $site_packages + else + python=python$python_version + mkvirtualenv -r $script_dir/requirements.txt -p $(which $python) python${python_version:0:1} + fi +done \ No newline at end of file diff --git a/shared/tests/bin/requirements.txt b/shared/tests/bin/requirements.txt new file mode 100644 index 00000000..354f359a --- /dev/null +++ b/shared/tests/bin/requirements.txt @@ -0,0 +1,6 @@ +pytest +pytest-timeout +pytest-rerunfailures +boto3 +markdown +GitPython \ No newline at end of file diff --git a/shared/tests/bin/setup_test_env.sh b/shared/tests/bin/setup_test_env.sh index 2668c68f..bca0a793 100644 --- a/shared/tests/bin/setup_test_env.sh +++ b/shared/tests/bin/setup_test_env.sh @@ -27,48 +27,20 @@ full_script=$(readlink -f $script) script_name=$(basename $full_script) script_dir=$(dirname $full_script) -python_versions=(2.7 3.6) +instance_id=`curl http://169.254.169.254/latest/meta-data/instance-id` +instance_type=`curl http://169.254.169.254/latest/meta-data/instance-type` -python_packages=(\ -pytest \ -pytest-timeout \ -GitPython \ -boto3 \ -markdown \ -) - -for python_version in ${python_versions[@]}; do - python=python$python_version - pip=pip$python_version - yum_python_package=${python/./} - yum_pip_package=$yum_python_package-pip - if [ ! -e /usr/bin/$python ]; then - if ! sudo yum -y install $yum_python_package; then - echo "error: Install of $yum_python_package failed" - return 1 - fi - fi - if [ ! -e /usr/bin/$pip ]; then - if ! sudo yum -y install $yum_pip_package; then - echo "error: Install of $yum_pip_package failed" - return 1 - fi - fi - - for p in ${python_packages[@]}; do - if ! $pip show $p > /dev/null; then - echo "Installing $p" - if ! $pip install --user $p; then - echo "error: Install of $python $p failed" - return 1 - fi - fi - done -done +echo "Test Running on INSTANCE ID: $instance_id INSTANCE TYPE: $instance_type" if [ ":$WORKSPACE" == ":" ]; then export WORKSPACE=$(git rev-parse --show-toplevel) fi +export WORKON_HOME=$WORKSPACE/.virtualenvs + +$script_dir/install_python_venv.sh + +# Setup default environment to work on +source $WORKSPACE/.virtualenvs/python2/bin/activate export PYTHONPATH=$WORKSPACE/shared/lib:$PYTHONPATH diff --git a/shared/tests/bin/setup_test_env_al2.sh b/shared/tests/bin/setup_test_env_al2.sh deleted file mode 100644 index 1004e667..00000000 --- a/shared/tests/bin/setup_test_env_al2.sh +++ /dev/null @@ -1,77 +0,0 @@ -# Amazon FPGA Hardware Development Kit -# -# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Amazon Software License (the "License"). You may not use -# this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/asl/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or -# implied. See the License for the specific language governing permissions and -# limitations under the License. - -# Script must be sourced from a bash shell or it will not work -# When being sourced $0 will be the interactive shell and $BASH_SOURCE_ will contain the script being sourced -# When being run $0 and $_ will be the same. - -script=${BASH_SOURCE[0]} -if [ $script == $0 ]; then - echo "ERROR: You must source this script" - exit 2 -fi - -full_script=$(readlink -f $script) -script_name=$(basename $full_script) -script_dir=$(dirname $full_script) - -python_versions=(2 3) - -python_packages=(\ -pytest \ -pytest-timeout \ -GitPython \ -boto3 \ -awscli \ -markdown \ -) - -for python_version in ${python_versions[@]}; do - python=python$python_version - pip=pip$python_version - yum_python_package=${python/./} - yum_pip_package=$yum_python_package-pip - if [ ! -e /usr/bin/$python ]; then - if ! sudo yum -y install $yum_python_package; then - echo "error: Install of $yum_python_package failed" - set +x - return 1 - fi - fi - if [ ! -e /usr/bin/$pip ]; then - if ! sudo yum -y install $yum_pip_package; then - echo "error: Install of $yum_pip_package failed" - return 1 - fi - fi - - for p in ${python_packages[@]}; do - if ! $pip show $p > /dev/null; then - echo "Installing $p" - if ! $pip install --user $p; then - echo "error: Install of $python $p failed" - return 1 - fi - fi - done -done - -if [ ":$WORKSPACE" == ":" ]; then - export WORKSPACE=$(git rev-parse --show-toplevel) -fi - -export PYTHONPATH=$WORKSPACE/shared/lib:$PYTHONPATH - -export AWS_DEFAULT_REGION=us-east-1 diff --git a/shared/tests/bin/setup_test_runtime_sdaccel_env.sh b/shared/tests/bin/setup_test_runtime_sdaccel_env.sh index b16239f9..36774b59 100644 --- a/shared/tests/bin/setup_test_runtime_sdaccel_env.sh +++ b/shared/tests/bin/setup_test_runtime_sdaccel_env.sh @@ -27,6 +27,8 @@ full_script=$(readlink -f $script) script_name=$(basename $full_script) script_dir=$(dirname $full_script) +export LD_LIBRARY_PATH=$XILINX_SDX/lnx64/tools/opencv/:$LD_LIBRARY_PATH + if ! source $script_dir/setup_test_env.sh; then return 1 fi diff --git a/shared/tests/bin/setup_test_sdk_env.sh b/shared/tests/bin/setup_test_sdk_env.sh index 828f8f31..03f6eced 100644 --- a/shared/tests/bin/setup_test_sdk_env.sh +++ b/shared/tests/bin/setup_test_sdk_env.sh @@ -26,11 +26,21 @@ fi full_script=$(readlink -f $script) script_name=$(basename $full_script) script_dir=$(dirname $full_script) +setup_test_env_script_dir=$script_dir if ! source $script_dir/setup_test_env.sh; then - return 1 + return 1 fi if ! source $WORKSPACE/sdk_setup.sh; then - return 1 + return 1 fi + +if [ x$1 == "xpy_bindings" ] ; then + source $WORKSPACE/.virtualenvs/python3/bin/activate + aws s3 cp s3://aws-fpga-jenkins-testing/python_bindings_dependencies/setup.sh . + chmod 755 ./setup.sh + ./setup.sh + export PYTHONPATH=$PYTHONPATH:$SDK_DIR/apps + source $WORKSPACE/.virtualenvs/python2/bin/activate +fi \ No newline at end of file diff --git a/shared/tests/bin/setup_test_sdk_env_al2.sh b/shared/tests/bin/setup_test_sdk_env_al2.sh deleted file mode 100644 index eb64b4ad..00000000 --- a/shared/tests/bin/setup_test_sdk_env_al2.sh +++ /dev/null @@ -1,43 +0,0 @@ -# Amazon FPGA Hardware Development Kit -# -# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Amazon Software License (the "License"). You may not use -# this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/asl/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or -# implied. See the License for the specific language governing permissions and -# limitations under the License. - -# Script must be sourced from a bash shell or it will not work -# When being sourced $0 will be the interactive shell and $BASH_SOURCE_ will contain the script being sourced -# When being run $0 and $_ will be the same. - -script=${BASH_SOURCE[0]} -if [ $script == $0 ]; then - echo "ERROR: You must source this script" - exit 2 -fi - -full_script=$(readlink -f $script) -script_name=$(basename $full_script) -script_dir=$(dirname $full_script) - -if ! source $script_dir/setup_test_env_al2.sh; then - return 1 -fi - -if ! source $WORKSPACE/sdk_setup.sh; then - return 1 -fi - -if [ x$1 == "xpy_bindings" ] ; then - aws s3 cp s3://aws-fpga-jenkins-testing/python_bindings_dependencies/setup.sh . - chmod 755 ./setup.sh - ./setup.sh - export PYTHONPATH=$PYTHONPATH:$SDK_DIR/apps -fi diff --git a/shared/tests/bin/setup_test_xrtpatch.sh b/shared/tests/bin/setup_test_xrtpatch.sh index 07fd9e80..63eb1380 100644 --- a/shared/tests/bin/setup_test_xrtpatch.sh +++ b/shared/tests/bin/setup_test_xrtpatch.sh @@ -75,7 +75,7 @@ elif [[ "$VIVADO_TOOL_VERSION" =~ .*2018\.3.* ]]; then echo "Xilinx Vivado version is 2018.3" s3_ami_version=1.6.0 - xrt_release_version=XRT_2018_3_RC3_Patch2 + xrt_release_version=XRT_2018_3_RC5 xrt_rpm_name=xrt_201830.2.1.0_7.6.1810-xrt.rpm aws_xrt_rpm_name=xrt_201830.2.1.0_7.6.1810-aws.rpm diff --git a/supported_vivado_versions.txt b/supported_vivado_versions.txt index fa85458c..5b4d35c2 100644 --- a/supported_vivado_versions.txt +++ b/supported_vivado_versions.txt @@ -6,3 +6,5 @@ Vivado v2018.2.op (64-bit) Vivado v2018.2 (64-bit) Vivado v2018.3.op (64-bit) Vivado v2018.3 (64-bit) +Vivado v2019.1.op (64-bit) +Vivado v2019.1 (64-bit) From 32833e3e75b6db665bed2b8ce150b93ec88dd120 Mon Sep 17 00:00:00 2001 From: Jim Madge Date: Thu, 10 Oct 2019 16:32:25 +0100 Subject: [PATCH 05/31] Remove duplicate line (#468) --- SDAccel/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDAccel/README.md b/SDAccel/README.md index e89c4fb4..9c714df1 100644 --- a/SDAccel/README.md +++ b/SDAccel/README.md @@ -198,7 +198,7 @@ For help with AFI creation issues, see [create-fpga-image error codes](../hdk/do * Depending on the host code, the \*.awsxclbin may need to named \.hw.\.awsxclbin .For Example: ```vector_addition.hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin``` * Copy any data files required for execution to the new instance * [Clone the github repository to the new F1 instance and install runtime drivers](#gitsetenv) - * Clone the github repository to the new F1 instance and install runtime drivers + ``` $ git clone https://github.com/aws/aws-fpga.git $AWS_FPGA_REPO_DIR $ cd $AWS_FPGA_REPO_DIR From ba941a17dd4007d00ed8e8a18362c457d194d125 Mon Sep 17 00:00:00 2001 From: Jim Madge Date: Thu, 10 Oct 2019 16:34:54 +0100 Subject: [PATCH 06/31] Correct path for helloworld example (#466) In xilinx_2019.1 @ 0ec1aef (and not previous versions) the hello world example is located in $SDACCEL_DIR/examples/xilinx/getting_started/hello_world/helloworld_ocl/ rather than $SDACCEL_DIR/examples/xilinx/getting_started/host/helloworld_ocl/ --- SDAccel/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SDAccel/README.md b/SDAccel/README.md index 9c714df1..a6fd741a 100644 --- a/SDAccel/README.md +++ b/SDAccel/README.md @@ -89,7 +89,7 @@ For CPU-based (SW) emulation, both the host code and the FPGA binary code are co The instructions below describe how to run the SDAccel SW Emulation flow using the Makefile provided with a simple "hello world" example ``` - $ cd $SDACCEL_DIR/examples/xilinx/getting_started/host/helloworld_ocl/ + $ cd $SDACCEL_DIR/examples/xilinx/getting_started/hello_world/helloworld_ocl/ $ make clean $ make check TARGETS=sw_emu DEVICES=$AWS_PLATFORM all ``` @@ -104,7 +104,7 @@ The SDAccel hardware emulation flow enables the developer to check the correctne The instructions below describe how to run the HW Emulation flow using the Makefile provided with a simple "hello world" example: ``` - $ cd $SDACCEL_DIR/examples/xilinx/getting_started/host/helloworld_ocl/ + $ cd $SDACCEL_DIR/examples/xilinx/getting_started/hello_world/helloworld_ocl/ $ make clean $ make check TARGETS=hw_emu DEVICES=$AWS_PLATFORM all ``` @@ -118,7 +118,7 @@ The SDAccel system build flow enables the developer to build their host applicat The instructions below describe how to build the Xilinx FPGA Binary and host application using the Makefile provided with a simple "hello world" example: ``` - $ cd $SDACCEL_DIR/examples/xilinx/getting_started/host/helloworld_ocl/ + $ cd $SDACCEL_DIR/examples/xilinx/getting_started/hello_world/helloworld_ocl/ $ make clean $ make TARGETS=hw DEVICES=$AWS_PLATFORM all ``` From 7318b852f7dc8fe7174ab34a71d5dedf7e5814e9 Mon Sep 17 00:00:00 2001 From: Kenso Trabing Date: Mon, 14 Oct 2019 11:08:36 -0400 Subject: [PATCH 07/31] Update path (#470) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update path Attempting to change directories into this path (i.e., `/home/centos/src/project_data/aws-fpga/SDAccel/examples/xilinx_2017.4/getting_started/host/helloworld_ocl`) draws an error because the `xilinx_2017.4` directory is empty, now, and `xilinx` is a symbolic link that points to the latest release (i.e., `/home/centos/src/project_data/aws-fpga/SDAccel/examples/xilinx_2019.1`). Additionally: `helloworld_ocl` is no longer a sub-directory of `host`; it's now a sub-directory of `hello_world`: so this part of the path should be updated as well. * Fix unset flags The alphanumeric part of these flags (i.e., `f`) are preceded by en dashes, when they should be hyphens; as using the former instead of the later results in errors (`-bash: unset: ``–f': not a valid identifier`). * Update path to workspace directory This change is consistent with 48c3048, and the basename of the image, but has a different filename extension because of the transparency. --- SDAccel/docs/README_GUI.md | 8 ++++---- SDAccel/docs/figure/gui_fig_1.png | Bin 0 -> 127297 bytes 2 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 SDAccel/docs/figure/gui_fig_1.png diff --git a/SDAccel/docs/README_GUI.md b/SDAccel/docs/README_GUI.md index 4ca59dcd..af09b223 100644 --- a/SDAccel/docs/README_GUI.md +++ b/SDAccel/docs/README_GUI.md @@ -29,7 +29,7 @@ The SDAccel examples from the github are downloaded by the above steps. However, First change directory to **helloworld_ocl** example. ``` - $ cd /SDAccel/examples/xilinx_2017.4/getting_started/host/helloworld_ocl + $ cd /SDAccel/examples/xilinx/getting_started/hello_world/helloworld_ocl ``` The github examples use common header files and those needs to be copied in the local project source folder to make it easier to use. Type the command **make local-files** to copy all necessary files in the local directory. @@ -46,9 +46,9 @@ To debug using gdb inside from SDX gui few additional commands are needed to exe ``` $ mv /usr/local/Modules/init init.bak - $ unset –f switchml - $ unset –f _moduleraw - $ unset –f module + $ unset -f switchml + $ unset -f _moduleraw + $ unset -f module $ sdx ``` diff --git a/SDAccel/docs/figure/gui_fig_1.png b/SDAccel/docs/figure/gui_fig_1.png new file mode 100644 index 0000000000000000000000000000000000000000..b98b468a16c78b57913de1d30ac746dc937f2de3 GIT binary patch literal 127297 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

$d2$ouw- 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 Fe*o2|dJO;o literal 0 HcmV?d00001 From a29ca360953b67541eef927fe8ae786e7c339ddb Mon Sep 17 00:00:00 2001 From: Kenso Trabing Date: Mon, 14 Oct 2019 18:27:11 -0400 Subject: [PATCH 08/31] Update figures 1, 2, and 3 for SDx 2019.1 (#471) * Update gui_fig_2.png and gui_fig_3.png to SDx 2019.1 SDx's welcome screen has stratified the option (read: clickable button) to `Create SDx Project` into two new ones: `Create Platform Project` and `Create Library Project`. These changes are rendered in Figure 2, while Figure 3 captures cosmetic differences to the user interface. * Add Figure 2 * Add Figure 3 --- SDAccel/docs/README_GUI.md | 6 +++--- SDAccel/docs/figure/gui_fig_2.png | Bin 0 -> 190593 bytes SDAccel/docs/figure/gui_fig_3.png | Bin 0 -> 231008 bytes 3 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 SDAccel/docs/figure/gui_fig_2.png create mode 100644 SDAccel/docs/figure/gui_fig_3.png diff --git a/SDAccel/docs/README_GUI.md b/SDAccel/docs/README_GUI.md index af09b223..9c84be84 100644 --- a/SDAccel/docs/README_GUI.md +++ b/SDAccel/docs/README_GUI.md @@ -62,7 +62,7 @@ We will now cover the following steps: Add workspace inside the current directory named "GUI_test" as shown below. A new directory **GUI_test** will be created and used to store all logfiles of our runs. -![](./figure/gui_fig_1.JPG) +![](./figure/gui_fig_1.png)
@@ -71,7 +71,7 @@ You will get a Welcome screen. You need to set Platform path by selecting **Add
-![](./figure/gui_fig_2.JPG) +![](./figure/gui_fig_2.png) @@ -79,7 +79,7 @@ Click on the **plus** sign as shown below. -![](./figure/gui_fig_3.JPG) +![](./figure/gui_fig_3.png) diff --git a/SDAccel/docs/figure/gui_fig_2.png b/SDAccel/docs/figure/gui_fig_2.png new file mode 100644 index 0000000000000000000000000000000000000000..884371fbe41459b4782cc699e782f06ab794adcc GIT binary patch literal 190593 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
aCZQWPh!TjlA@Eu=pekCoqKtskk@Dlmp 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 literal 0 HcmV?d00001 diff --git a/SDAccel/docs/figure/gui_fig_3.png b/SDAccel/docs/figure/gui_fig_3.png new file mode 100644 index 0000000000000000000000000000000000000000..83d61d208f1c8dede9d01ee9297533897229799d GIT binary patch literal 231008 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

Q$Skm~` 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 )(6P_Ti-7vex* z3pBe_rl8WS`4C9Z?lkd#gBersE3#>IJ(}D-JS-3h*>hc0)ecmWZ;=2Nl-r>a3`|U5 z6??b4Ymb82L+G~Z238g~PMC<4`}s4yQ@lk&?9?bE_!>xSlGW8!u<07>KJeM=ME zRb}!cENI9O;hc#Vo!hMQEWQ=k3RT2j59Y@}EQix>xGxhvZ!wysDzC^h8P)Eoa*=w3Nwut0g59c72vEPRg3J@q>WVS-yS*d*imU!t>Ww%J_9uP1=3tMeYSCy_BxG<4YPU zkqJJh?KbA&cM9}=n1%@+3RAunRQIF2GFTDu_7b=81NJE9I!r%cn`1N<)xUmVx^f^e zqL=;ku4RsJ;#&a|Hm0i~QP1xLzrOcOvi6N%%dcG5xZCV>Gw8YYi9;K#De)Uown{xQ zG0&d~b)JQ3P0_yRo3FinMY@eoLo09}qdg&-af9!+-A|jRlDm(#nhseScYC*=J}YmK ze%_oAx;|F3$D>srEf@C|9pl{ZzMymP=)s1I_C!n2myhM*7!4!2YQ^|G{>Ay}epa%2Ge_ z(l*?G^zWZiy`$Um=R3Jz6ke0EJbf2(V;AA<+2^dz$timscSVoGpl)+HC^9lKiO)OO z&f$G8*=Q|>4L05qK|3Uv?;0;2_UW11uTWio+t42??k&dy4*ayNYT{-Y&Tpl=>@$3x zZ%+bXKJ$yI&(TNN^d{Az^qc9N#gFl{GHX&$b*Df|@3@2n(s#G1X=q@6t)!&nLt)`_ zL~@#brvzA?cY#icq6Gu}ZVXCIP>jvW$#Gcw$q+^tEg zE+%hl6U#T4`B@pEBxVfb_lf*MU;L!?@5rF$TSoMKRD1!ywBNpT4#JD7VaE=Bc-82u zt_)H?;@zV+8HACUarZmhf_dpau)gR$U-2x6qp|EOKZ$R+Q|_Iu0EVti%XJHD8!9@w z$VG)8I;P&bJnN%Hi!bCwyN}wqB3>Hz#Ssz`D%4a*1^>Bws$deBd_u(RyXsg%x8Bs;VQ|ju8ZL-&T>Gm5 z+@sas8*Znep55;v#v_Og4?akZ{TVMd>JC;^8+{_-PFkSG+?l%Q!umNYKpC(cX(cXi zZW3uOlV>Qfea(;V*7)+ZE5cdTh@ore8}aF_`#HH)sd=m41aS^zT3f0FDM))mX(3*M zNBsqMjskZdA)bu%bYIA#-rYu3HlRfZ5Fi-q{5tan3xSF3&}-HM^%$q;8HfkB<7jl{ zWMr!2d%!UP5eC@6{G;xcjINtX(*eF}*S%p|o5@wkxlg#~PI-gwc75?`K{FSmzMSK5 zDuB5dNEl$KJ%@2n-cYhYm3>19nIG}HY4ph`LjI(yE3Au%5xQHX&c6l=6^rft9GX8TzVl0u=?cl4w73jIFWI)ZI zmzQU6q&>edJ3Rax@C`sk#C`}l$pg4l=$$~_0tI#4-`@p}=fLP_pwjr{P2|1#+tg+_9ZRi^|)+uKU<%!b~Azf6X1;fu~fR5rbv0mR^~N$buvP zB=iJ>2(!3H$4?~M86(45H0CZw0gFZN=yad0qNVUrVQ~+i>qec{h~J3FS94av=;>j4 zw%aR%@tR6HTAMTh8VrX_XdCEaD#A&|L!2D=WGjsM$Fa?Sb`!aZ-5qy*hYj zhjDrKqR8u71`=5dhhG-X3!1*v*T8;8e!$~jO>m;lD^x04yvq2qEJfJR^Z&H~o!+!2 zEq*Qnj&EH1Ydz_;)|n^#^hSe+di*9VgWg1Xmzd{o$Ja=45Mp5-y_&Df{r=rK^z6^1 zYo%9k`;wO@8O21T!z2~GbVQ!8cCZ17Oj}aMygK7S7^S2a<}`oH&C~YbQRRkGp4&Mp zbzaMCk$PemOISWhDYz-AsUPl8wPkw>zi4^I87a+g^LbIIXVM}#D)#VW0zueU!AYV` zR28hrT+@4_4G;ul|L75doDS*?{!>Z~(}>wXBwim&-uPU1t0pZj@L-o^sHv-)ry@`( zb!+S5ix%inLM~3U!H@%RMey#0hab6Vy7k>V-y|&#_bHD2fQ~^Zm(MS{Z=P_BBH(#M z#04Z_HF$5SKo$_ptd|p3ID;MgIB*5aIZ4nILAebbOmRy~K+>mg@ZhG>D=uNxLDNJb z5u6hnivd2gENpCTKfIEtN5MBi;_AC*`y!A|2#p7PF!!Xt<>PoOj|$Og>o{BtYMNGl zRl?`Vdes3TLrt#p5wm;cH8n}Vb$l2aLITvYfPnSb;OAL01X)cc9>TmzK>5K}@vwyn&sl|5?v~1Z!qAeXz3qkf{+S2ai5B<6ToH z1J5tmTGiMJWludLolRZ!-F?xrKX@~U86YcUt}aduJvjTw$MAT{3L7^X7Kzrgbh`vO zk$UnEk4bT8#lq>x5|8?Cg0ea~T=^bM4XdfjKODzbpWfV{zCmBP{s|BMU%JSrJa@$^ zV!2skHADC5BX!g8rk>&B7Xveulhwp^@=J7J(|2IGw6)K@g#9dw`xGe(A0~B%HaGc^ z!cr1AE{JTN#^R=NnhK`9$Q-ZIef+NJF%M-d--eNfrzQFN$SfCXG>;i`xf1T8G|hc8 zC)YKPu75a}ht$DO6B78DpDfYjlT|!&hES5T(#zfNJHVJePTp9L(-Cwv8b8t>RXQ5r zCL&>>o$qv{uKoFKXm0n9{_>;R&r58;y@89rf{F^Jj!H#k<@wdhO$bcc!q_~bhdvfG z0=4+jkv9;+(m)7tcVF^RLkJ8&GxYE<*M?o~dE9hn7fr&W)_VHw2_kqW28X($sVU1N zWY4swk?>_p3j$*GSqV8c&sscp*mzKMj*Xy_1Fz3_oLyZvp&eu<#H@cb!v^UE!w?+P z;<<*50MHP5nGYTiz%p`jva+(e1t#;so=InLa?1eR>oQv-&pHSjwVRupQPv>9MQ53o z=b6=1JHP~90}+&nz>OGHvs%ul5gYW$30)+DZXTX4Og`I#30qj4Fbx_H{#GCYPzP^e zOP~^4k0(UIEC9&oBZRkpU!M$M`B3Y^{+^zjI}(A4)dJrVBc>masw=ahG6+e4i5%~n ztJ6l8SuO;7h45*H41p9KK0!eRAD;&ZF#jmM$PUm0L}~TDHY5>xA6)|jfMM@}KQ_2+ z0mfM2oR*)j2BzmkMFP3(Z{;#W)*MCHQhx+-NQU;&djy0~C(~z)T-S3%=@98eloO^; z>uBEkZ@>SBy2OY42OaHi0Ba8&X{;q{kMl<&V)SxP${YhT3qRi}JyJ#vF$Q`P$ENlf zPktHayl}55kf1&(b}bGf$-(7$gUz(g+B0#nK}#|6*U<6?Swm&;({FUgJ+hC(6E>qC z9*^0PVU3K&RhgNo_!|mwzNKWrc=3=lBa@3koHJqQPs>(O-^X;h*&yQRyj(`OCL_6TnzkC<@o)8+;@90f&BW% z@^hPSi?jsf%t@MR-ZfpR;JOyc!Xz$!H>#krfb3plm4iTSS6j^Cp|VYu9F1{9S^j$$ z11K%?#U8i2I6P4#e(Xs8s@mmKv$e$?A|g(!^9GeH1AS1bDmxnDKngp)j!Cw_x2-Kk z4$HQjqXwHYy^gjg)av7IhM#T|MD*VB|23x}Z_Im3Q|xa7<$FGXw>Y25Ez78IfB>vH zGcYwpOkW|w!(i?bamS$=o@FG5=~S?^R|4DxD$<%fL8{5$8i*k~KS2aJ(`%K2XqXPy z<)JTC zR+(;lV}Sd#A)3cI7usg9E(AOXYCjPX5lDCdtrn2t5a0s6g@Z;J>^FfsCX!U`ULgZJ zFGNv1K3)s&=#Ajz&xj?L>rL2}tKd*o?AzIY@@5fOBt&Jg>R4v+1_jo)38fR^AZ=!M|N^4zfp{$TLdOhv;_ zP*&D9At90A_l2>^`y74t?8Rxb*3X~wyFU%IMl0l+av^_sqY#^0RCIYs(d1FRw$c3? z9pza+EQx6GC-=bGQGw&+M13j}_l?E-gc$0!Y*F{cvE5x^b8)CBaaxey;Uf3*poLu+)5f@76skkq;kt=O~b%N=ZwX&8Y|x8v69UJmjeDCT$gr&Lu{H~Oisc_0u9u^1pmY6>c4 zh_i*x0wFD(vrUF#X{|E~c)mjb~b@V@l)wqGx@IE-Z=)eIb5K}7+1wW^RNWhI&iX?O^* zw1ERWPoYR*!bR6IGgC7*CIy}&FVmW`5@6uBrpGevnxCTM_*`S%`#v)3K}cULfihv) z244$%++LgRf9;6>T@YyK&&pnJeluch4 zqf28)twma}l=s9|Ne%Fn$2g;)MXfHf_2gLNKh_f}PY8&OvCh$`r^i#FyPH0LcQ?OJ zDVIb>c&d4TAN!(4fSGyDH*$HeQgP|TW3h(c$W9ztt*R`to!q-K|Nco)=ThKtZj?`6Asr**0JqpR z?Kl6MdqhO{TSi5LH`OhkT+ystPNZjVvalZ=d&AK9#f89ik#Noq>mJ9_1nh!6r+Ru_bBthD@zqq5@&&pB5vR2!56k})a&@yT1^k}Q+ zX=(6ZkL%dU%XM3r$WD6iQhhLo>HnMo0`J6X4<3H}DSoH-Ic@$6*7Ac9f3Y7vP1oc% z|C-;JwtIi|xw?9GIk|G7`h%QnY|m3)<{|0q3I4Iqbm0DHoTDnu&@ZHSl$VNb(swM@ zXADmpFWw6U{P}z*VD%fN9(Q#Ez0nc@>LB;k4`OFmXPA1QR5mfp4k;-PbabU1n=CZE ziT70DgMshh(+kOU$*yBUO3G!Aa|tjM;2~LcoD9udT5^S*9zojjgSg3&vDMn{qdPUXu0ED_k9}VVGPFYb9V7-u zAV^7EW$Z@Yauq%4STb%DR zl3S5wi{mYo*1wOIs`d+UQhv8b&ag5oF1TfpWV+`Rh?A<-0CD%IB@SzEA)*Cf+w#6R zXkO8|a9VnFhm%e1M^p?-Uw?)ci}el%yW+a+JaU!yfOUop3xTQ;2}@e$x***qTWnPZ zy~ScZiWlvqyOiV0NW9uETukg!|2}7fSNUjOhkxgiJz}DK8b6$B zg={-;GZVG}Uj(+}U#28^)-CSgPSn*vtk>hm_vc@HpUBUT9mO?#l25=L{_2H|Xdwor zhn29f*aX}+@PZV0qR~F2TIYVCVo>v{TF zeAU=FlKAqo898)0U2@LA%f>BF&&O86mowinXxbCOKXl8V|5jg*0WFlesp%bh`qH0G0i9HQ z52okaoW;pqzG~@oqzqJFOi$xY2=GsRS(5Px>u%g?Q|qu>A15O~efQ2{bASH$%h$p@ zA6HDwBO^0yna7Va59ADE1IG&?FxOi@hr0povx-)C$0riO@o~r^#O&wn0`yiq^@&oC+tSvtt?d zxm_1Y*~m+8Wh+TEcbbeLx_zssKDQ)e0Ke(Xl?7=;j&v%pKuRPPZC3RaUZ2`Wg~nz# znD#q~FW6rULyxjsUbs)=Mk+y}VLe1?iV=P3H}-skND&<^M)4ftJ9ADZxIjjP8Aa=0 zL+p@0*&(F*F~B4|_0w-17N$x%D6q0(V_BQrs_J(r!}$)+fv+^cSJALOt?B&vH{#4K z_C&hl=$zW)ma}8<5HUS|L&(N@fGF5T1+S+kr@hEZ8u}$W!V>-6dOR2GxvCj6E?UUua5tfAQEI{C1*7HvWjH1QA=?Bs-_4aY*q@gI+1H}s5Qd_bT0<%^xf@23~S zUJY3l+Xjx8*p+A99rL{Dy+XEK#4@czvN`TCQjRZ(QeWADofHJ|c^s|*tM~Va4f_E` zl}&&ca`JbdWX`$fAc>3V?D_T^9{P<9^zwCBA)>2t4d})8yDsCZwH+G%9@NzaoRIMx z&Y3qm{cV1nKvUwGJ8KqTv|r1CJ}`AFtpJ3DK)q4;d=O zcHmjo8`j@bjd+*glU>=<;P6B9|Bzu*_6S=8V*4n$Pcbi1pEX7kV}uvnh)v7Mj#br1 zHWZA~G7QSG>hkiXYS={~)dai7PqI`dnwnke`Us7>ab)L=KM^02FsxaS-|*FsYpS$ekn#)Q{@w@R7;i zHCfnsdrwhPPV@g}44iLz8@;|xr-+VcXnc;f?GpX)iFRYMAwSW^pWz@A6D~d;p3N== zbQJpHRtF9uTPx2TFhlbxu0mzq%Eu{`5`9@q3>zxHkmcr<;Rzovud?=Me`_lD|@hIS6I{m|cPH`G8-a{C56K>*%Z|iafc#RzY{-N#eQCr#B{dp~K%gXpn z7D!>7PqUJ*1|7%M6TvDPCQm?>0g4et;Wx)40%YUkVL`Ua%UIgZ*e zX~;T{8~?XT#?9PmkwkuuJkG_Uo}aCnL(^UR_>Dy31*eWrDvFBD;y4++#~Zf?KuxwFD)P|W zRC96gUc0lk%)9s?9KnK)RJl@KFb+H)ZsdmZU(?S3&3~!s#bpOYnk=o3PFm}eA-}jd zqFa6^XI)n@&h2yOf??FRE39$vRU&?2qSY*Pazz3UvdOhKwS`U#tq>iB2JPzU#$gUD zp&++IF+%K=dgh_i!gc&s75-Ht;*c!?bC#(#S|R`Lq8WGd`-BFEpx1 z8}mCh$!Vo5CsgwJc)l6&6drKQj0w6R4x-Y}4Bn%1p6H51SsKrzag9`pv3qfu`bTKS zGdNPUiC9O!lUCxAkiglZT}hfR{Y8r;DTO1$syv^GhJmVBm{v+;y;vDrl?44ZQo;Z;Sh1`z$tHxRr-D;YB`urX?bget)XWgVffqPf*3y^ zTTk9asl$%nu?UX6UPF4FeZ?hX#6p;*l`|p*(Xk<*=?{KZ*cFO8+OW7uWP4GuRL1y9saNu1Z?lxD2IpT#-K>^^5!82Yf|^?DK) z`?itMyKr-ENu-`a_@`mZ%gg&ijsfCSQ&T#DM;AA0_V%Q=>{Xk<7JPaCd%_=niL<8{ zXGhc_g};J-DPI0@tkrr_Q3$9---o-^tQ=!7_fzm@%r`n(arfuXjh4J77eHw7)lEG$qYQWN@|sX zG*$twqSf>qsxR@ChDy{Kc%$h`q^zYPHvVn%XT%%RIdt^Mu@VyLrV|)tZFOiY)HXKC zOziW+K+08xx3qlVKz%%o)t>r$Ovgb3wg17du4|ndj4j4`}V+tUE;>S!TkX9 z=(qty=G@0KiPnnya@bYi;qx^3nmbQ|K zH7`+h+N0HTGF75W3!<@l9ddA$WAsE!T0LQq;!k@yY{ zB|WofdKm+Ev~zpHvtAk)1%r9xq^x*zHFXVw#*$g*{DNKVoj$oB6Sfzm-<5VIZawvs z#6thg6bRp~qOm>s`}dFP0;4M~Uy9nnfdAfm$BBBc{zm|1*5@os{r>nlokG$pcWo^- z&+mem=sqs`83_di9a-b<{tpN5N4dkp7|5aBZ ztibPx?j`S&O>St+cT2C6$wA)wIMtU(clL{W!qp2;NLTnUkN_NBOJ2WDV2mGK_SQv5 zVdQYUynVXVS&)@wK$d5+`{QSkzK_L^*Gcikv3vM!N(JJIQ7@bQ!*7m%t=Nt)JkseK zzO5#Si533k3lDXG6LU;*$MD=o78F_f@F?p!Vv({A{s>v~zkaVG1Cqz{zWVG?n*P4H zO4>7~iHyzQy&bXt#ubQ1%T>+mO%GD)yxa6Y<9fv(Obz|}0LtdUVco}s;H!gisZOR^Ez^Dj9+KA2B1q|gPQ6clVhgeKMsOSXXqHs z6TQhUnj{}W9h5L(p8kkY`M(Cs7uUYy#Sey&KZh?!P}bcjiP`tR-uiw)^{k%k;@DmxW5}iE|{o7cSFUZ zzn6)>3XHSg`gT;C7ty(_90eA+ABLFEex4St&n(x{*W+qfG+Qrd>?%@+NctblJ=%GU zMK8_Kl$>?Yk!)#{Vz_j`8;UMYg~Oi3ZGEut=yg`cGrqdgf`bj#$XFd@;1iDQx4?ZA z(NL4*H0DxFm<4|tI#XCZ3{q0YXq|11ayCcNU-e|r%gXCG974aS*%kfQsF01nU(M1ra1$Q;e=Pu(zRg$OINz7} z!{P%UKlCMgdl&0p$|r>qhf#!eTj4*$>Y-Bmft#?XSsK|;DuQ3O7|FP_iBiVG&0SH_ z5n0lQ>d`oZJPj1|R->;mDqz#Vh;IA%yPWQA8JwNuXXqd(f#vz*cjo)~S5NuXR8)!T zUBBDFrJAI2>lG;Q0vLNdPe`kUhPqpFRixB0scL!d6Av~_1?CCX0C+Qco|rSESy~oNyA>-j;O0Is0H!lv?iX#SX(|G84&%`9 zw?MFiDYe_zC{9*JH)7FOlKxMRiF1KU)6q(Cv6Mr!XNlX(0oNsvMzE|U#^YG-;`qJU2Xvp^E)z`g$i!IYTa(@&s2!%(&gLvzidlTvofIc z2X)M0kXU3ttIxJU*bPl$A}2-IG5>Tbdh0`D4oizFW?-P;*?T-!Pd?%%5>Psc^Co8? z?WC=|X5)VmAv0!oRwR?bXVY~`_`F#pzftM?hU5qtX||t#wCK-@>qWMv9dGd@^Oq)n zR~n#?etlc=8QV9{PjV`Xt`BbWN@0ke8ng7{)q7O*xhW(N%fQ^#NA8bn^vU9K;}rrY zH49hUV7$6xd2{e&e>v>=*Cs#5;QiOaLd@}qXkbF3P1+33FGHxsa-WT{QnCZ}C_bOS z@pCy}bkm)XaF-xfp}>|AZ^X(=9<}?ADs^ccOA*w>GU4ymYe=G`L^e2Ue%N;Sf!Xd6U_;FEvaT~v zl=J=C(1;=Gt6NoTgrWZ~t1r(juf;9@b#~K`C3;UTF9x2WoN6~(!&Lft&9Wje)aklL zIuXaseiD#@bDr#RL+rT6%_Ar%%|iHvKn_u7{c89n*1l%N;Ai`YCCYr-IE#+VN6zCQ z@azAU>nJVnDL(aGC*P4yim=qt2B^(~@t_6US_nI1L@D6eQynyx#bJ)9GF9|KUFD9K zX+41}2?t+@TBF|43umOEGaf`oj%+%_(|Ow7&tMQ`F96YFxTp7#nrj`toDIO?b+zhytrO$ze=m2S^4S_kzmlNdDj#%RX~HP3E4b1) zIiGKXYEF3k^G4--*eVNTLM62uKjnk-)?xaC0O6)R0ruIBowQ30POnw?-91Cy&W^bJ zd=4h2{Xn1n0cR5v?xS_pS}->lE0M=K+byN0A;kQ46u5ubE(n878i2DGG9dbw!0eFZ zhyDe_dn<~vc-{T#4^zp7{FiH_igZC1cFK_){5vFgTQ~Wzen^u4*RRph`13DAH+RCW zD=qCtD;^&g#?+eCXG{kF(7xV14a);g+QrYk#cdSr`n2eVDxO^hBPM;tf%@mpY1bd} zjO_c6h3fu~_h#?r>W$0lp$*ef6-KN4d zeB(B#iO#@tH-BLD7E@)xwr5M<%KiuoZ~Ux9s94g*HhDILgh@+tnKplg*1_SbraLTU zJ4+C{C9nN6eJ(M)ntq=_msp2_%V< zt}eT+Ey2%VKJ2HnE)9XlL2PU)FrU(C=U!D^=!`|QsjY1xGqe68!Flm1ec7|8%R448m7?QqlwhkKL{ zrF~S%m&LC-+FZa%JftkD-*vI=>AJi;h#lO|>r-`r59}M*EGuOB?*{pY#IUx{7j=AF zZ|rk(;w)d@*Q(01T%9>;gu4fGhAkQDr6msJ<2OPRxid2e=C+~nK>?MHkPvmyStvNBsyHaL z6^75Inkt18(WvQ^4WbO3y}|2`8R&s|;phw+H=(*dFISO!ma;574B99`QNy#pwb`*N zq6m0jW)O(e;`K?9(%gNj(>L+d&$~3UDeJR>g7|QXIQ-e2 z8m%46#sZMNt+>ufyKDblEkPF-?X97&D3Q-xq9!bkk(YJVeC$}B@^{oPskg~ z?l>u$VWO9eN~(x_sA76F<6e0E64$dK(9_GGMBa6pK`b3b0Smq&|a z;(Av%YERnR`+38Z{N)k1xQ4q1(GD5ed3M+Z7Yd3j;>4w-+=#6#T>J7}1dfv7(ebsz zAq4Wr_$zjDDvNWEg`52=f&72F7iLC-{Hl}M!gxTf?KwmFL0yvZ)cv-oCq9+Mdw#GO zTQRD{eUhMUh9q~v9sg+SlozQVM((Q~G6jO9&1S8ywPyMC>p>;fhyFFGRaMTX_xuvK zyVF6*f;eLoW*A6L%Z{h9ZHx@ z=MQkBtWzjd)@wwYJ%5S&&n=dhafY%ztN1FIL=l*7tEgF0r-clmWScA9e;GCibO+v$ zOiZjFGuD>`VRT>5CtK%6i#KV^h`FqUCPf50bmu&jP+He`Tt1L_vg8xzwze4{y8iYS zgYz8#(%dBQb*r-}=G`t@? zP*&m7iWdJd)f)aXLkcrz8sl?47D}NHrG`iowhFjQ;-%L;h3@AYPh>cPD2(O zt_RN7bvLWL7W40^zf%xA>5SXb&vZ5Ej{fUn5b?a#cwOd09>YT4JN%K>ou1YiU7nq} z*Q!A^d!}5DjT<#@gV$}TVW`{t#Ec#ithUPyE&Sur%L#c$*Y9Xb^fyX|pt3UlYQNzE zkp(bF=bWNkKuYbm_^|7%vZ2SMlaiCqrvLX;2nigH?Yv^FHQiS*TTObHI7qO#G?3c% zWePUnysY%fz1`hiI&scSfIM|{97?!|I6gv@RN`SQhQ*=}?lg~)wz+^K>C7nGizK;+ zfv+`iUTs(O`c&^Lk;qdKolnVFeU6c_V&I=fAy^vn8>rV!WtDE{6Q)(0u)=-3es^7R zO8I-Z>Xx`bBlb=`r$+?!;O$sxj0bo$EnbwfCI8~vll1$NJ)6JqsAuWvYnhm+g}Nsl z-(&t|q5|iLf{ST8=QrVn!?Uy7)4J37A`mC%g$L!)NdvaDfrAKpb+%3mP4c%cX>jMb z9};>U(#CHl!;tW6hTHPUVExSXG-frrZ7x%s^bT4~%cr?9at{i}<=m~Z=>EfbMdAFu zzNjeIZyiZ>7r`btk_r+2;|bwOJ5iitjw~vs#{oZ|M?q?ICTA| zW`(4nq}82;J5CCwo(S97;_cuqy#zJAR@(Bs{_(h8#bcEkth# z-J^E&_03meSmzRj=D4H}IS%ufSDk>BQMR8xUrc}K_wQF13;FwMS=`ljy%E7Oy|=O$ zfvR8c=`Br2MC77@jHj-Y2ahjaJtN+q;U@qlTo*|g>Y14@~nlvvHj7jgWZ-~(|?h;EWGKT-)7_l zN=REZ7i=3g1TQ*^(ti;prlIJa_EThc44KsoC-NcM<9|*V=ftn#;UPIGaZG2=h=mcO zdvMOoK$V=GFsAnHW_1}R#plMk3wWE&IZw=hP}x6BPEMVc!UY$W)t{8j8>bg9Vx903 zG&SIE4e!-b%cb#bV=gQ#C?5qmxj8d4k_>F{O0#4fX}$O5?c+cHd3qC%;WBmo24lwn zsj|LU{M>Q7T<<|cqn<(^Z)(kNN=d5hiStuBm>ww!I>#sCH0#;iB&_|pFqCS`yc6Q) zuSpG4+m64w`t>rh>q^=%VZPkI>r^%)&dOMFrQ;;1Ghi%lgPop2!(put6(B0K@R}M6 z&~8+Be@65|KDxHU0Vq9tI?iJBHnqIQ6k=lncS>}0P0_7zg)uAUMHV0;e` z9XJ*56{tLy=gEKLBAT==x)PH1?vEZO(Pnyj=2LIK`?Tkmzk;(ot}nul#u~YK`6S%$ zEV4(Xu}OdGY*;s7eL-_u)OZ-ZZ2BFJSJmRh5tetxY1+ID6MOv0D1ZNj2rY`Hv-)^#LwGtl&woW(3< z@~Axi{MpJCXV>2YW@q6QU(_P`!B3xf(h1TBY-ajI(aBgt?MZQ0OfkrM=V?DgC1M(6C67t}|v-d8q0oX5Z zEl>2hd-8C#Qt}+{(bw9FmX_y}VTY5@?jRv`AI@tYwys>t=jNK8A54b57#?O-n`Yn? z7&E*+Iz79_2_5tAx{-xW{yQ~^P5-~lpMp#=G7#PR+du4rxua=^rrqz?PV0`P@+VqE z=YP2@c}-5t?Z?Z_>~a0C63)pD%dSIla5kU; ztu*)bMD5Y)#ZOxJ%wacQaa?;%(1FJTV4h#_{n6mcl@B6juIYXB>2esc<$3(d27B1C zCgRO+0k2f64b2lgs-bHH-Eig6qn+zO2;{RvX72b<3Sxz2bg^#!Os40|Dep8?y&_b#Gb zcTpkXoMt5G{viHT>~ft?L8i5+Pk93>pD78-({}|kD%NcAGkhb+r1Zwh*hs1w^7Uy9 z^Vg;s>6C8hH4V;rIrLIYalU?s59z;UWe|D|flI^LWzL6$4H5jcm8CG7;?MW2{)?oI#Sf^4{=V{ zmuo27*u{Eo=o8L9Kn*&%9^;Qq5PDiqxf(ZXDcO@+I`ks9Py^Tgz?Pk2KG;ER{o&WC z$L;904&A7@*k{Jt=JJpK;_q~xID*2}#AH!8tm{Qn)4iSbXz$tkE0E@{0y28XA7tQ! z>v!xF$%7sx16^2zJQkMHUFO9iR!4Vo8Qk9&E&e+P!Dp#=S}%Sc5M~oL_>HR|=4`2M z=3O5sCg0e;Stq6l__ZyaoyD=4iX$GrvSaHRkOM~pMexR)=r)BaYpg=)<>rg* zSCX^OCwFW|w;yv=qwM z?BD&BVIzYl_aN03Mj5x6Cp)Bod@9yT$z;z;%djIq1!K!eu~U5JZ*R&EY?w=JHyRV3 z0BHQyRM7L(d=Z#T`_n>{{F=8#;I@;li(r)Coqc`%Ah>%hxhOCd4&R1Gm`?$qOC^)Hcfgt3+#5OFPV`SI}aDF7j_G5ZxVW)oL_ z_4D6_`Vp}a2?&fQ7ls!8ER+DE7C`3mu4`n_8#n%mjz1`X*%vTBpIH6GLs_ug5qN|> zKW`ivfh5jai`1NevXDh|_t9ZmB;9icMI}Qef+U*62784y1wJcLwY$T}9G93HR(w@z zHgr^e;nOcCJoAhD@YvicD>YfuGRss3KN{dm;>W%;GM3{d(Ly8U#hb1Akr!)|Q^kRT zB+1B#1t>u@Lv6NP?|VqW`tZR3giBAJaM$C4{{-Iei`JX2c678$zwP7*tscd|K;Dom zm|zP^bK+RvEt>sWA9SGebcXRJta|npxtNQ!0aZ)*^n1tQF*O9ve1EI_IH_mftIMuE z%9A=bS{X``%uIViZnoUV+aLvjw<@h_&AjgFZGN{gWWx)$^I_mo!p7^#ULIH0rC+Kg zB^^0~_ZboVofsd{O%AwIuyC35jQl9i$l#(A5KudK5d;V#C{5H9=zW{~`NYN59sO4T z!+TcR;=$CnMhMcztwPGh!vM8~#dcw@*Gd0;h`${+mS@lrH6kb}BEn4s1jLxR^#*{r zu4^O+VB)^GZKR@n)vADbglX(`$J^5(V1YI(%dRON~iqG|1Tr!j8{Q8bHWX%(K>l*xF>;b6_7-v7u0 zwn_)DZg62wBD> zgZBJ_&8cY=WpC{8635^E5k>YDW{iSHfiTXz{S>iu#vbl~DA9{5$deh$A6PLPU%ofq zf{Cr-erAYrE$t5TOd`@wDH{Ed=wfV?qv_~~!>oB_dGbw6Ea`{F=}rC*bsZPWx8o)p z!&prT#2r?)YCHqhSV(DOW(}#s>f2~(V=0k#KY6e)teMg+nXuDScxW-QNtvE<>|5RW z9U;^)ns;KJ^<|+vD@fOW=KM-~rrdor-fo{1?MDdJMSXjpgz=FZ|zn)syS!-DvdGng0@^az4_w7Q;(JAJnmJtxpn{@{h3&liXt|!C=6-V|e+EnIh zdW7haOb`7^l7^^n7;pY);;h%T-y%nz5$66@y`U#YPOV(}G)~KtxfS6GrLonagP$-n z=CmoZ#seN8-4De0;+Xj9iz_S==>CYj&^KV<}TX6L~dq4#|J{9`jN23jJ`;S)9PBJCQ}Q(s3GX4nDt+mH;sy2yz{ zJ3{G{_3i(sAMCUtV!&0)M3`&0N9}*qF4-Yc9aWIK0d~g|%;NNkrXF2SlUE*NeJ6GP zLLn;8Lz3(Du-0Q)!(8@3KfSG4^Wh@^WrvkCZGSGw_;?;!MnN;bZJ6oP|Cbybar1?> zhjcY1hj!=YB+9OBE!O}vvetC`Tdi=A8ayAm zetiXY9auyhW4@0fDx~E)-xW?SypWiBU`A1J(6M3WhM&!DM8siKXVnX_1}wIv7G)Wm z7St*EiuLzRm?(T?6h@#JGE2R`BP(!L=({DJ=R^QZfr9%DxYR6dc)@ z-*r$pZBkNl3(>S<*-8^Po#Lb(A>u7luwQ2QR%XFeJ}z zLOz;zoa7N%uD@7l-X+UwoiyK_T?~i^nH^<=V=kwYAU2 z*^N&or8Q;*j~c@+{QK6>!JuxNPMe0Ltg|sbPx2q>t&VRP5ssw%k^OiO>wLbY+r8!= z7I43PIjMvN9Fq7%elV82hH;U@t=el#d;(w8qZeBVfkT0ZTaw;qyBK8|fAoYm!v0?i z@aJSB@o+(eK%%Hz7rAI9c?H3k@$#;1+$^1jrRwzm!dX51Q~LUc{NTBf zi==3B(RSw5+l+DL(h{C$cV`Ce${6s`qYnScVkh63H(wmjQxsM5X+IkkHPjMhzUv=h z`*rro`BwIP=My21?khnY@jtj=E>ZI8m6O6wbiXzDrnKB#Ul`X}At5{`!NO`stP9*M znTvwcVBoDVU>yTyGChSUZaA;bpR8O^fo~2>SBf}%dPEPCZ!ohAUVv=wEo*4-vNw41 z4|(|c2f9Ko<{BMw%+1Zg3?elpMGD5*z&U8idz2HV$kKAodKbygh9s|3VFnG%TfSAD zcH+(*fWR`Yaq^iV>so^8*e+j`uzD%n&Glg0-{;(`eo z48OU9zjy0Z6VCD16Y;alr&uNm$msH)hva2&(a|t&N66`AYOWj$Ffj#t*@&x8b4qtM zE(KP{{~&A}p9-?>Vzvsie6MgTmx1m!!JJdCbeG0-YFv(pLgfN>$@rO8|Nf@36X7U2 zTbeatbW|eCAZ>!%EkA}~opKcgmNYiyff4!A+wY~MD+NdGb8uf;57E1RjQ@f=@Q=P| zJ^-m@IhOD~F;Dj+Dky=~s-jR~&rG5apZNY$;=@o#ewFQW&Ibl=l#poc>RMb}A5~T+ zhk4}vJZ%|+i`dYByTs0&wzL!mI0IXa*s%hiKEOKK@%%euSgag1f1Iu>_rwW6uL=XE zV5Bcfn;ZqZ-Z#R7uXE(hWO|MIhRN?8pDg~e(sc!&SonSV2h+qc3*r3<>#dPTU_yYs z;?U`~_PlGP6p zfzNNNyZ0&ynnjg09fY<~kp$ZlJ07+&Fo6qD6bww!QWOq27^fKZ4qU;u#t)&N$!S#c@1^mX8z1$%>t1@SOda-`y@lj)XWba_g<|E_&!e_+o*aygaFM73*zTS|~ezU!W*e@k*@8>g&TR zNxwTMBqR;SZs?>f!vf{mrY!oLqchE~k^jnZMKtE{{L-v3^ez^$9?#mbw&`NPHy;8s zE_?!f*pdlqDm0@wH21@95us znkaXB&?J(PPc5$gHC;xPT`>Ax`TFmIlsY;xw^5aD{i`Fb+Q^wHV~|+0dSf2_C39Yf zk^Mozo?s0FfV zC6XCz4@L`@6Y``e!qWy$MJI<_i^8MUS6-)^Z9%{uE%wq*Lj`i%a|&+g*Do>H5uq@ zHvQ_VDEYG`wCAzH*(z>dr4utBee=C9?$+a|`7!AJs=ckmGsL23I{o>Fci&_}Lrm&L zikHXL$mxZJPo3xw{5*3lJLhrv69&hazrA|y9$_7`tmHa@S`>t|+b1X&VGtOyF;K<) zpq)FtoooiulT_T=UkewyZifs5z5tWRhhD1S!_+lmDZ{*`yGO3?dvV5PPe4oU>=kNC2K{)&)yMvsoh9?3!42 zzExB%ek4u3>sei`U?J@N-~khczb4{k@g$}KRS)rbIr%YztiudB@5=m(Ldty$^~II3 z(mzeX=G0=n0lRwC6d55BA1sW>Q=#=b}0{7GWju`os~oou`gp zRy#!g>@lkW^)btS#Zr0W$7!9F<`w~F`&!51zw*B2uTkEiAozjK;;d}bM^ef=p7&5H zp4m^ydWl1$qvU?t4=zfR?zO}Z!d{n@Za?9WdKnyE*L!^bQj^pgO?9S&zqR~>~d zk4h*lx=}wjms{Zb6?#T7c1y%L$^Bk&u)~s5QF$R6P?Ynaz%wy5rn#SWZ2nz{*e%Og zrnfF_d+RwAEG$U)#zX|;6i#`^K5cpYC;H#i^u-&)o0{1ngN&$z@cbp6Qhr547G z5K_zQRUsqZ{X_LkQc~2DIi$+R>$=Ws%IxQwXe)dBC5-1w>@L!njUK9^1=E%c6aB3k z6?xCSlNCIB_N*Chy-ZHOD6P)fXZ+mx3YGCCjc1^uhpII1`jHFZ2mar_gTom6K1jTWzm=0sfCqIs#0!klm#2= ze4x4P=P4)|O)W-dOo-n>$D^~QZn0J`?@rQ^O0IT);j30bX%Tw&`YskZH6&zB7UqO& zf}nCAgy9MIuLE?#1*5m+n8^efOraaK#izU!CK<{QYK0i)^|NdDnLj9&Cobt6p!(6A zWLvLH2ksJC1dHAJNc6dAKJ@;d*i0)IbqcigmM`uJ*jdG}x{!>T;WNv}h$Q~U2i0+y&Dd5V{*VjH|?b}A&X zZzXx;84&2QRK>XJ6|*rLbBWUX_p(VKW9rUhqHVRGTRy}VdmM_aebi~y7hAj{79LKE zBHMhB@|K0g0Jh>cJ+~Q2UFUJ-tX13Hoe~Uw{`;V{RyzF2{?lOd&btpPpS&&C$06C4 zZpgFKduet2p+{-<`Up(VUEyUrZnqjUSvz2w+i zN2&G+`9&L;vuIt=w&m31o6By{i9O8n`P13BEf<@4xwk6&c{VU}h3J1X-tjW3k-|*P zvz|j^J0(jlleA|-Q-hV@i(5>deiWqpbYs87hvffznBuQ{;H_D6s-`Ei;EStzrPIbg zb0{d(E**MAe&e}kxjeKNyP0I7Ee}1v5P!v>GLO$slPpzk=Q&;!O>g{9XHO2kxFHwG3P>JzO7-=4~xA7}C6 zmCdE*do1ipt(?X#JFBQhM^YZS5>OrYRJ}@euR+`#h23>&>O#w18YiEJxjx_h`y9zeLp-G{&5cOtr$f0E$0JutvbX zw97@SzHD?(<>WnhK@l<}&`AeOnBG1PME=K*AAE1Z-X;50_4UAU1^_zwo*fN>PoN(4 zD@ErbXmaM}E?k7V6~v*IphjH|l`BZ{7&1TId^5MJj zi%)g(9e*@7O2aM^2qNAJ(r!5ud80KmXBWcis;grmJ%wU&+k-7CiJ|y4++4(Opq_GOvLF;78Mq?#QXArM z#BrV(By_kk>mYmM8*hVjE=Y?-- z3xh4Z(la@kkQ0T>KBR;3TL_-0<2yqW7Ei4M67eB+NmyB}s<_`9#Q zwF3!}R&oE?cwN77gG~Aoe6vE1U%ZxSQX8;mUck^Gvn{P{HlB}~xq%e^0T3Olt*wRU z1pUF?VDN#;6rO881nF$&sS0Z6wYe6EB$ZAs%n-IeP_M~=UW|eQVU~60?&zxkkD1dR zhQG%M*~@pyig>E>K@0=1BlD8Z({zWo=x9qS44+zE>xc`TpXmHfn9jn^i_o!v@bSuI zaZD(?YKGg2V@l!tb^OrK(4csSy&a*~0u&HR57C4RfS8!yAy0?VUurNpfS}kMdCr&s z*&2^>{$l*Y!O7TuuD){rx6$2hqC}N(v!{5sVVCWrN9Ttp>5Ta4D~D#n`=^^%nUvgQ z_G^AD2swM~f{gm@jvRT#>Mpn4;bH&M-8(g0dsA-I@E43-tYDL(ca|WIdAvs8Vtcp)3 zE63Yrnwec9?s0*Jm5R+*&KJ>KUKwl3HK*upO1#&WZqL}#o%U+S%l-Mv_3L3_PtPLN z`<0?q*Yi+l@spXX5!X+b^WmmeyD3ezH7cXtD$%JFuSjl7*R6>X5Q-O>Ok3AB{dz6q zI=?@ELNhmc=l5)c_lStl_=G%#3pNqo#;^6#?EsYEEJ}NYN6YM8MdFLo*zS-P{gmZM zqcC2VeN_FG(5@dBh>_*S-zr+SciT_f1-~04)6kfC_kk-hJ26P--oZ52B?B*mH!F8A z5o_gH3U}VZ54xFAkZUWe4xO{jV*f>1T{a-CzOd(%#G4NvB4iYFj|^9H&*cA!FY2_g z)Zjk4z0W9-^-J_<+R2()<+mS>MX&elJt#bze(Rhh^&f3tS?1>E=CJ-QWZGb`2@1;I zxX~`SEiXI!C1Du)?PO|0M@PW-0si^}JGR+Y9V8`fLTvrcQ>+ACeHhuj{7%SO4o^_f=F$8PeD=!uJpnv+|A0A+`WH!_As)o};L92M<&Q+R{T`j02H5rj8j6C-hI1o7QCr#nDcMRm zY~8pK3BkEHP*cOAgH)_f`?#dFD=bA7*Hw2b~<&pP<6A6bOkqJWz-E?816H14@3oF%Mzutsy(;g-Q`Gdg-y_9W44~aw+Aeu&}U_$ps2uS#Bryd-w9qW1-}U zq?MJG^=VkxSHg7Q!i7ILD4~Z)*lw_r>%(0OGVh4L7a*Mn!O_{d;jTGc4?7P}(8-jX zZTBHWb?f$RmbZp-1s0w*IBwTNvcuO#ll0U{CpD42DF3K{%>K*Xe#dPBv{5YgXx zBF0xa%rfc4W(xf9V6oI$`6_eBN6GOD`nH_mt7S6;aV>9|?fUiKw6sTIR&qe&iJp^` zZ3Y8gdj34;`_x8nn#Gv;RsY9&fYHAt> zV(RNlAIc{sN64$$O1?fB-+o3_fUn1}XVp1A;cc&tn8dzo!Sm-UF?JjfX}`3#73wg3A)HJP6F|@70zg_Cr*c#k0L2FbW`aWy|5DcNgSjC>sAcTsiIe!TZHzu;JHfl+4fsj7d>zZ#xOGkcjV z8XLY~Qfs(0yJF(PyI=5uZM{%olS1c>B?HQW2)5e2GhhF5Y)q#Hsa;ysxvU$Z>oB#U`o3hczE4=?@ylov<+5CZ@VD-OuxikNi^IY~h>w}@B#8+ij*#hF?HNQUINN?}cYvU=LB~L9{=9G|-Sp5lwCHx>* z!Kb7f+g{{Jnj{?|d>jg^lqOhh!I4KrO^xibV$sIhd+^9fYg-L`yxgj*N2~RI}h-M@8A^r-+ zEv4$J5)}})g=}9Rw0cF1jg1Fy3Pey&{E%m?u*xRvor>l@TH8XJ76z+q6FGec8Qd53 z2}yY%S%k|VVYvi{VjNL-i)M}j@x=_$5aAmJ;XnfWf@`^N{$x=kA*fIII$;iUCUs*u z6-nqD^CNz7VSLUwe+Wf#2+wa3U;OjXEaE(pJ*oAnAmplJU4@a8Zj<-=2M3|0$%Y$w zw@z+9Tv;LY2?Gg4v%evdyP>3CS$Uqp>CaZ;KNE!ux|k@bKp5-m>l>8q1MQJBQrNP$ zdt;C^K?U5yh9 zVu)yA^%8fc$A&nx|Gi;cd#vg%Qf&0GUczFH!^Wpndj2`qp<@)Xmu)fTM(lnBE=jm$p>e|}l^ap2v zAwGpRk4J1?UIbEtGS@m}4^FtoML2?fjah4pft`RE_cRnxQ5h_KVV5k0_c$sxR~VJ| zX%;UZhN2$j#%ldW4R!IN9FDdd*;WJcQp;qheh8NYWFDh(HsQyPn;oeseUyuF=naLSz+YpnT2%2p(1+*ii7g+tj%JJVh221 zR^~E!rbkWn#7EKE>~UECS2o%txv@4g6(h0S8Y+(e2=q$`vat)fFI%hX{cG*%QIovW z$DZIO$;*o&twVIDI}a~7^U@ei7Riit-u+uJ(B;&$5i#HP=g*;s4`n)*)9baO8<=0$ z(|o0QNc-Tdnb?E(Ckzx%a0*^IptA4GQ9n<^7Y|u$k1exqi`)?zYyFd?FoAMgr2Y+k zk&(EsCxisEXe_fR&7^x}{!pmdU8VlU$>(Pj>hz1(*NRNWQDrUcUGvZEnYGCcuYRL! zmEr_dZZ;w#z3*ZfhC;!mx3ol9Ji52G_>V!8RE8Ykb~a}8~sGG><-hMcF~ zT8_2ZKil!L=~-4_kSed($P<<#?=6R`OTO+YqBtkHQM|FOE=?gEB%{Lfj-11BMbfRm zy1aR4w#0UqSFO(}gph~Yh(=dRJm2w<>5)7dDQvzIH-Gqg{8L^uw=nA&)!VpdA95o8 z3nNL-Tp){3q{6$(dy@4gjfa$@I2r{1EtReQ{lR`gMWr%9mSX!pwsQUJzs2?}ZvS-G zaq4@bd+mOn!dr{?RJ|L9X6%>mEPN;kjf=i?#Eo5yog7oT-jIn3uJ`D9KXs8!ntY!M zf6x9y=ikJ>^`4LEh#f zx4&drpUeKlin)nm*Y^j7K8z@c)_cZ{Q69;EWWErfeB4`XH)J`GS;a!?6SaKk;~Q|X zL8b%LjwkR=R9M(el+lC*27!emlk_@-kYSMB?mXXSTH7ZtFAt^~D;iy{eRSP72fjUr zRn9T5KP-$(d+;W3vWvO<`ZUzkQSd)(86AL`oheo>TlK>8R9A1LR%pQzio}Q_+hB!e zJ6X7p;W&OBfP+o0HuV*aS7Hu+h4&Vw5f#3$=0AV-{5cUWg{`{+YE57s1v%D=(ucd3 z))$KF3B^)n<%)5~OoIx{z4J^K%p5%3VI!lxgkCk;Uq1p`;LnXr5mMY~_zXfl8QJDZ z%@iX81B@4YM8QuNi78PzqYCJ7XwiXUhc66qknQ1Bm`U}55o9m|B1DXHk^efcPF0}> zcmw@;@BOzuicb8G3qVcC#6p=Frgrcmgi)OG#ZAP6h-sKCAjW5~dvk^pB1N31(VoRBx_=!?trXd40>xvV%?8(D=SL5W}TD@Fe&c0OwO-E?+6F5&orA5SfoOFPBcwBq-BZ!7ReQHxTPkH!ocw5iWgS+8! zCK9azd2&ck!y`bY{UdMF-k+!gV5E5*2Bpv>M=tOCeE_92VGfMG3nXJrh{zB7;Vrn# z%?Iti<}z3p4HHg&>iBWTGc9@^5=7tT_3JH6JK(}4v_klGSy$eg8LVA}^YZDKQ~vjh zTpI-4Ud8IfUyP!P4D!Bsf#!y6D#1h|00jxph37kcs)Y>Ga_s!lp6`jL4A@IUk)=hZ z9dhmX;4^rkPzokRXtq#f%f%iend7*8OpYs@Z0^x6+S{K_*6E()8~3n_Fdh8j6|}sZ z5GEEGFue0yzDP!D3isgk%f7h*Da(Po;t~^sx?V|^Q_waQi(L=>%Pmtr5!PT7R&C=Y z<8xc&t{`_=n(RKx<6Ww%ekUj<69$FL?_N76lV8%RqxwxylA)(H{dZD?g86lQ?Ldn@ zGL6R8<|9ol-aR+0R@D_<*SA=XM}PV(|GaOC;oIe}G?U}BQW{OaNj+_3jWG@-;}b~h ze@MOlQJWnTP0T+5$)3cPCdQ$YM<;zxnL1hSN9hoorg-h=*9!_ICjOIp!&dCM=6jbf zsx{Rql!+c)?hWCgDf$EYmADeldFef92M|3hNd7_;9$hgA+G9WfT_iP)pR9RA&rL&9 zN6yYJLqTLhX4#nk6U~QaveI|&)zww|-)Fvr9LHjSR(;iNI4+1`RUUqoAJ*rBi1}}u^AbStk$N24QcHPN=mFOEDxbWkMk4bi8q@Pl(}wX z)v&U-NixDB0^tMsnv%5iHX)(q`2sjCW1Io1_DvygayqTBuWE%86B1xmSpxrf;D5*& zw-9p5R#x18aj4;G=;&DJ55l@yUSFRH>3|6>k|zWxsP5OI;sWG{oe&%v`Y<^eNkIC| z(rtKu+=H6vGc8v1d~3E>5B^~EbQC&*G02A>@J;MP*GKhZDlW_CM@YTiC}FG8LgRjDU@dmCL} z)a}&Jz$C+4q@<{jG3A3hjVzCYl9{F;$71ZqkP9q2V5&ht!LWjH_JAef*ZTS)G-dEW z!ba@#J5|sHLQUHAN+CHSPb*MOXy9C!%u(b3~J;ji~g za$7aC8&*dAdc^bJ&MPfjp`E1L_B%c!UY2uL?)x^S&mUxu#h-Jkv%7B^a(7qek>j*) zFCDtfa*HB1j;4C>PKdgCLP+y4>ubrpEAeMT{eo?jg?z>8&Xp_J4)O}UxVR&ed`JnbC+SNFn+bl(*c{?lwX-Y{^#u~J+;8tu1o zr6w_CTU{L;PqKTUMAaDSj|{JK9aYCk0-_H+7I?gcEc5=cI+3BVg^}(Ub68YO)_&<;bz7xp13XqjuCF&S3gxT3U$nPLO z58W}`Mp!1sLZ#l*bK4fIHGl}s%~ucv?{#IoanA>w4*v@+_Cefi97fQ3!lDNB!;?Z1 zSxY4E#1@;K4f_&yXj^2h@cZshIFSFZGyWaHn@Dg8^?&#a-Gu4Gpu?N^gl8ch>q8!a z?}HM|fkHtIJmI*mC&Y7Xk~@R2zeHA-(}pWtrwy0=&e)1e7} z;RLbePn__D;6Gq~!cZ%_+x-l%5`Z_bxZ}L6uD;h>8hamw2Lb0p&)=?NG9oz{$944S zawh`=W?aYp6v0yk?*b8jF)vC{1} z$qWt&;qP-FnR0rUl+*(&=>s6`0A7oT&rC3HS|v60yTEE7X^OpP>Q)CIfT@)=+j_0p z{P15=LP8D^B-kF z9=Uo<&48jjmuBx})S#;G6U|;9@v?nJAEe>?O~iCNtw2}+V~HQfx!Z$<0?NWlWg=oF z8XC1%u9;`fvj>tF`=zgG$8iXU_6HuXcth!AL9e{6`9yMF#SUKLfHQ^{FPmm5Vq|m6&9P z`;(~Y4Lcn#V0i!6O-St2>x!f)(-rM-OQFXWYhr%q?$G%%8}B&8A$?59*C0h%_RypE zxy^BIGL_=grZG>4TN-TT?}C2@tKL7?F|Z5 z*kVZGic#!q6}!82NE?0PrdIrVx}8S0-8qX!HkI~CDWPKzzd53hTCU3y_pIT%X7nxSe@SIj5r_dQ*ZLs)?bwVe&X<~h0h}M`Dm^KoD@tXXC8*7 zzj`Vrdg{l|`k}Bp9G73qJ&}mJW!!g3pX2e|bX?3ub?GCgE{7@1J!U#Hcj2qRg|QRH z7OS%DO8d;RtR4kZeK~PUh_<|Fzy8xVrjbq+s$UaGlxIi3UwfNQHvBH_nk@UjLoCl< znMc1h*C4wsMP`{Fdo<>9Y@}CB+X!Ro{lK}j7njfE^Di)Ad5EL>=xt-^PgO@=@Y}jKG*VFnop>1Nx87Bs88|cJ3b{SYtxQZxDqEh zY!FtLVm62~+4hUMp&^Tdg9920X;z(Le*XSoLRFe%_RK8dWpIglmAMKS0l^YLEl_w= z3LrWN1bWADBp7?al?oo+tE;X}o-$2>aQg&iuMHPm>RIPk)%ULKc>tCm?7DAQ7d{7~ z9vU26iWPAY4#fy=pFRl+sKq8H+kX3f@yWYy!nfoxu6gq}wQThgOi%DRN_H@S2tn@> zCk9p}tb}(re58!K%86`d50ld9BcxzjEww#1Hs}N*+o?i#fbi1=8F0w;C8B<4$*fBu z^%XvOjc@y@xiMS%9E>Vm_a$SLN!CS6gM!}^`f-yt+3l~hzhLPN{*97d5*u%9?lt-V94Jy+nfTzZ>@ZM_2w z!~i1=7B&h#dGKH>N=z+qMdYM6NFTBtkEr}mJtT6w`1{BYiv!6-=1wfv$)g4J;;-NQ zB2~+veRzKt(_ulTI$p&viFnc16l#8g6E|!tgH3;t@{S%SGh=oS<1ko#T3df0Wzx0x z=S*0n{=8V)iB8LBGzi?2M6aSc3^DE}lPUmt9G?U{B!@pP{EBjx4rOcB3= z_qU^zKf2q7j)YAQ%uP^*>b)ct7Y~dhrbl> z-2ZZ)z5V53x+(kDu`hoTJP*5w9riZ-WwJLz?n`+c2|N@Lz$-?^$|Cfm<1Ja#74zYv z#>~9c8GhOpLrev6>)(KxnUH_tIJf)XuN&4=t26aPZ@K9k*2Qi#eNa82U`9V4d0%oe zy7;|&($Q(a*&2NLvYwuGNVb|s-+s&NAo2$IQeqwuO$j0?r1<;<4##lk!xD^-@7JMd zNJkk=^p|^UPj|<|^YGWNt9YDBF&HQ}g74zru`#Rwg65u_oN)MI({KT+td4;}TrMx( z#q?J>P6FR$z*e@o+HAhs;6}pE1dSj9J4GT5x*Vvea%z<5x})ku8jd6aURr{CFPwOr zWS8AOJ~VgTQG}i-^u!lB>|tdZ0Kx)@MM^;?Cyv8e)GPv&SzfoNmcn#Mz_Iv|@?a1J z&24mu`g{dg6!gF^heaFFCqY`f4r-p=zdxlp3t_b;XnHhW>AW2Q(=b2hdQ4CP6|F+E zh+`j8UzDN{`@Lvol`>qr`il1CKJaRV+nYK&pF9h})(`9d~d|xIpYLz`V91^vHLP99UcIzhDwpIB; zXP5Mz9gc#LJ+xfs{5j*^RQZQ*{BVmnZk88*UuDOwJxzmW*_kXNtc30xT>7((GWLce zhs%K<4VMmY$+uEICd$Hh<3pa{bxr+iZWm;X-_v?!9%$IuqknpgtpC|9v5{}Lo7JnR!Hlb^{Ls9HhKbb^xG3iUkB*$Jl4bjn{&_lv~ zMSC8m9p?B}@o`4!6upuTOER-ywdI@8eOFk{SC;u-nY%|m^zsx>+`%Sl-ng~1dk)0X zxLuGfc_;IUbacqfBqn;qKV9+jJLRvQVmSzA8t{Xy$leP;WpnYcvR-!IQd zCre#OQ^za~zPt~0IB@jg>gwmdcaNw)Nm1$#O{sthTE<8+<9lGnwzXcFYW(+Se?%el zOmhMK^nEpLa0`YzgbQ3?RbYvOXN^+NrdFth$QJJwuju6E=hM>BVPK5t!69VV%-Gx6 zT`O`Gg_X`KeB~q%H;rvk`}17Cz3Adk499c37PT$}9x31U%!WzOn?pPUb}3OmrlNqVGs-f&?;u$bR(9w_6Vp{X(G5@LeWsx4JOF&?F`+-l-$81 znG--)2>)j2W>TWbAk?C5xI8CDe-PVb@vpoT)US7M{3G2s3xhXI@S}Fd@I)yn-7R_x7c3uhe>DR#*0U|B zs+?dZ0lv1p=MCAbqQ!9`DSY4HJE?!oH*cI_xtcCa zt>ngiR`I8WPe8tWdSgF_v*dg8vMcRs2H(^ZzEKFT6-7MZ-EP|KajWrIU;JObZ@Qmo z!t(-VxCfZs7Hf8RDrw#S+B#VmMlzfpQ2dH=>IF?6-BQiO(v?nQdh-uAT))iANxV?A zTn#V!Xj}izS@pC1C()wf;k9b!*i!}f;`4R5xaxWZB2)fkpBXX#OW(`#{`-k~Ra09n zVf%~@ZFL=zvx*_11$Ryh%klOfXt?9z6;tH&>^2p3hKv5z3E3)V_63X!Nbe~H534@! z3}GS)`UB*ElrZX$s1n`#`*!L88faYBg>zKcpkgsA9YZ*Npn@5V5;ycuKrc8{>?qg> ze3fWbd3o)?LWWN#xC=FpYnF)>4Hjr>!Sue3#h?u{_lY}VOQBLr6lk8|oN&_AogXTL zBYGv+r*#`E9veYmo&kTw(f8-O-a3ErO6Mfn=tHHu8KJ}tpakoz=MkM1R%UNV(k;M> zdTS$^&LC_7YGv(S{*}EYTI5sv`0AhCQa91mx4kt0!W6Obzoxn5u8e(O@0XrH~Z|b5?IJG-X8F(GK zqN!;Q40L8JvmP2O_uI!|CKwGIX0RsQkURxj6U9A|e!X&=*8++PyF2BkYZ*p+fieq@ zJ`E4AMgc@P{FeLk6n({4c=zE$e^bo5AR>e7+X{K(c`j&x~7pL}HiWpsTK_fyrM>$Kfq$cZM%R zXo_eTE_Dn^RssFF_Q{M)Z{>GO-MvoKP!EBDLnyPx`FEq3jW&H&IYCA*?EOA@Fzu80ZlCd0y2n68l=2^CG6Cbj zVvt<^5p-Es*D6FCZAk+FdGLuP!s7MYz%vNyUxq~+f9N%CZtnAHl)@IRXVujyl9NN8 zJ(EQt7?A+FG>~txR2?}ei%AnQA{b?6qTI*iMMTT@sYL)rIA>PT7?7L}4hmau5-5d( zDAI213-j(%@TEmt1isPAJJXwnji!2GG&=hf9&-2;{Fsn~e-b5{H@)b~?21fw#p<&S$BH>VrT_*OupCNJ6xB;PMB1$C?8x_L!Y2#|7vMEy z)bPPX(%b(vm<4?ZwM&=I{>Ou-n;EJNY9Wqlpl~x$c&g}2S^VOm8gkinl9Tg-k`fwA2G=7`V~Kzb zBkJMLrAg&jgc>Ymfl?*wzD{l*7bv&+H7~k5hg6Ql=)DBl%JD#g{G#@oLZe9-!+l%CaU?& zNL?dJ!B~yWm;1~cigUjubltNvU&$OO3|NwJUC120c2|x`E6I1`cyMG`*fA!io&w!c zHQBu?xA&veK{-8`9pQE9T7C(gsyvsP#PQfeO zqKvELn}uT8+p3?pHK%=s+z*}wNP{O~0;{#j_rkwFwp(o8ElIN+X9v;uRQ)qU+1vvy z?IVlhbz*tDDp9$ycpVd}R#0&v2NnCz?Yms23R(w`=O&4aZ8#)RbXY9}WM8iOy<@W; z_5QwHdHdY9k)hU3b83|$S9AT4-=5zm1uXyf*m(C}+wo~L)-9GWm724#pCY^K8C`qw zI}Oc@fH;FuO(Hv+(w*N53U-&Z!p;pxUD=lrVk>H~@zx>gNl@az(c8ouy` zQQmE6X+uN9Ey-Hp*QwDo*XqjiJLm%V77ia|KSaZ}+pESpW3NJ3HE(#Eeu#o_esQ#3 zi184aN!hx)vyw1{iOKe@+eG$Kkdsu>vmHu%Vr_IIi|b;>ME>zPHH~7a>*N{1u7_?& zI!Uel^+|r8Ji2)GbN)(a_jWv|iB9RQ;y|S{h{Yr1QT$h!Ve6~%}|9*XMrGN5I z8fIoYrOD@yL?Wj4OAGY1ToNYH$y#2A&f>piWsO_{`|N6Nljd>LBnoW1%4kML zMkXqdwENRz;^(WHNXi+v$)WVT`U&$o51p2y#f`DVzthS|yq4R1gM{FZ8v!FXh*!Iw z9oc${nfT$~`7*t$UMX6NZkLGZx5^{C6sz&-ex-PZhRxqItJ{{^CKNBezPD?jFu8yU z|7gm&^Z$O=Wb-rW8s58~G>*6+{21-yHl$vN6rUg=i9g`rK}ALuED(04n-JJjb`Y8*I7T!Q+E`*_*Xc1%1^feiEmX+3jr7!BhdXrf6+-R*MLcKE3Q zzIo5WN`2m%z0OOblLSLd1Xs9V31rlv>IOyq%kh`m7>t2q=U*d=VA_q1$*)~?DI>PT z2S@R4eq)dOC~|dOr{qwZZvmE4<)DKz0}TU!KfO~T3FiFPT?Lu9y0u#>vMh@kDAi zmsme5_?}+n`nb9+xDq6aMgP2c{(YfPg~s}?Osg2K@8~d2A+IC>AxZGa&WzGemhDFT z;p!P(AWl9x-SyR*TK9sQ+7B(QJS;|cpN0F5_5ThG{9VelHJS7z?rl3I@pz+lJkp1b z-wWfdZU25b=%AjorT4+igs-z@yUCq9&sucvJ;7}z_uaASTCWT`JKBU{3471pyLX1T z9cVqXgjT~Yogn4H1{TQ`chRCjSHVDJOP#z?`1#3pe2VJi6k>PKes`PU^^ z|HlRJReF|5SQF>wh66%@uF~VGJ|-HH46`51w{G3S|DkyVF}eb21%zf>a^(vG3DjU>_GFBXjuKsdFao}R znV+AVO9w#!@C@;9Fnea>;UR?`3+HnKa9+{6X=-cpHIJx?5b{TU2gYxpJ`Dx+p4(<- zuK_(LB(M=E=E@p0%)xdg1abNu1`m@#;Z&jAogka^#|gImTe zgC!`^62lF|@C7IzyqlQ;8pa_wVZmfTQ!*#zdx}oJ)4+4h%^5cItVKmdi5eVo2NXe7 z>@M~m3;Er~AfgZi4x&mVQeSLF?Un&T?*QwVOSd2l9%i8`i5Q|b1htH~;XpZ|7$=RD zzM0+YIuFQhDYWf7U$j1#Dqva%a=p&?<+;(eVh<@irudH^pA=)ZLmxr>znL4*ng1*e z#hAi4m#7DDpK&_D3fmM+=tb8e-#;E$N(Hlx7m0}!Vid-|B22*aARbFXUf%VspB~d! zdGz-gi`4z=rP}pw^%3rKRP}#r*eI~C0pwuT}|5FzXErGxZoR_F9K zgs_RB!1l^z-YT=NtmmZrLOx<5LGiGMxXo5xPzgY$ zN8@F(J@pdD7ouu043Yqev)~*uR#K_efBHhN8A0BB<+1Ke@XHB0BQX&pcw}=3hu|YF z4Xb*5%dD3~CR-<~`mcETeQ_^ne}8&>7!$x>K~C5+BiaX`4nTbOD@Fzsjve|l@KVpDyU4A7Xb5YQ zfaF0eGW?mW@$AJ55akJ#ju;GO5j=Sy>cm3DI_D23L5BgE1ttXfltUpaz)FttA-Z8b zKjk}k4rd(4Kv8^tZz9(RFS>N;(tYr%1Y(v*&>RNOd}c7x+OEf&T19*wq^thMi#%^Z zptlhTsIp&d50zzxEY2R#+u`ZA#;K|6d>q9mf-Dv*;4a9Xd*4pU-PN9@z)CI>C<7dp z2!H^nk-URdz!20o=i*T2_mxj8;eqIn{8sUA@E5I`^nVu=uBEylvfwsjlyAr=`OSee z#`RkC(3@sg$Dkbh*53!e|E?YLtenWN430E6Dql)(xqo7z$|2Em*ImEpyH!^w7_ugP z>c>L!~Dkx)UbYpxFXWB(P2>OE_uZ90kP9`FrqfR46-+)H2 zE9!i>mhL$e{LP;#8$Ad=Wvfp=B;vbk&h{#9hsA46i_J5f zAW8q<87{sumPuf57VTM22tx2pUZ+;MohvIV=-T(9iz;eCn`Mb`bMT}&U-Xp!$n$5< zh@F7V8LqUeNf6D1*n|WVgRZF~%~;kDxdzub>D@bmKtK%QtyagZ?u}WWO(Ym^TIkzX zR8+7RY^01fBA(-pf_w{*PkBthNTvtjg_D!h?A9&j=ZZ&#Yk3n$H8CjoTr+O=^ykWK%+&YTx?nNqBk%{4QY2*J} z3p6}a@Gj3mYZwI+(b-^J`zzn!GWrplj{55_HH;=QF$86zdq+|pwntB=r6S`41t(dL z$ib%v!mB*;#GS)KX&*f>j|fZf)u(Zt^4IGJQbbra6M>mfo*_`7KRoNbJUNTK{;DF6 z8H)e)F6Jfh7p+qu(PLM%7oTmAAw&t%gy~{T#dA)RJhTSO9NP}YNRA*;SAmMH0B-r+ zP6z51ZTs5Y69fNcw9M@15#%3#RoF~N0E2>T17(00L9YEQ#BJ8LDc$+(*)ydb&A2TT z63-3OTV=!jD1ucIQS0ghxwa8eva*_xZSw`K2wQ_U(-U2gUi0sHvFgXL-6T#o^>-FckN<>Wj@TS7bCU?CARXa)F?aL0PXq{uQuFgi z7K@`I2N8x4d63(E`D7;et?})}C1N0bNOD0mrD*vUPA~h`zC?SYpdsvP_#A-_Ie9V@ zj~Lf>$II zDsdx@gw4y5Y2Ho*9ZH}OYz#s62>vr2_VpMOuFEc(JB1rft#gMgyUXR|Lf1VWLSIQ! z$Kf!r5j_9U3#?y__`%&CNgF6!Umitzi@2b`7D{0K1V(^Rkm?}MQm|%laK<11%DCcvA#qk=SKXrT~2)mv|C{0^cMdI-7YlRSf!*k-Wi`o z?u?jc*`D)s?mUEn5~z2v_C2+$7|ix1AxiGrCr3Qhrj z-Hd)ruJs^g-(+QCkPEfU53p7dOOb;SDH2|7(LRVoo1imb+BBrv2s=BjurL~JZm#d! zjy+eL8sPB=_vg-g3>h2lyuZxRIh*&9nLT{7)KF)IHVsh48T3Um07qhcBOEyoqD%+$ zXF=}E)Gyyf%$&kX)|MWK5eDSeS6=+Y;Z3Akz^IULV4b1`p3@h2=HTd$)oNAu5b#8! zmzQ0L;SEDADnxV~Y6Q#l>W6FC+h_v9bj5@iV+~c6RNxOcLR07pXN9TMiWY)XLT4(- zL=478{U3kwN8J|Y~pY@o}J(j>6r zBr%t!;bX|)m7Q!jGfL?B*Y=cy(qCo$VUMU0VL<9gI5 z65nJ_Oy6O$Mr}cJvo@8L6#1_V{JKA>svHy#VB>CjItFO{9M;q>o%GnaN01}&KDP8G z^{aMGa>oPvl-&WbmW06su5iTB}Z{)+~{=krT>PFPU8s|{qijOLP^Iv3-jUNk) zXjP@AShf&dgUTm#MBlPL$*oy#&wnrn@vQrwZKj(4?Ga|?L@#2O{O?Ef_-3~M-}OEI zdLnl7%p<`SeNJCL_Q-#0Mz)TVLFfTWg#97a{i3;gsG_CTnxrI#7S!=E zvTrY+5JDCFRqHHq=0wd|v?mm;>j-(_pL{O#Jy^T71E*@{ed6OqM`<6OL&yAxH2zQq zR!+%e_=vh~>bn|@b2=`Z|Hy*qUK8E>>fRTpyN!!eD?X(86hYzQV@eUilH#6E^hHqj z3Kea>^OsR$K4Cr!@f<8e8p915I+HPz0G%z>VL4KgmaZK+)eBvbJ_`0kT`s;qy?)6p zivPZDV6F6dhh6x4zFhfSDbXvAY)|g8J+ZHvI73m&-)h)2rci$HX=QXy3~l7E2g*V2 z4fsOSu@vP46!A%0%fiBFoT_)#Q~jY`xgGdqCSXm7{fU4+*9Vi!Hqk<&1(=0gnl#$? zR!+A6;k4a^UQ>yHPS~H3!&hWw1Iwp&HcT>lWLPbKVaHoC3BMrEuLLry6Uc9&w5D4Y zJyH0i%M@QMXI>`eo2>f?5J|T1y=shef|xznCM(abw!dUc;grsa<&0_wnOB zO0;y0OSz88i>)Gc^(8LF0JNrk!V-4)_|GtL+{a<-k<<5at3)nI)fJ)F?0RN41%vjE zi-ju_@nS#vnmT+(e&DmGd+srYxbgf6aN`>fnA5B)(i2&=^Q_Zf2=El z9=S?NJoV41#&x2_K~3}bg-Hs%{2qU;c2$cmA`Ri2-#T4L>M`+5>d8^PM*SudK>Jt^ zlJO*ltHM`3%bg~VRxaN2s-C1~E4Fr;Ec~LTXhX9PP@d5)-I_YvgusmdTfjv9x{vt9 z|9<}eU;O|3OO?Hw0rLO0jh&)X!Vz;S>Yn^*yU&40ltV}Je7a){S{-zv6lO$I{Qdp= z_^0l=MvZ$8i;1N84|@)ah#1cNX$>>{&aX|~FVE)wwsU*r4cMpe!v+nWS=`6??T!|wA5tIq2=(v)l=DK81T<1yV`o+UR) zV3ON2Zc#_gtcVzI8P6ZP?D|qCSpdjr;IP})+4z;d@|4kDk-9HyQ$5ulRXzZ2vMlMV zAXdd6Uh`%4j+g|WL}>NRc42@8tYT*zjuE%osHQ;MPV(;Q*rl1h^2|t8TShA~xNt=F zP2JR@N-$UHIIV2oyS|tPxW*%hUXts+WG~h@ajOHTBR;Yn`d>sL3syfz?EnA$M3Mjh zd>-=3$B@w#-Vu|-nQ3El|Bl#`z8rxC=JBaNGtPT`Saxg^4NE9G4OA3A!I}P>N4z;g zK1O&Tp^A&zVlvIV5ZLz=IqQ)lumdg7jgkJp2q*fUgTPb6&oc+VPECDzN33>rY5!x{ zI4AK}w0a&g<#6$2rQ8R0(3|bp-^7pUfz7Ah1g-|^PKqF?UC6@+mhHJxZR>L16pgd< zQdoilV7ipeZ$f;j|Mx@qMg5Gm7T2~yN1IofqPSbia8&heQ)?C?e?soku@}a}um8I# zU$x{mvvNTs$2V_AP<0-SraVklW3~k|1{c{Rl+@IiP$ae2Ma@}`M#}M0mQBt?&v&&9EA868z5IT__|0&W z`6yd@@fQH>MwqxaZ_p6s<_%)ks&ss3J=UA6c{jAKbxT;ngBJd!u_|tni7nS9bH4oJ z(2;PXw-EhuR*!LJNJEYHBx&lwLs_vA&{kp8_>Nt@qB(MMl(e7IF4#lAx#;^+3|hYSKQJ68_!3%2@H z(GC<#&XO!_B&ym}9CrY9S7~N;j@PO+-$$?blW(`>?{Yo2_4DrYV{}FqKKYVGAyw;e zhs?F0jamQlS?uxVN7~i>hsRuD*Yzx~P59NM)VF^<&Elo1S7rHLLH3(dqp~mG{9AGgU{fbK{)qPPq-j%D;p{x=W$i;l ze`2k)tJp$Srbi;%X%tENMC#1jD$7o@h*`c`8y~EVSo&_DJqPvRDM^Tv~B%=#7-*zGxj~K|zPV|KFd&mt$BM ztjfXricLT=y+M@D=;VD#u`1i)iQ&Y=_YbpATMym#*syk;&$_sGu|RzGtM$@+Om}7e z%E778m)$*0r+J1FRi*0fN4r?VmFgC=*8fhugxPh+%JBQec_|5*&N#)Z%|HK*d$>Gm zPsx9JktZr~`+tSg5amx|cZ>QByRfup`S*z_X;kYAhBFze>hv;&f8&j)Q4+1qP~xIM zU2f1RMx|cedT{uPpRB>tm+slm2Y(&3%1sXJw(PoCGC44k&d^YiX%Kcb%2dzAM{eeu z0=qoGd&d-Q=dF+Ql|C&cW!-8MkGL+z25oBb=ItqGery+`@x{DZ()N@8pNp2Uq-c=g zvN>J5vj@L;NKHehlz45Q%P?J3UR`RvVKDXgSYD~w-Ih1RqS?Zgen^QZu|9j)m&f`@ z-dA2GfUPOMk=7vin2awOFG*SH7PsxN)8=uH@hN(sUlzM%i;SH6kc>LDY1OEk4(V@*4 zD!Q-5_!~n5srW3j+ru}l^S(MY6YU$5%jStYU8%Bl)W1`&|1C>*@JKt-U}-r%W^QIw zJ42V-GyOIoAi-&1VRAYtNT+Om*<_w^tbd;FMhR-eQ>tjuVK9N!*$^poqG{s>RQm~wK$)( zFx+hwZ{jHFai`C2eQ3iyP_-*#TafW|dDX9}l0rsP1xxQ&cm9hDDr%cJ?G^Qxe=a2A z6ctUnt@!q6W0pXAAj{}E#?+VH9i^kz1?3tisi(@`M^3F2XlGd*lyaGM9@L=9eCDk+=^l^<1*E&XyQRB9x*PtBzVG*a|E%TU zS~|?kz31+G&ffbx&+V7uU#a1nje?h(dJbJCa^}|iTdsB|TlYgrr}v8j4kSrK;OW!7 zlq5#x!OghF!gt4eH1Aa+Xr{dGGNyq60n~}~Znvf%`|jW1jD?-`@#qb|_-vSrmX%N> zZ0?5cu564>f5Ae79pFX#I%tZCc5i0wDdKYkYrU}2{%*`}>%vvHBaal`o+N2()g6}g zbsC(ZL2l9E@$JB^>vuH8)jo(!5bfCnh463ZUQ*)B zS4DkJGfn2oGfat1`k|Gev>;YD8;ZvR_V6HTysQb3l+$Ryv@9F~HYcOdybqP?bZf~_ zby)${tHHg4mM~wvoNmzkkk8CxN>?a>D*;IVO$$i!?g5KZ{zi|`;IGoTHYi;*Sfdm1 z%74GksOH}av9X7$PT;su&=(j%!UF+2F+Tk1k#&44o=Sa1M&P>esc@m5E#Z%L>NV}^ zUG{oxM7A*hlT}cY8m;F_d9XSM+n&g5dDpWL`6*#XRrO;(>x}KzB=YX&mHMN{6ZqZn ztt2(&pd8XSNvcl?_}Kje>p`=wj`QcRZbEotZMErIWlb>>>E4G+i-QVZW1$5N8ZC_1#3l_dLvZ_uBR2mpHC->z-Nc|q>sC-tMApM80~EN`U6($ zLt=3*QBB-ViEmCvOCDAWxa!>zXt{8m zJ-m6iZ7TDM@b$jO)m=D6`#$0GeC+$kJW@is)z{^L_3tL8q40N%Mwt}DU2LuNyO!z7 zawLA|AW$>`!jrYpMU%}*s>|%iE+(Ra4v?K=Pgc!%(2d@eIS|5>v)onIj*)XVp`5)J zcVh{!+|d5Kx<)O+BhN|FeI8uEkQ#JQzct2W?BmQ18`Q&+oSD_wNT5XFe^CD^Vf*W* zGo;}@lc-X2+GnU~Hjm_o;%mcapPU7sWhJD13JTHN`Z#9r5k0_yDS3_Xhv z85)wM3%1(%1fi@sm~f#;COj2Mqsm$9P*o zH7xNt{@N}_*Be(J1uR3mR|-u91q?rPXrj3mi8X4hg~1k;CSS0N%1Sr&wOAwHq(2Uj zuZjxt;1B(%v-~##T~rZ)K84sH$)$7`?0+W~Yk%}fLMA)4g*^{)1p$JQOy0YtuZv7% z&o}tV@0vh~#`Hy zoNzm=F3+A1FGMDTL*QF45jPs{fQ%-TPbOO7-JP51+`UG^C8@=PT}EI9&wm%C z@wAalak_04d}+A4-yTj?mEp|zz=_pa`N>D(UnKGQx3*b-YKe^&dZ_?A=Nu$%8fnmV zkcd$Ku+Y}_=MxSN{&42TB1nJ|{nNBr2(^oXWY9p-gmK$MDk2I6Xiq>4f%<7fJjEXR z-XFLCvzn{FnFC_`qB`?`2h&#h-@&|Xr{!IW*YTH#>MLGC;L&YOxUxH@O0Q_x54*U# zvs=ljW*d!z-4?tV{2Uw{|L!Gti1X~u3n;dh(vU=*HjSVzolR_$m>=h47X&Dk=*oy0 zP)#2V zdIO^^C6B(*t^Lq?%|Uu?&50AsZ8mgLI(yY}8n`|&rCM4-qC;zorY;y6{OBV6ROPBS>oe$xRIHGt%0z7wfb z)%k6=Lejgo!f!bn9C*W-LyvdU$*l+$iw26$J&dctKQf5(WZ04=9M)NcU6zqdx8Ebc zhyy`){lcAH;fYt_->G`@_f#ozOo7b%KgftB8#6(JOo(oqfn}?g`C`w>P3E~X&S=<0 z1@T+j#MG940K8DyeljHWYGhEn0G4g!y2aEUUbhKao8xJ^FkdA3BNpLu_5oEOi!5_+h(?}{a(tj&Z zUp?GJ)~HQjLGRws;N>{nT*A>j#Pk5|zLjKIPMAAkp^v0BU&<_tv#1jOKQMrKbA3bNvX)sIy+A{tcGY zn6VE!KO@1g+Lz?|G!llmE-4+5Z<-Y zsGS*oS#889&^hkqo^Oof)_!Jr634)|5_HFvKZr^1c1RPPFM{|mQjpb{r@>TIeT*bg zG4fFxjc7JDA&L^Hrub~%dNzP%+oMk#+TYL*ByrSmL^Jo_3$(NA|H7_)W;M5hl4p2J z|5YE|loS6QQOL?$YbcCM!=SkG1NXh5fL6m_3y?FkF}_^Gnh;=kL7!8&->pPAQpu<2({$OWfE&_53KzWK3=k>h&Tf_@bJ()sQ2WBy&&%xnd zv^(qHe0CYtlNGbWr-i?6f6V2a1ikw`(!6|88J!OMNlUp6XRxlT-_-5si*gmgXcOU| z<4+G^-$*1liD-!;RX%1Ppgij19YfN&{7t-cxd>QgR`#Ab%2f(CAbBqlBA!V;3ua&c%LM?R zIaXC1^71>)J1CtK(F41+H5YSRGkq}_ksr4sAHOB@w!F=Ql$6g2L5UL%=!g;f*+Yqg z;NJ)N16{nT!`>knp5k!L)W04L!`9He8eK_?*l*P5*F9=CSXA-*g5JN;0z4}+sVdmR z5n6X?*|&y9{3Q31N_+}L3CLNj*+^Sn#9?L zWIbJ&gZF+&yyLLx3J&IJsAVe%M^@9- zhSlA~WV}8=l0nvU!aB@lo;UZSwiUraPg_9Y5G4jQbJivmhs59P9#Gtl+Dvm^JZU_x zzUd1A3egT}p+GWllc&#tu6MpR(q<8R^ECws>>$lZ1`ikmi$`M)8Ky+4Sm{0EI6@Nw zxI7DBZUFd>yV!pJ=OX{04B<^T_cS}M3L)u7+V15MT2B7Uh?o{fwNr47lxT3*pb?Gh z>ZE-ZO{|`PRoQim!}p1OZxP0Y`1kBbjaG8OWn~d^kUs{_8pO#sOazu8rSs`zX4l5z zI<;@n>qiHA&gTIXkCN~m&C$`(PnCiyj&ILdQ7Gj~PAg{^4*;KQdVuC#FB?kE1OreE zTJm|IPv)^BTenw7{g<>X@X52klf z3tdDj2MR}59#@T2@0h;JPtMHrvih9K0s9Du0R#cSvl0Ez0pbXS+M6mUBdmRa-(P4z ziSMM6L15K4is>Gr!0=B%H^adaW974eM~8!Hv9Hd&H|5}cYb>aX07Yo8BMski!b9I=&J493)bava0lJobg#JuN#6-& zeH-!)ihn#5H9XQzfJh8#{untmZaubMVITFFrGla9?iMx!gn zH}Q2Qg!J{J$^Qin9YI=+9IF$<`caydQS?hu zQK+?&SDi@PVXYqLqG3y;(owT?;8A*^G!G8>dUWu4Qbo;PBs#xW`@Vg9JXhLya`X=E z7*nrPej0hffka+4i7STid9}9|$W0mph*6-A3t+hXw<<;=mN}zTM8KBmp8S*XXRL}o zPs|tvrArlY2;X?phrBmk$A!x%=sTUtIE5|&iQj!Dw!ikjQ`o6J3}VtJ@b_kGL-I_O~6+bF-# zJRaazJ-nN91!tfS9G<;g)fseA=ew$E;}f}>Emq}27w$;75|ixpXV92c8)i`~f7QOVGJ@r@_s$QuX?4_3_J%IecZ| zC0`6VBO9xQ1xF&!MIr8}_h$@IcoDuAuUG_+w8%?+ZF3FWU!_+)nc(#k5H>1zDGJmlhQ!B1^Gz^2B3y(=zHdg zfZ$!Gw&$Ea59ik!z;EH3OqB$aDr<{9n}ha*v*0xODZURFpoJG?6GDrW-*R$Cp*ACH zkp;CJRDS=;?i9Txu87^tG=|l67cU)serM z3%9XLd3kTfKHEy)YG-#(I~9eP)oo*<%xir^?2lq3A;=%S07|z7^-2S1#J+^!esuv*#V| z2X-wNK#wD43jB!dYmFKE2RZ8(?1?Cuv0%)s81EBF>pG;g)A+gq7NIp&z7^|mMyigk zqX^9ks6`YF<6OdvjMEOv6Q+}W4|Z@YWK!zHrce1Di3jeUe=G^Xh~JXpnj^xfU*#>Q zKn%on2biZ)h$mp(nsvh-rIN#S_Jl@dslFrq~eU?{mkV~e7k zcX%J3{0&bw*?yy25N}*$d!eDAcV>{zUlXH>GeMncC~LxJKX#F45(YhuL3qbpcZlL@ zmqTEAW`AYA#1s8Vj)IQzsq2oJ!pu=2hNQCN9AaG^P55Mse=s0sA5=SXd3m!|VTy^$ zI+y|dA-JKygW93InC{-E2bh+k~dvLEI!L?;cvh z#fV7EiWNBK-RTA=j4P+oZorI={6ICGE}k;J;&t!D>*MvV-B>R`K*lF2=LuVd2bwTw z*T*VEpLDhtUXcuDh-}A#GtUpPHLXBk8#udRZ@SgLHv2R6W`%){!|U6gIWdd6|DrX> zM*ma7MC*%AP6tkGC&lm7EignY4T-s5A#6Q0;!-W0ynqm%{fIHEHjmcW-8h`b!V0Yr zr?l<1xOp|gthVHBV_EA7rquFs`3sl1kf_{|)Ub<3|NcB$1nfAqK-LlYn!7zRD30L$ z75!R`ufH*Vg4)L6nW6TbNyMZS2wD-&!?k0_7s80y)(rA;v@^L4cj-iI;*By1)KHg! zScX-=BJ`-$>B39o!CZY%Zt|5@_D?7;cl&nGyc{Kc9O@ZFiZ2@K3mi+}F-+I9qNc2G zUvZ5{U`}|}xn@Km?)Odf-9(n~+I1bw6~ML#z_}J!kVw z1>I1@1_L&H(G}G|_oVVv_~YGPl_W;8wyTHnMsh5RU#+A$JnOYQo6pzu$;h=Pa)y^l zT}!m{r+oC+x&jc!Sf``FfI*SU+V@C)`A~0TWncG*@O2D}K_CY8BGoqVkNet2bwaq!QJP25yWyXW}f2&uoxdOP${mFVz^Ev|lZ`oLKyZ~>i!LDiH{X_Bx_S1a(lQM&_Q$mo{ zGhXTayI(CJWVd7u=NH1#2IoPIRKIlSqj_&+$O(eOh2fbLrHKq*;h4eNi(qDhqx5p* zeq&^Q>s0lAk*>uXlcd-^J}=leB7R?9;GUoRFqm_vcFl&=1>OlF99=0RKW2KaHNevg z*>jiMZ|JVfP4Mt#nj+2fv74ZCiXbTMwnzEwWz20HerK=8byfXso!Sz0dmF%#l<$bA=Sc}rItK7Q%BE^^3XCkoq0Wp zwX3vNhJH?@>%Pn^`lVQQK_R>Zb+M|?H;cUS+IaDbK9k=tRY9ADgJk9VYykXMs_h#H z?%?%}ioCnyaT$q9^572?+aR0R3Xb|?^*Tdl=mN>wQb(q{=RPgtwom1d%mL{{or-9t znJ_czPo@GAy-++tC_g0VU2NxP=Fm)|*f-~b32a>i%I)dfv?FzXU?N+?lk|M~!b3n-1VyC@% zIv#hE@Mp7g^OcwtWJq`)>{aN-(PMe5tsxI+^#!UB^z$9Falh4JvFjB6@}IdXU*pt{ z7^iG{!v_)(y=Dqq`5~BvgJcKV{#tdh6B3n7HX6n19@IR+8=C>e@I=DWBB+H&%`Po< zNac7QMmZ0!)u!P2LIJ0SqXO&v5?UWCN3rd<_xbcGB~~J`y3T{q&Zb+{*fhX8B`cp@ zYp9_bQ}6~eUDe-A3c}ER{GR)=8JQZj8tS>5;;tl8Sray~PLu*k;2Ajt>HIVbkE5st z$+jW9Svf(Pm$ixcL>S7ZEV4!hH(@ox>bogUDLa;=>-IL`0QKB zFoU{wWjIYU2@7hSgxDP{SzZ`eVYm_NpuIxy6-GLGL#`@Gl&m=k#qyN6oCRS|z%KS+ z=7;G%*1m{sv0XTGU+4v_YWf9sA|l31Zt-R7Q%&QpKBhfFLz?uTE!E%7OL4nR%i8PC zCl9~o7-LtT1nh8YI%@S3TF}^SLe`gKB}>)fJ5k3d1$q_IahDSB4Zdy5f*&rW=58f- z3$8tW$!y_4k2+{P@e*;}_x|t$l9R~Xn&w;31C?A(@$!VJTv)M;$zikP+Yh*H1;&Dk zmV@y(y3-e*Mu=yJQ-6D&ed@tABgyCRP~@wi;tMT_pq>BuD@Y;?+yF)Mt)zkzYzwg* zxpH#;Tpvj%>YvIzd3{%|EV-HHIl8~v;7xqHqUY3ewdB7WVkx=Y0@e{}YSPUW#e!b!(qFkr@s8A7u5MQS{*@cLHaXp;?9gm18y z`D?C@irK;bO5*XNUQk!tyd7dVqoaRVWsr`IKBQx(1aX`;=4s6$fDF4H-E0wJbcJr{ zT1*d$8d@&@*PIT6CSsh090=_Mq9?G5mT3jTTvr{TYn1-<7dMNVFnYXQPVT5mt?RnW z6{VC9YQuvr3;s5v>^mRX_!sDR0?^_3298@hFnf~>2`b7C;uX?dzh!&cV9Wi+qDmJT z*8R3pF>at!5yoBMlj-t4=WO*G?cJ=|x?%Jk)0bT9LqMT1JbfGV!gII43l7%ztfmu{ z17Q~y5j4IZi0vyD3@+L>&~7@e>b2(qJ<+rA%krs+zZva1wO0VuPPfY9kU|=#4$>xB zjPUo_t5loBleyNByMDkW2rQ@@uR>0!BpZ%_E3I)_ z!s>@St)11iM_>E1*E78gk^5CyL8B~xdn)1R?QdDc9ZSN?N~E~Z;s8b&uv8FZfMwa6 z;$ta?{q^l+qGY1HP}*5pq<-!#E^;%Ak>DTSEQmh)>eN{a{@ExoMtuXB7eP}nvw+i= z>uy4-@y;?NIl0k&^BCW1DjBPvE-yR4STm=|eIS2fEN%pUCdbDTiyjAc1rmnl z=n5Qv-lZ@S71Dnq&fg!m>KIU$C5EN|yAV8o{JAz#D>Q!FRKUpSshfEBjB~_mOD={s z;Q5&HkU262S^Ne=C;X$a7GYzEeldA%pz!ltzbH>PxFp5)aCZTXWVQ<*l;Pv{WTNTS zB1v_l-f71S-qA9H{EfJG9C9gG+=}+bf>#jsJ6u0pwh_#G9pw?Rp`EGiq*dCp;|r&$ z0O~5s$mv2h0RcJp0%`mw(KwTx?L$j{Ku%twc`h;^H?>wBZ(dS~skiC>BDgiB)FKF$K7a6ek`!u1$hmDZC zpoxP%^OG;xnsA5uH`?^;X-ulSJ#_XT*cvo}A`Gq9(bD=KZ4RVt0Sbo2;QgIw+WxW@nFdZSU%y;RiPilW-fIm~Qg9e^4-)1RcEjNi#4+-Put zY_wbt*KZ}o;Y>;ji&$m)E8Cht_4A?hd1GdOO%Ndw2U8x65du8g|97{M`+K*kS2n>` za=;wGt!}I18wjTta^dn*g zK7%>~b6tjDu^JtBXtB5sLO*f1Tii`lk@ z7T$VWxl_ps*~rfd}FU1-Yo4sEg+; zXAHbwQVnv?e&_`-ig73|=o*f;p$zcC92PH7#CAI}+50Z}odsal&1|r!oR7vQ2Nhn6 z^$tTL=9$xn!2Kz{S~^T}9x4%a#EUCm^ONF<3H)vxfs(~D8Y|t)*m#j3sDU-WtLaAe z6E~R$1QX#4z588+IwQhJ?rq!@XI_rZ_o|4OJSC*pk{(DS|cZmm|IQnno-Orxtt*srkjNJ)B@HQh2bXo)ssAfmIoi z#1^yxRxx5SB?S~svK>MUQje9d z??e*_`)jpQ#-giCy&>5#0e;@iJTUCoDV8#0`1PR3k}q3{KEEQG(L`Q|33$bJt?7qd zW{85ntxG&)6f&y1>oYGgP?Hugms3qJAHcEsS``?DDOQAB-m z#AlK7T#3ufhvGz-qr%8(^k(>63tj<;mW+|&ZmY8}=z%QU_&)2;XRRtFLpa6?1cV^c zTILh{n7Zr4>nawOns;BHWv&IoYby2|7JM$N)Z_0;2xviw2NSn!1|PoJFGG7E4fz|9 zx5VR%@c7m@g%^^Dor)#m#6C_q4V_79&MJT{T?X$P zyAFpoB2pi z@ulM+8iZ5Ag0lSCySwUZ%-#TlW5wK zUJp0iDeeeaFfL8wLEdjQp;G*WzU=_U?v6+M{nK=w-%h!5*2D%IKw_trpzJmD(xNz9 z=wNor5srTiEXSnNwrfg&RFD99%}eor&l+Ll9;}xW3A+18pcNSM!o@47j%DsIg_Lal zJB_Eiq4ou%V;6Cv^%?G)g};HmG!~ZQGHKU_3S9MeJd53A?PyFFTa5hI3lejQs^6N> zMdhpahlUchmEr7c%CR*2VOvHAw3Z-?lJ121VYDsHGHjMU)Y9}H-bS+sp&p2mK=C}_ zY0zNiP)=U;*EKm^uz@ne*7p?IZ~6$ft9p-WxPb9^_MpqQj(TXLE9O6U5C7=(8)Zy? zt-$3_I_6KZ?nI=p_A&%6^trgF?xJrMyT0Qy{v6%ZypkA2-nNiEGc}$96-d>eSbf3I zVr@q7Ae$o2;j z5j7)*Ai_{Q!88r+i{NOuNM{UJA*!x6PKPOc0ZO8Q>~1v0*oYykM}LxTN0Kd^$ztvw zA2eKXG6uX~_cTsP$h)Rw<1ii80XZR+p140XNQUgh&MabdvQk7b&n+0rG+|#zKHA^4 z({(tKeMa7!W^!*M{t@SAN%jl3kXc^b2O-TpOid*DT27-2q7i8b(>`*OCCTA!v6bp4 z1ZNOgwP4nhyE-3I5mo{`i?wdC)W_kq+TVi(Yg{6sGwH1J3C%eC&>C`;qn+9CpQq0lTOYK{v`_@KTY&IHrzkQ>gNK=JaqSCdo>`xik_C~> z@)*%bBvG#nt32Dk=NIF%IiaT6$|mCClz?pBj0lUM1sT}yFsecS;x%{DDb@c@F#s02 zz+G6Q4N?RDys8~3)^Mee(U%6xRau0NC*c@ZnNDTT_JU(`hhz~_RF<{6itj$!y*->U z<>^QmPMz^7J7V|l!Vg=(vQ>Y^vu?x}4}4~0M+uP4Wr3osx0!H8)tQZ@A=ChWR8#vl z{y$@n1PEPBhSxle>QFi_ zHFd15xO8Uhc}~H#VzZo_dr6!cP!v28FBs#NLZ&E-LN7zEb`u)=eoEf>QO|Pc zyGmaTiZeShx{S?MjdsTL^wCemtmt{u*o239pWMXVHsF%<_A?6 zq#~H!dxOQ3j!9ooH-t5;bbB}PX^S04CnHtthtS#=IIo?$QtVTUqO~=G%S(u;4`O!; zw=F`cmpauucLL0wZQWx88&dakVIl2#Ka@tFU9DRQ8ykIQ?>i=y^v}ulQ8paf51Rhm zrNO@kk%qp637yhZKYNsH(=t2*Z%lZ^7cOECx(?2_vMEvDpOkP?xCtog8FYhZK?iGO zWtPs_A3ZqFd5vFa@H+X4y2pv$5ZmA07qeESOiWqKH3}_QCzCyD)oMP?xjh@|ahN zegEfmQJFFU@t~4CtnB|gREkT>Oe!+FEPZi!*s$lI# zn3r?o|Dc}}O(XZIe_V__y@Jnp1Z~rM{OTmjil=)fGQJDzw}Kqly4t{^IZ9#2iK{bU zHT!8Uv*UL?SKbjLfu;X6ggw&I#g+qm&(!786K8Fn3$th4frYvcEI}#iHNO3I*?J)P z+1t!rC%%b$n&!#(#4LD{^(2WntY2UjQ{TW0;B$sJ$HnFDqWeSzE?0zm9`J2+M+jlRm7Mr6qibEc#L| zXvunY&!#L~9t5VT19LxUh_jPYP^^%(cE`77^)0YK$e}Mu_PL_GA3+5Ss>hrCi5wL` zm%O2GSjmCyHvzx=>^qbGs1DxCYG3TDExitQk@2D81K*r|3?*?_Ri3aacO!F?VkPoV z#wb(m3Cs++Y10(UT$Ju5_L=@vdT)srELZTp zUKYDA9}quG2ahDQ>jqcCr)mpe4}vtsV&&6Jc1xmT>&SC^+NVU2e<1hYvv6w>G8jno zo|m1jIaZ7QBF=fpb{63b;t3lHgC;Rxh*HjtEhO10^tBpLL|Bck+9m0SWO&=v31dD* zU_v}JujX}B(*Nv})&q!MPOC_MS*+X{(A z`j1l*yi*_iG=719$qH9?==z@pFqC*^cU0L%GR?f7W5|v(dy}u-C5!AL-Vi2^OMeik zJr7s>TQ2!C!a47mug@$To2*lG*(;*Y|2UJvL~yg(OQBZow+9p6BCZ&=IFMV zmfxVD@!;I`;d?aR4(ZK8MNqADk8q`KBa{a0fG9^~N@Q@9g=X)-B>$9S7blPVksR1N z(h|NJeka`y>XSHob#!ZcR3wiZtCT3hZO?n2isLpfymIlag>u|>*HZO3sFHz29 zZ{@M$j5Sm0*gBqYPVQ0bH#-#a)gg8)%6sST)S#X+X;&6Zg=TZYRZ62nXC4ZU?*zL~ z)Lo5@Y+$iPlSvHd{@7R)8-mi?v2<0ODnkPoZb+M%T`+zv<}Rf9FtQZIZ`hM(-$ z_;|;WOAeT1Z114w?#ha}@-*8I1M!Mr41YezRg?Tm|1l5Sp9Zy3f9QA^sJSkZ3wF1b zrF$>5J&UD<8ZmMsr6TGa@JCYR_dV=NJC+waMAOi@@|Q$~F+>?CDe#+2l!0azUaYJv zf?!(BrQ&ZE>Id8=us^`VPd=-SZ+pblrI%2wGRDN6un>HlfdN%E8)86Uo(^BjE|@Pd7>WH4IS8HX-IWJ=Qto2r}p)s&?6*wjVF zlu^f^$sKKD8Q2re$L06<;oX|eyw{%a!7bgPX3hd!z4$U)SbZW8T5y!c z*OA181KO9_9rnuw60ljJ!Ju^9RnN4rsST0-r*aO?TshcT<7v&R?2ls_Xeig+($g$Uom{O=8-Y1@om?bn0H*jp1}nNV>4h4`f5u1u zcScblC1ZcsFfP>A0$DN^kP@b%W*#(ou>1}4X`AUx^FT|-wY20&?#=sD#PWlkQV||( zs~4I9{v>B;nqQwd$$YlhKdDK5e0$@yVqdWG^XNTH_Xv*eK3!C7>D2Cy)G#rlhpT&L zkw|SAB@s|BA^@z*XRVH;oC*>j6NW~4Izq&9Ro4CB$=0m&9#Vk$6uv(IB0`q>2+00$ zIxrqP0jQAM(^Vz_Bnuzgl>h@9%Cw$ZY>!-7G{6VICZ$pl-3Ol$@qx-;3%5@T`1U<7 z#6DeEJg%<^%~MMI<0ZaV`2hg$d6Bzn4utJ1p{XS$yQ`B|dO;IwFIvcAe{Uolt`gU7 z4KLHHgx8c7AdP}l1SXlsYO0ksuU&Iyo%oZeKbqBHkyF%;Md24BSW+x1hr(pSkd#IH z9vjUX^6DBZ6O!iYiJnikM#U!Vh%WfoJfSw-WIqpo=7u)$_8=ebVoh|?(X1XZ76W-N z*#HmQswu#zz zr#2dPnFPENc191fG%Yb0T^y0M$ZZQMH<V9B7*s#>zZ4%t)! z^&TR+2t=h#e4@;F+F>9ah2hWRaKnh1zLQ!Q+oEipHcH5tnH_ zE)zgyr+ISrCs`CMUI43lBi8P208%-zZ%4|KneJEsG`yGFCb*Q>Rl0I`crT}LPP6O*^OmB!FLQjj=cHv$Ie z6emDU%vISBzSj8PV+GT;fB<>Voz=E$*Z$<&btuQi-!Dl&_c+dl%7#*{oSRhD{<%F9 z{{8x+RVGa(31#CFLQB51{FQz(ht?*w@)G1Vtv=e^2&Xdb2RoZlP6JbfijbS+?0A&{ znbkdw+ZOyRle#$^fXMkH+W{wpwPS4$f1PaXp`Ha5%Z@Ne4Lt(Q-xS-RMdlTHDRi^c zMI9~JS=aVt6GbY}J2y9nO3EyQ1&|(B0eN=c$<0MgnRlc$x2GB=KLH9r^^69PxL$s% zw~?z^$_&bHlgb3ffENNBC^G=l3G`gUcCj%e4aqAgoB=#vz=aOriEk4Zn*h3Dt=;M< z`SUut?QKJzMR93qWpnfJD|8d!1%FRXgi+zUmkY}g3q!6nm7*NH+hx! z0d5Vz)4?txGWPnK6~L3NH$eP+}_^&TuZ4vBA;)dAZ9 zW@^FStcOBfyKaYaf_5nXDDF!wH%qSJ=5h?}7 z?t#9NB!X@+J3FQTWf^e3_ z&rswE1eS{MOS4I%Jt=S3ss-U_ zMdAb^N*YK9j#?WwP2eRnLE7&e*(2VNNL7YzIPw7gWq{2L$Z-frNdf!D_~fLcR`JO0 z1!j29T#XezGcz*{79zkJ1889Vl@Wk@z{CW&h^4ZXZ~JF3LnY0vtf+C2bm~qtW4nsx z6{O<=a~Oc9SDNBo_P5<_$M1k>03gq`+$RGr0DzeJ>c|=YtHZf(hpL|12jEhZ3k!n) z><`xlU=1ovC8wuv|1MBXkfr5Rz`iDi>IjkNPcOxnO3lci!wRL4!2)3X0NnQcPH^5D z3`nH#@bQ5>5pd=Jj3yu=_%e6>Kh=#oWN}cd&fFD@6MClzIrLiy_pES55X+}9wpQF) zx^_C;Ebp}Lpma%bZtV%Ctzv_)dV>6L(lk10Xt9mDRF&?bG`JwK4i1aawnLiMlL(e{tZhlDv=wm>P0<1j%4KV!SxG7ql<L1Zbn}K)YMY|UkNq7x;nPDMu9GP3IPmNz?dtX z`5GtIfg`imIEvqPD+N&8Li;ww;%J_qPhK*B%Xu_IXy_FJ`AH4X?}fZ_R+YRquz_2Z z{FJemSK2Fy6acYTRvW81J-td)@`bM$p8>bvcfdylz~dwOHVps{Vdm4JnRdOs->VJh z_}KOptM}@1YTuvAZ?IqQd|276i7=P?Sh_%ufp9wf?ytlJ*p}tcv<$>2;Mx-U`^Wo6 z=aqu&0E8WY1R6{8*X)wZ>K$5THWoLu4Zzi3k2t95xH0_o$N{6^`P%LU3}CDQW!3BK z89;dg&R_sZ+|}6$h0m(H1ut?734pVlGxq?rt{;E}4gy~E3W9zOYd(*>zGwKp9l+Nw z@t}JId^D$bURxLL01e~SmDvZ7EazLj1p)#BAclvB?YH_d0lu!2gwG~a$I%@Mp>U;Cm+C1#yptR>poz(sKz7UgCjn-`W%$%}}B%eg1v-^=jDDRW;OwdB+ zL7%ukPV#?+B&^%-YC;(}CCQdW;GvU^A8jTAd=iQ6QEz6vfTCzp*yyODlMVpljTtco zd|;G7WCS>vKoXZi6deTxaN>QzhXxeojimtlxU3%>)nf>lZl?hFEnp`B6i7LmB^xeH zp^{XyzFi;H0BJj5&H_ZqvbmGa?<#3!0BYBoJukQMu54T&KwZ=>^{A~F+BUp7UIyUB zj%OQEuS&BT%^psL$^B14skf)=U7$q9W5CR1e=bejl-ur&PWBl$vcib^9!*hm1 zVDGipnx8qJ`OJ783B;Qk8lHNdDC(APJ0JieXC5Fm24TM?{}C+z2h~(Tux>` zfB%Xn^3Q5&(YgKloqQ3k^jTS1Uo+oY#=*wO`Y}9Y=YMM?ld#toTX|0Eya+^EaQLwN zOG85g&>Q0EK|#~NG%YMN6kz>F6bg*^yLAr-qVZa$GYv9b_j;azz8CB*WkPvJAo$}1 zBZBM+>_c*>7y<=V{O9nRF1oNY^D+V6!!J*0#63wt`WW_h!4hcX)Obr^e*GeN`t&Jm zcphKhEd`GU9b>QPibg4-%F2YD%5)B!$nL-*88+A=cLjEI#h}B{ zQ*(42+}(m&vW;^d*rCde<5jjat=i7??PIB*e{SCzZd@ta5aY$E$2ZvW{809Akouys1k(g_X^AlZC2XV@F(~H&%xN0Ot@BnVj&zm@0r*vj+kHwKJX;nVgENG zchzM@1~7YMIrTB~d-Rl$_YR`Ew#l}%?6d4eZIlladl0GM#?y$ny#Dfq0hD($(v!xQ zDwcstbX@4=h7nb~{kNUzO1y%CLGZ>SH7F1zfYq~zq_iHzYXoT`-qOt69MmG!$v!D` z-cwZtug1>K4%1p`^FOq-k&)6s!@pJexs2oLS*jq1*J4%x-UH&?IpX0qe`1LTe#bcA z=6 zXcEx~)grP0upi%JKD(r4%83;JEU8Q~#2GLcP|H)IkAK7?);mqkx?lUj-=^u4|*5N29EqwqHdeN0vTwDRx zt@?S!%`Mn<J0dw>YyisNs zO9Z{+Ovep)Vxc3;=V~Wbk^8tbRI&S0y}BM2`VJBA%=}J;qX@^`y=^m~!4ML=K*R5a zg(@XxJ6sy*4{EAWQpvTj_ciuW8pk6Lb<%SqkWmI4wlGi<78PY$eYkjxtoPI502y$< z-59@z;CH~@5FLift$yq0s%$HZB_n1wHt(jUOz|6Ug3vLjC@HfivYs=#aei1$Qi+6P&G!s;I4sdZvXq2)Ijq!;5fYWPR$a6Q^>Ib&0fTT0T2a@ zCi&-O)ag3eyWrt^^Nbiqmfw4e=YOtD2+vns!k8s0R%X z_oXtdgAffs2vEn}tt0lW1ywam!#W5+C+Svc_T|$XocQf#JCm%B*KinxF1qm3H76zc z{}OvlPvv+@q1Je1!@M@@Wj4Y7;i$_CQRZ>xO9vzq+xv*0i*Ji)GrJun2g=d_f*>V< zMZNSScRTsyzChAR36$-ZC$QU4k2jbPa)MQNa4;r3yVdzI1$}H$a%VN8LHdJ@lheK> z|L8jGSp?A#kW0BH>bi2yZ{-{aH@*y};N%eyxX%$&aYUVxN%H0%fZ?t#)wHxUK@*Dk z@^-K(@lfk^yZd&}ik7%TEH`-xaT_}3i?4&SdxpyQfyHN>SgWG9X_k~}4`F3B$RUGz z=Xu?p3>B6c*wIc&ANlaltcz~t@VC+AwltEE`+a536acS5ZzVyI34HouZ9mr9zN%$`k4R__d4|stg%1$Ys;Jy@?B0t} zS93eNP)Kp;Niu3+!eR6j5{$VhCt<7q&B#`WmN1_W3G~`Z1M!vfXMmcph-(5h7EKL} zQH0alnC;xOF8>cZ;~)w!TA!4ZqEM`SOje@d?3i#18%|>BDT^~(QrmasU7#1Mh6grX zczSxiH;pYWF7{k4g{J}+D{c+S5m8QM@6c0H(WY>X0a9aezQ2GaiEqPm7^+rJ)nI$V zM*jO*B5Z-@h}nO9cIHXO4-or!n*xeCYVd+^48imi6Gc=hrg8)6AHrj&f0zQBt0{71 zd!9iC+p$VLKaxq?l&~N(gtI{ozys3z`Z2CBi9Kfc zZ-&gL*ru-@wuF;)6ZcFswD4uCuso}H1sTKi^t6P^{FzQZBq|6wPZI!0MUdqnKqt_c zJCSrp!W%EIa~pTJw&6DlIS65$e0&P2TG>ys)!+bG#JNhp%uHbh5o`s%DATJAeB3>4 z$@3x~8Lbp7wBnn&2!4Jcd7JX7JO4{hlTOVNKln}9y9bI46z;oIF~Xi3%#fdaeiD50 zFEhzO5)PF;&2v`!j=V1m?yO|h!egWjLlmGv8t^BGl|0XxuUu`Ses(c5RW=Nfw@7|m zJLS}s{hpxVyN!?Uf$`QtpEMvX(5jF7KKg&7m#ylU<#lwQvi7JM7u^@ybVMG zs;W{`{bgxAUcowbh}ObxOFBbx4O33AY`YcqmaF>2Qjn8FU<7O^Kf1)D5vu{BQ$G15h>^OqeA<{qKNJrOE$6|=aroj0Q z>zgZ7T~<*hJa2O5K^PFQDMf(G2ONd6GvUvNGOXtX-N|{0Fh$jx??3%#D|Iqk+~c zkP`R!F7^mHjsqBegZ!xAu)9C3)kg$wf^jbXOMKZu<1{Y6jajlnJ(@F?%X!u~-7 z-%3Pjh&Xgg@7UXOCO`hV#3~{wsRZ}{k$@=E2?gzXL&|%pzX^vc8jZqX@$JF_8}cnl zxT_yOegxzUTiU_a1q<8z`ZR&30#y(!h~InyZ7J9p1XRa+)2jf1f$aho1klXf9LugZ zEhrkoJ$iHRH2j5){1$Ck5AX9j5(#Q*YM@?SL==jw`V_uqdIpqgal}A|_?TH`+aQ|$ z4gCJb1|I-L|8vVXqU0jcQ}5~DKzad`ZL0|n$nF|;f8((`2mHONDi9p+=`%Pi_Pr&5 zDudsF#2m6_z;@K3UC$DY@?MWDH=m?8k4dNEBu3x{Mn#c9Fhc~OBIvt(EGAZkU@JWH z+j`)92#5G~K0$c^a{Ok;?gbK>jElb@p8l9{#DN$Cq4r#z!FM}Mo|*H6iwGphKomvC#2`QCRr#OC zcBTYe2e{pr`ln%M31AV}R{Upn18?;z+sHJit^tNjetaG_?H?S7fg46VT@>2KJn{I=S=is3_m4O>h1)K_EE7EEgGgR;!xIQK%z}jSl zSfqbwWMzdfqwG+o15!!c5)$o@vdGKJ0|o%+0FnYAeE>W3AHecr;K5XjhMVXgN-2|S zX=_7=NlU&CCkrJ39%!QWUk4$I9AJq+V+9B&6U`j+JNlLG;ef#ru=nN)lZKw&eN|Nn zM{MHPOgV_rMn>a-!LvRzfPO*y6<$27`6)$|E(b-P1}j{)4o5SnNP!yJ@OM{*PB`x1 zdF#g<#A$m-LbJM9;F$o>3Cz|mNwK5?63RvZ(ZYcx{kLNFkNYZ?h02!phL3Z3t1wFo zHeCX?zcbx5qZ!a7#g3KPGf;aRxCQyG;*U< z-yOp%CR6m(`%`pnmu>eFoR{b-L?5UXrIMYlK^IiM@KA8WR8>_0j)8wgG^xo>^Z{F* zDZpm07S89OwfY3K*3g_a-gV>`!CDYx2gDGld?5O2|HdLjENBqaG!FVuhgYLbxxxDa z$OiMoKKkJXq!j4v?oKjEwnE8DNr=YG(=*Ozf9rC{eNN%J5wU?{5T2g`@{SLj&@B)T z!vYXVNlrdBPz;ANLBc0)Y-~*G(_t7WC4!-pB>a^6 zo0(d`#sH+q5P`x~_m6RLMnFEDqun{}<8v5rCF%A+n*!99Bu~xzARYK4N;_T0y3=yeVZ0cJS%K3}Xb%cV0wW1@tiXg*+ zR1OdgXN1Yw9$Y6{s*#ieRF~IGYwYB-mhk3Ob91u?h_)d*9;G1YjpVdKt_zgJ;u{?v zbS4SeAX1j=J;hoHa?WOmuo0;GfN=u7B@C|FZ;i>X9!e%Q`txTe9fW|WK-88%Q?5(m|6AP6l+*Kv?_x_ukEL11l>zPFkn7Hl_3X$;3XdA^x2~=eze*3^yW) z66mRv0d;%vN@5b+TDqf^AjB?U%^^@9pd2N3e6S9b-dc`ZRWK4cLF;|JdI)x;!@jI4 zE{JD~P-_8f4bn?tunKXKs@1Fjkskw&$64!PA zsz$!HV7#y9>JLG1`U(V(pau~Cky?p+Ko5J^Z$HwYB!YEu6W|bmae!kCF$a7;Xh$P^ zOglTJxhOw_LZBg-5G z`sp?Y2T&1)n&j{*@L<5uPBv5Bwi#$zbnX1}=VkLm-IxPuW{g7T=S(ZtV$eEXl|o^6 z=Ucf5K;#4;+X3HgSAf&eXH)FZUSiWH<>%)&Hkf1!x@Jf+C?=*;%1KE;64nfh9N)cr zmr$@cK5nF?rG-BM0$m{HXk=satpnB11-&*bpi*c6awWh}!GbSfEKJeS;TUXeLPDh# zSqB7Xh@)%ietYSjj*;lNWkc~Jt3bxKClI-)P+A{gd~PZHk8KD%q$SZvcMZ; zWM-y-3={|^k!!g@v`~KfR9aW}8qm_Y)^x7RzNf&xb#<#0Umpy{B_vF?GND)wYCT|Ul~)cH3$PmQi#552qOgg6a%3K2B@hwY6n4JE zs^HTOPS4EEm8aAiA0HiJ4}S3}FfuX0XZV503v|mcWfa)P+X$e;Z^=UVg4*D6<{4T# zx|-25&vI?2xPjh)jQHBMYuF*b>0ejb&@2nu>gqjYAu}P6oO*OlP2NF=Fm?@_* z*9we>zenC;TM22|dk`Nt9@shyYXuaUGE_1z)nn}ErCuC)t>bFq`};;A@fvr@~ZoL~0a*XQrtu&5&0^*+ihNxlR;S%FVBp+Dq{u&6Du z-9VdMpjLCN#CAX<%|oWDL}qeta((wJ$R=J}c0Y$u066giwnoSzD;1T;PoFjbL8Sqa z0)Ujb*VcDuY`YZa9+-?1aK6F5kLgbwi}>TSh)Nhk>Clo?@H@0mRX5@%@G!gOcFZnI z$Jid;k)z2XNw+ecfat3Q+gB-@YzE#J^h~U}BL%TS{hLnLj=7hd5P`(y>U|-n$@3Mi zi{pqM6sQz}B4^e1FnS#$sU#zFwq(ea8X?^gO*i1I5z-w|9R+PR!q3P((5dlTw>l4t z2RW8DUsdE1#=Qvkzl{fSh!L5eq9T|6}LCz#xykS@WIW#$l^LbjLzn!Q{#+r0j!|yu1xFy+Wv++~W|h zrRw1LVw>dRv^cE3_vPGyh6si>s2R{6OqaMn8D!cDvfKcmTR_|8TFxQ0w=-B8aoeMvX?AVnNH64q!f!+;~Lz-P;%LC z7tLU1h0=9Z&O{s}ToW6XL^NVQj&RRq=&8s&eR|8SYBSq=uK;z627j&Yc!dsUr|y=d z$;c6|_Z;WZIlGemx0$)sheOMbD=UV;m+z)Z?g$libwN&N?RqGFu(-T37|gj6KC(kd z-qUrm=rkTBwo6K83c7Gzx}AroT1*N6ZPEm;rezp_ch!*y>l}N$Y;^J{E{CJ8;D5@^ zGvR3sH*R*H>hgJ{s4(s#@-;jA_8_YL^TV_!AbgB!Jt}f@;o|34V2m7VY7^8EoS0s9 zckmhn?7Plc-4ePu@aA59z^JW(!+Z7ZB_})51kVokHeA{2%NmcvX(AdBnO3toiH8E}f z*VWoIK0PTmwbR8R4Tc7|hljXgn;V^M+JEYQlA*yjRIgEx!~{PO`jwI?m*j0lK^Q!L zJ2(bZ*8p8ZxO80DafEyr@cN@iiV&N~{0@(2RwroeZA~p4UO%<9C8Z$K?W}b(arqG1 z-rhIg#D`^cL>KrSpNfm8zOD7?Fm|N-fD*-y!r+cVW2Ih`LMPPM6Y&38jC}8&F9-AU z>L$2oG<1w$I>!EMWpSwaq|T{TsH0U z4}0b1>)qCx5-$Q?NZBiGdVed3Z$5TFiC=RnlfG#bze@|mqxD<6tv6T@ z1c+ALz9K#ynD2hRQN@BI&|I#+dHjSlz4=NTPub=mSuWO2Lv!RJ2yp3 zMt%*s4Y$U1W#Mmkb^ZPBx;Ymt(T&|C!4G7P%jykje5+Y)bJf0LUQuE{fb-AqzSeZf zeUIv`MoyimiO^RKCV#F1#Q-H*7e;B0n5vX!Mv@Ed8yir@tB*)Cv+FGkw-?*FBxqOt z!c<<{*X$HfTJ)6XSF-I7(5jj}jan8uY+3>Y{xheG-90q^GX&_5 zr)R9ePxyB~P46u?z4&ESNH2FgKWujpSO2qVE6LpaocmG$MQmK$=i;lsIjqfW!!FW@7%}O*lFD5nwrPqajj;cZg?!mOqyc)kT**` zhaPx7zlx@1FdT4H!{NT5kLZ$qJkC-Q-gzzm$k&%9Tgn3{6?`OD!t zNm|cjW5h9|9hby`)!86+NGpkPt6J9^XJ7y#;mIr?Mq*n`*S!6^N9X-GYU&F*DMl5A zg&%AMZR-|Y*XM?-ToPxiQw~9G84_(756!CzA%uK_{M_Qa4J$3@p{@rKsie`+qvgG~ zEFtTo%U<{RJ>i{- z2u;AVU-q0R4DgXF?L|#_)BPjv;z?2#F=*_?eICDG>&>E=6VWu`X5#_Zu~HddH6U*w zZ#%yOuH8sh%n;JmpfDOkBd61y ze0glaNyB>Jf7+{Y&rwp*Hq~Aq-R>M2Q34rOGU$85v9+-H2q6Y}EG$u{YiFGTlI;g1rpI!jxvEDYpp&zqLP@At1 zcAw$OPFGacS8r|`C{7ei!-#FuggyfQI+}wAelv`N|f(3z?`9{8V>?0C)ZqqMcKoCYmM5(}L_DOy6CEDEW zgxaM|t^WL1#?4{8!u*XLD_n=TxP?U}1@p1yeWkwQ61g!@;{s|tx3WAY(l%Y=&tG@N zMsFDpk7S?M4P)2UbRNO%NaLERbIV)cd!m_kB8^@9YgYD`l#~SET|`7gde{G;H#Ui(P2&5D-{Hzu zR#soXCD@81e93&qQx`W>^0&%_);ABqGX|crEAcAsdSwc{#GT~v9y}Unx4=G$p8#qBw@>RS+0=?yYsXytw7x60t3y;Wpxc`S$)kB< z=PowYRMP~@sF2`yn9p``KzyKQDF2%jmyaTj?Es~NB5SOTKv2Wjj^&I5#T`soR7;V7 zUmH{glGfu+(#D%Nop+xHj`jni`z|z$8?bpM87qe-yJxYt09u~2=8?XiWX-xZT{0wN zi15Yyl=blr#)QWb=$73LeZRMl7#qSEQQqq|dL4CCfgvH1L16XH@$n3?$BH&_CqzCFN=NO+*GQP_S8pyZcXT2R{Zmi< zRebXh%LnwD?h)2D5u7uuW0*>KTQ1SOhuA!po&Oi8<5q=n?8No z$!2L~*1WZd{Wg(Gx9gBhG6a3!TNTS9OcvFKo%g%5b)iSM$_7VVSh$hZYul;knp?+r zcW&TnAx{66i0k_{+wWAOUn6Q2+>BXt@7pj(O4;gk?eRjazin?Ipt! zCA#r863rXG2x_+Kh#!-_dH>LSXHS}VH5=rhVbR$de&PpBT%WuIv7g9r!B~9r z#BCM&^govQWi+8>`1AGoTMO0hgG=?BC!}CRs~If7FByOYQ~Ik7hpYsODOT<>J|3qh zEp)$XIkjMZ^+jgb4HQQK!C>)^?9@Fy=~Em0JUl#54QU#4cuW$ktGu~hS!CU_5`9fn zquk^Ij0hqatZ7{|ULODm0~OKvw+6{U8%n z0Mx92oraRJG_FJq3TigdZSlL1fCKb8{YxziXe7K&9>6anO@(YA&<@thLbo4AXF9bu z6|k8Nct00|7Nqrjja-JRDFeXIIT=-xe9eAQ5qF~=4!eHuTkP_2oE3fpCAMGEJTGUb z_q$J*VRse)HkJzggj43Ruj_UtFsctg4F-i|K)u^y()Pe<{ zGc32tqA=@qpwgXw)RR8DIG?&X`7oMK|465|xDnWG2<)a-PH#tcI?h2hMt|ue;me+H zS^*d=D~+?Rt!;9OBq;$rJ*cNm$Abmiu)Zzp@Tg`8Fr>t)HV!;Djhp=Rc-LmYHJPEw zTjqPiSgnBoGuniwU>ntyGroXh>slpHY^q<3Ka$V(uFTncO9T?rXiLL(TMQ7){l-EV zD>9xMzckAT%#=gh+2M6GRlu`0+5zth!iGXRPQsxy;`g<^&f!3>m8)07EfvnV>V-To78n+}di9#Alas5Y zmQoViD`Rz@T|DrCT3QzoH_6X9^Jyq;?uXn!td2k^X2IyVA4|J5fhW*39rYZ zY-6Ep&;ULwZ`^2Z-U{O}*hor20Ttd0K@Got(OWEAFoD2==NhTRGDkGKEn-xUnK#Nq zy^7OwG*LnPn7=4Pc9Zyg9;Ztp3?@vvnLVom&N?e6{x zn*G2U8)amGdj#9g$pLVrOF%>j@zYsxl(68GJ0I2U!c(_dSO95`JBh>ss(@<1r8{0? zNqzg+ZbL6IaLbno&Oo~%0U>ec-(GhaV*zgA)*qAfIOrG-7`7m9x+$i<>%GMn?K-({mgm6GWU1nF-n`R@pXMiE)L?W9ewi0-M)7KLF?np!CrlF!5Ku9Cx{`xUj zOIiqZJM}t(up%FfZtrV$|EbR?cI_7xEj8?9ygBADCjAmXjG~)cXXijOH2gZY8V^?- z<6OBi@lC5NqIa-JXn7_NiYmmNkM)81754X+UKpxDg~SU0PrSPC-CNxDcZ1L8@DPyW zRPi-Y2aFGw;K&~XZ=;vR#RA}B81hJ7*5N2g?z3%zTpDQz0AFA$??k7IF@WU};BZ$?+$zq19;##+9tt0hyvOYMB+O&i+G8CorjHOVhxsok8G(31X zWopW%U%Zju{HLb}19|4^+^`RPV1`6Rimir1Hk_g->sJj0sfcIBFD+aX^QJ68H+l^pvI4`O&?%72Ow~BC>d>QY zj}<-M^1(Y7)G}=rHZ-vX@Vtq$W?c_DDspy&poj-&e>#m(F+r>qNKKD}R;Jyxkz?`g zN?5uV9IWStlZZBjoDisTC|f|gG=qWyo2}&-_}Z~^FhoY@d$4V3XT?(ZLE}78ZXi(h{#U)inTW%;SZys*GO}>Y6cBpllg_r)Dcs=?xI{!; zW$4H?quXYBDWRVPg^~5}=wp!Hdhz1!7M)OwJTxf+ZPoItsFjP`y;*e06v!kMHI)@N zefQ^3zPmZb<+rmsB54kl@1kI8yTSTwQ8yzk#>0l=`2IL5iPbks34*lxhe3W&?~9L! zAdy&$uc`ANIUx6uZm3*7+P4HJV6miqt~rzrJL0?Ica@473;mcs7{Ycj$8&y88#~;- zn^nt5RKpgMc>**=KL1o`#gfr}adu@XmSKxl;!?%V#PI=&gK|fhh5~iK zk*LTk!Cgn^vlgZa*;dIyWx&Y((8vv%P>0dcyGJuuP?agh7~l!EoKfaZo`LM~_LFXs zdyxM@8i`rSs5#{G+pam9Hh1zRyiS8pzSq-UA}+Knva+w4=Pe8zWBdLs?`npI`B`D_ z;^=8JAS-sixD7U-4#FhO9UNW<)g0;`bpliNwg>uI>P9=baQ&tKcK^K;msO6c3G{L9 zS@1p{4se<5<<=Xnh=JUC_^^7LqS#zpZA?1aJjo|izkK_e`d?nJBWZuuK3nwO>^*mN ztD}ZUc~y7w0?qr)O;AcWta+-Z^)pnvc)fz|kXftW&=-k z+z0TQ27mZ8@w-d(7VFOFwtXqKz$}YWQU(Z6=k__jyQpKYm>zlO`t#1I@jwOYzUpUL zzQ6w=%w9vS>5jg12w^bvSxoFwxD^=fI@Kq4Q16xJ3{2gm3L$4Cj8BM5srW!zpn3x!nz2(xt}VONW>G%2CfFqe`SsXN30wWYYMf? z>D9&2kY7BZ3PTEWyE$yHQE^FTkd@qO4l6KSHxu}#9R~AtolS%v(^>(yPXYN1QIoSz z*3);qFv}FG!!MF=gwjeXn#!D|4U5OZP!6?y@2lo{_E*L01P$)G;1nkn2GgWNCyeR-gS7c(HGkmET*xGZP#CfT8WD4Q6c}Y zE~5bfAa?7LZ$MAd_VJt-Gb?MuGqvC#|DZ4~0g3iEk?HLj8#TSo&`Qk1&mYh;Up83; z881})!9f#zaT48pWGq=izr$SlUKMFG0J75Y7FuRpW^XdXk6H9GXt8R;yV+ zyS4i^+>E?I%L(r-F;X#H%m!|a>z(_UHg2)FX!0b`4batvEi#2h-JQc1WkoX<3OPj4}Oi6&PX5@ejg+%2S0rH0bcn$6!m#x>0>Ls9ZUuU z;LVVT)0$yvWo@NVX5{*^W(pnsyQc>R;1>oUPE!kB3c1HYS=bizrq5<8!d6x<3@!*@ z8BCtNEXq=!Sohp5k)<62V(Nv#`=4uTS)SMWeyN=bd-o1TlUCfT+^0QN;?o{7#y1w* z>TqDsW-ZtbH0AsCyE32zTc@0%FKuga1oPtuy#gWO52MD~1(WB^+S*sCXm6DmV+80Az?7M?b6IFRNNns?7!_)bM|#;{R#KyzPvMDkRR=aVxVqXGh(wv+DN?KRQ1h3d5d*0Wk&!_I0)AD7tgLM7loRl{dR;jE`D_3@(k#iha)J8Kn6-p% zGC1rB>swmM2Ct#F`ue3&xQSqvZ=Kx6Dnr7QU_|k*7&#OVlLQ5TG^iasliZM+y2tR3 z;2Bigoh;7hBt|pHmwF7SMf35mcKPkdO6=ECcsOp;!Yu9V{4y3SVr0LL*!@|~Vr?T7 z0;Q6#3)&C-1pf7S1#?^2i z7`1#n+*4|~TCL|s{3P}F)BVOrlcni7pAgPMLTu16{2MIzz)f8$KCN}wXMcB3kalvY z=73{qKT3aksbcB#7mo`gheyQjj@wIFzSm-5gdlM`7v>OmW6sfyHx7Bt%r2TjV2Moc z-}#*ywmKn8$AH2VY^KGxdwC1Q+)7l$sAe+G%q>mB&+Z&h)cjCNawmaS&0NSoYi(+K zdn9WqY7SI^GimUtIY19?v(`w-uagj66NVxC{i-Zq?=tTs^{pkC4_DSx`x!Bvwl4K6 zdYTbZ7r4>B!>{6phK7(q1{D@0f%Jl|TY3F`Dkw@oHSCG@dgq%fva-#+exnA-Rwe1_ zF`Pb&)Dj{{~f1DMJ^6u)&Vm9H&iGH|N!V%hU7kSw7|70PGv{VP$~sNWrycg9n;=kxK5t zyjxAssZt%q`mys->b=9`y33U@KKt7Ra6uC5eHcS6MuXAS(mu~lg`LAw@Fpkh-H`jO zbHvxC?IqW1E(A$KfdhJgncpf@_5xRxsXrssqrnk(qo@N$9-Ei zt-{xEWz*~W2PDujHb73B8$&qX4KbXDLqI{Dp2lqRC)q;juG!w+{%$bN<>X7tqP|SoT^n?)n+UreD5L*(|>G|mxDrXt^g zX`Al;`J$dpCJT(xNS*(OAMzGTlL#DeX zh}tCp_Gm4iN2=~RLmp*&fmX;j{fg+E9FDD}5scr_#Ie+7ij0j$P3TFnZ=f2=iC;5v zrh&#C1u~cT>vh}&&%4iW6erqpY^(G(EBln2@BFP-4P(Je+grBU7tZ-Z+Z<5O1@O0^#v4@tUu=R|?VK!3Gof2v8=uXgJ({t>n9RU;ahKd^PQ- z(kJCHfLK7X;5BeTbHsFR+mBD+y>6uU7oV*SF^HF4ED(al$TLX4qG7KFJ zy`WkvA5-jr?iDa2xqxUBv&0R#0$rD88ICp;_B}W=`-mLPb0J9TLrfIt|8jZ`!q^#% z!9`OGc6#hVwvM~wtw+w8(>&%dy1okuP?d$`jKTE>(uYQnhm%cBVFQ#UP{g@CXm&w+ zXl=Pn6oAuP=y(hGSuS6w(?fO)^+^VXJSo5FYXc<(g{cbM(n zD#MBUVs^whzy~)5&tH(OhYS$LnGr%1ni;4C?CAAKn%D7|;wvek=qH@`O{eVTc(pGC zzSxhH&G~iM&BxF)J*^NAbcPJDDPkN{A^9GijGmret=RPdRM5-2(0TV|^@+eYec4KS zwNhF!Jz~>Up#i({H(;IhLLBfm01)Kl!qKdt&Y_Yw^@4*0Tc zqFDPjC#!fm#+9B5sc}H#xz4G(-DoFhEOdj%vw=6v4Js$fFIAn1#(Io$>%>bj`6Dd#>zI2|n zUE1s61#_6X+Vy73$!frE13?8X112Dk z1V`hd<5TGK7l^zOgA_$fQ>?0G<0bDS5J z=d|ktif1%nr5*rXEu%?U9F13Gqg^w(VdZ;{oIho`le@O+4lw&H@Wox4yEgfW!F z#6{@1d-`-;RreSkl9I$OseCls4H}|}kNeXD2R{a(=$zj9reTcvU<5eYBS}9m-_VfV zGRgL8pDpj}xrf^cg5BzQ*Fj`{xDr{(1AU_~xYEq|*D>R?7SbJb;N?}UFHh{ZFG?Tr z5R#-U_3VU0yu0*H?L2@nmk&pep;ZZvaY>bFx?=u6DaS#*aw`g2GkU;W65F}>#Rtq9 zW?jZavedUWEvnBxVu?zDzNobHbk5#>6W_7}vSRUnpTw@miBNlvHM}iQU)0W-i#;E5r-QB3>ittw}~o&}|2ou1HZlI>3cPyl7~6Wp4mhK`c5^6zK* z{0mMZ+%!aBX|~rAO`JWtb9Ga%u>4akw`YM4!AXjV#$Qw8yngFFaITSBiR}n~^68!LLPEnIVTu>Nv&UD)GR0tw zH5p&r!O3lI=-m+l7XVlaAU*UrK*X?Nls00#%S>}KvMoaK3yf?4zX>c8M@jGS7CKPUp^*?9M(MgG$ZaP#Kc-s})`jLt@hwSk%0urIhMC4ws$X{+5q-?pJ>6{ z#pT@}_k_%!a$rB^o?g&J1Vaj!Id3cDu>Wg9uZI;tB%bY30~ZWr@bU4%ysS{yu%fn? zD9jL$%A`_wBjqQcU11e~A*G44uu+~7f;lr(;_B*>rEnHqE1(I`Y&}gOpqm~L^E;(S z1~{U2WdROc4>(ZfHZ}?ANxsm=fbi*D)DpzN%nJ$KgWwDaeMW}fD_czQrP-y~@aX2(uFNIL5NFXYg2I005?Y zBqWGxVW$a>zqB;KeWdU|{rEq(CpYGwi};>m@!^q(Gz|Ly{{w%A5?|#M8`_95+yJJ< zwnCBdY&i0jmN2h#gm?NXSF+Klagdi## z5)cqYw40pQof4n~{Jy)7p45x$nLhvAmT*Bim_d8pqFM}mrOm=cHA3J3pip3;QTg#P*Q*BD ztaSmmz$aybfdS`-ywUR)KxWbqDbujR>k{-{N4rjwNQdtYPfaS7te7<&FFS=*RIJo;U@p)~D%%sVZ7x>YiN5 zWo)1!2r+kc1-p#@W3`i+&KAg=!M|T7H~x>!`~Q6R|3%mT|M?d=2w%V*ZT#}&HX|b= z-=&LeF=)fMv?d7r@HI*C?&LwrLp91wBtr{xu1_y1uo;p9E<{eSk+POj*m*ZlwG9bv3O zvbmo&uuhRu0+%LnA6B`(DmhX=|AX)Tzvl$v8gDAj9#+PcO6&M4<9!_5w{oMCR}7|W z+Z$RgT*pgdBh_>m=e$nsZ$c@z|Kk4n;yVp(RPz5KC8(1#0*}8OF=Rl+C5|6dbJ}0r zfbwzi>xEd?gt40mW6Y02!<)kv-NuN_Mt@9jUG;Cp|0<5x-uBq(;t#62sZ(KeVs}Gw z|FLBFKO5!Qj-CqCw->|L-~D*r@OXfr_-s0nvr(&+T(j)g1v`I+tl5-n)@C23pSBf* zh2U-~TIinblD*-BqqoD&m-9Tz-oI$u()(mm1G()cboh`P%JSudO8(C$eeS96&=<3G?W7e1acS`^ggS#_la+V_XSo$nxV#Fu3Y>fnL^Ns8 zD&O|!qD%aj5W>ZjTGpnbQWe#Hxt}Ua`?OcXuMQlnK2eR3%SShT_}O-t7%3Zmb$Q5b z0w$?we3qNsxr8&jw_hx6A~9EP=?$hZaH!dm z3}8C)ZPN?03;7zOFg)91Uw_H|&o{VqrcPb+!JV4857E0DVfly4tCl+a8Fo*Z@ElcZ z1bnm{$oQ!R9>q2a>3YO*`_uLt$2XDZ@QUTQ<@VJI1jgzaKTC_6y&-Y9$RliPE<#$|lvkyJTg9-Gf)(#7cdRbOBOj%@S8hv`WUu54F zjb}|tD%Cfg&YbdW<26n%J>X-HcNynl+PgZV*;r7D3OgdL*-dgFdU^f)|M;_$iGN{6 z-9L&+gs;`{FSK}HIauhapO)1`(N*PzM4hq z^j??2s*+}$spws|lJ<=xHB~a)uYC>W^ek2t@lW>m@%k$mwkj;<)RvcvwB`y&e09={ z|K7>C@q0K+xci%Zm7Lel_PY&g!gu#^w5jEa;)-&7)mW@DDy>plP)EkyoXWQYok{-p z9o5(3c{Qp!`ZKKHcgV}HY)!8e*clzW3-&fRU6GJTkdTm?z7IAV-hr~{!(zkXI>YVi6EhV1^uzy=6!Ux ztcJ&j=HL8bLRmfpkMah7+FkVTNv+{8pP?Onas0vtExxdUx6doKx}3rJWI5$XK(Qw2 z-cBk0e+?~HX3TG6`%m{x3c4<#XOCK6yuxi8w|FglsU(D)h-Z$$HGU$Fg|HPb4rYPf z>??*}AH8X|xKH+MuI<4On!mRN=kW7N)0{&0PT}?}=4{C4U|KkQKUCY7HJ@T}{Qh&V zKGAwOckYTuen9D9N1xvh@D!1IZI=J}kG?-{O5n|co{y54!KZw4)iWW1 zx&6s*eI74&WvmAH7W0n?s0ZjXZQOc?G-JM{nFO;hRE282l#3ecp%wV^8n5qw?t6)1 zc5IrU^T99mjL7}J+oi7IvCXN}mr5+Y@6(`BhI=(n<_xUG`|Z92R4|lAPxQF_qILU>+dXHkvO?z(=d4m_n(Ob z&rz~6g8$yS>pOE7`9CdZoDQX?c=~&>+*jvr&@~Tr9c96vW)*W!x}w5aw_N*glT((F zFyJklIjDHC*?AvP-Riwn(zts0Pgaku8fy*_o#`Ha<06G?eBD~T-`JIrJ(ky)o7#Sq zo3L4GvY$++!BJk$?AxeNbmw#>*ZyLs)d$lm@28SNpz#F{hbRg8}Dt;YKBTqim~A$LX*Ob?ykY-b2d zXUzl05dWpGVTt0OJAY5yve=#9IQsL@iAzLZu*RN^$lq$@9cyPZS$v75uvmJ{I+zLt>fJ z{qYtCf$}e|+KIwqh69Z+=hfSVR27B~&nW8V|M{vZ>{Rcg-rhMx=M!-F(*v)`CAy$L zXI!X2enCC%o#@2Jd82$GXJY@S4bEb_)H=ID7~|(fPU($VXVb$_f`$G67kO{}7uB~n z?AwYUDBY-Zcb7q@ba%IOgNo!3(vlx1PXhvx)}+(vg)8sb;4Kw=SiDHe=S!PjhDAjIgf2RoiO)zzakgrk z$3K%)vZ$Yj*n%)OCU0euqFj(7qB05o{#Sw$!wH+KeMyhv zjgm!d(T+L9ZfNR#RH7&b1#49Cp!I z#MzlT)AGr^?WF2&jQ8q<)H8U8`U_`I=;x#>>r{?iCC?4qG^qEy_Gb+ja@#gwx}`dG z-l80@x0roBMs&Kbj?u+T?w(RO;_=IwoVGxcVLX3%g}Vo>LdhoGPkDeXkB-rvWWZa3 zDl$!X<%$~LSIKE-4c*$jyR%)X$dz~E!78oLZO+hyHOItU(3VI1va(~tBEQ}2>Q)KM zEq*(n*3(Q=Vr5|iM0C7UB{WKA)ZF^>AuakDCCq|EON|oh8EUOI+Tl0vswK<>bN2T? zEq zCylR9)=03vFH7jB)SQz&CeSRqv{0qiNKPwYCY0+!?{7NqsShvbJd6toKdp#yIgN|v zlS9gu6$?3_lxfS>nMID*DBH_*&ULn(FYWY|o)QpK{i26hd&fu)xtb;}JI#@`+t^X^ z1rlwf>fiKnJO9FNce`S@CN5R_WfVDUx;0De&dz94J?1i(Ro5|-V{K!T%dN@5J=-~` zU|1ctKFsC_4KMzBiAitYK1$`smRST+~6k%g$!zZTrEp zB!A3##ta_vBB?G#1aJ;bO3lLEc8mMqOS4Cw$C};r$u;ucTyn7&pP^%$J(>8*< zSel-Mgqv(I2pV*dW;dT%R$BQ?A~U!-sx?#28|ptWpAyXt z^gJnKV!f1HE71@*#O>+`&n}X#iTu*^_lWt}Jm%c;1cyRwz6W~y{Mzc|MS)IFaN}-Z zTVVe$vC6h9_tYyBO!+ zR00U$-IVC#W7+*d7}~FTn&U255WGjSuDQ`(czO6bD2@C$9Iu284|)e?3|dus32zV) z`GDi~v>wwc0;ZbDDem~BNAs9O^H|4~r;*Z9ZNek86DfcCm6g!>(0@BL#hAX&2k+dM zC~pSR)g^r^)2Ke2iy^_l%zo1Fa0FKv*-&*TPQmtcD{LDx9;&=g5c_xiMZZx0RGb)j ziLSiVjKn+cEoI0kRDY9P;55l{0E)Y>i`}!!CfK5dWHPd&NbxeO#qJ^vh=^vMsTf>Ck1f!?_|aEO8`crDHg`V4?J(k=D~kHb zR_^G=_t#ZJ#|JrYXCANO{~p|*?glrU+9_tuIoT})b%P|k@i%37So&1IHGk@GiG1_2 zo0PKAxwNP44KE4Y>Ir7E>V-z?0Bm`cxeP5XvMf)tIY{|c|c<@@0t zzb#+jZi-2c@C|vW+z+PDo3!ilH>lnzW+%MA-Gz=@wQGO(@?bF-JU(xoxozF?HCg4E zKa1#cZF2i^c^gpxPMAr@brE)apN@M+tV|qSx z-ICE*~| zLIIcf7xn4TbJpv&!X@q5JgkV%Z{^qdvOfo`T46J@`AqMr`6TBQe|C<n?@(fD$I;|a-=C~T-NILB?t?DCIBz+BgL(|$2TQwXvL zAscBf!%T@tC~zUMcy(V#iwBRcP21B_v*agX{804+z*m z7tYlPE>**uc@r6ZlE@L_quU=XtG$LY2%XoKg$MpT_6SHY%IWr^!6W(4pe&IBHOoLR zq+HJ^TV``2vlMD*-uve)TLf+|7;&TXoM`C7=U7lpCR@B2|78)cJguWe#(NGK#&SM` zVRN1Aa2BW;PNdbwPEt$y5X*0lXSxi&ip4gEDoL=IhE7H}F4>fLnQx^xt%$IH3R{Hq zt&n7%PrHq5nopnI*bH!s`;uK?rDUP|pOOan{BXn&Et{Bj&ipJ_Toj0Sk$PhfN#Zx` zI3Zki7A|C*qjLR`xoS~PrkV(?;7Q^T;HRA=%NPvUE|eFmOb(=yLK3ds6L+7VA5XATFy|A14#-np$LK419vq_V4H-a`?wvJgUVcVv+&05W>?xL+%kn(|gnSOkt!zj~}{%FA~B%MJb;!u?M5I(?Yn z<9ZlF#NSL(edAE>#=vXWRYG2)OO&o&E`A$^a25`W+R@B7QuuB5?cCr+sq!IeuWvF$ zOVwePu2%3NEIRpy)*orqag{WIq&Cjkg;V$S5UQufba9IZUomIJT5_|?55r}Ok8O#V z6m&zE#)Q*l1A7^b$nn~}Het`B6zdNB8j#x?`04J``pZIHYfY^rLgBT!$z6j2VS$|I zP!1OlksafLjwPc)pTrhaTvs7_F6bzy@AtVht@_F)8S<8ODJ`~kHZ5$}qO}d?aL9r@yhNm&7Aj>VO zdaj`!5#_mi{;I&CDLqj>NG)+hZ!9X=m_&b>yMLZEGxPlv>p@M0S?Sy?%L;4O)1MAh1*8xwy8TG2^s4@rij+!{ z$v9Bk5{<>>a{2Knx~OE0plnIvh+wI2D|ii)pHOTBFOq16V+?Did2wob+4}0X7KfOI zh3SmDrayAJ)iS9@exOpVRFdej#mgjiUnJ~$tHr-CNq$r*i++~pqHv*_fHY#`red)Z zZ0)AbFo=|ZaAORg{yK|v70+Tk8=p+2=FDoU%`6{jTY)LiCK91+XtGUJeTvkciQOPD zSuhA_el=7SwE^G|q!Cr}%A;Ek^EYA1Zh_-13Q{Q?@osCvxn21kFl89Adv)&tZGv3r z?JFyOLLw_VSvV(GNCn&$ZG!obGXluE6enl%gdBs5dUqC8F`Y@ojVG@|Tw3mq=;GSr2WrS4MHZC~GrDid;jXHt zD@2)r`)Xu`(L&mvSk5fQ8VL?}3$*L;8Dj{gA$tP5bn)n;M3qTW znEr8RD*3wb8+3Bi8Vtq~C;f5Jg2%d5`ZB95gub-((=s|8tUadI+(mqd!B*Fa&#_w+ zV8iDtMkeknmf&95_?|~|Owegg)~i4-WCn#MK0l72>%0hdbrL6f4bnCJiVRh>SkGl; z12`mk{Y&c03~;f;w6O)RZ<|f6h-z;GopvmnU%}Q>8@oi3~`oEgh@+MAs9gWi$ zp6bxf>PG@U`B}F)gOd(@>U)?KIOiUkK(>lyuJOZKk9855`(30Ui7whHmw&4~CzN2^ z-jn}OU0HRNnbgQTx~#f1?v3}zYQ>rT+AX6Tfri@;to^06vcb`ok7NsF!k==jX;uz5 zBO+}LR#?UxL8mWa69q0%RNp9ld!S=DQ`f)1$&@lCeDX5GF6`=AUdBpu*pP3golnfJ zQfOnuP%54oLWrZqS0hSin$`Z~L&bz~8grsKlG0g{fNL?@d?LANV=Kp}1A%oeZBtlY z_NNW8W>%cf%|$}i9?L$i#m|5q(X9S0qrue;fi_WL&E(TpI~16KvhR8{A#7&QhU^IH zncHaNpC=dQ!KF+ImbyAQIV$rt&5gf0`_@5?`~h!_Ri=LOdF&hOi$>kTorYkGL6{ul zNbyx&wU~3+uKz&He_E+-v7mG7X>yj>ca&Uv_&%rjm7P&D^YUduPS{y*&v`#G*7Xf( z0ly%!a8yiQnNI&kV_Ev6;ih*7bal%j+_~YXOj18NjgwHNp#`tx_hD8=h5ZhP@6Ghp z^YhJ3A9^*>RVx^`U5$uC)Zs`WQ|Yz%3F8s9lC?|uSpNnkl~%gw;GRRouNow;67*WP zllXOj2>-wD1&E%UGO-CxqjEfUJcIXy^Mz?_<1*AJOcQjwjaN>-PgwcYVn3rkf1nRd zFrz&;SFtAyE|~8bdAQ^3u)>BaZXUDYkvJ6;8&10YkeQ+VqCGZ5;MTfgV)~2^+?7`G zp7w=_$Qvun#+?y4X-UyCL|n7zNEkm(PKv{O%S!)7g*}eTt0Up{quZWSl&g~I;@I9^ zJ+OfGhE*@JI%4To6mFCjFnr(K`kChkec#mHs^^{ku z6-?m8CT;La4d_^gp@l`Mn?<5BZB%WwQ{qIFdVVc{Iv8GPQFh3)d&Jk+I_1fNqz_q` zHhNt#*JMDBt7Ep?BQ*;t=C#p28#l0cuUx*)(F!@~CqbWMHn0h<&BN<(g!~*?&Y?6b z*5oy>BqehF0~0&3Xc*L$f)7Pck=~r)O?RzkY@1zSIB%&2H8SS!BHD!n>$+TwGwh@K z8c!~j0}hpXvuy0_lAK#uIa%q`DUKySHbS;eFOys}bGZ6WST&>14C8yf*7k{r@y*;J zv6vXm|F=@RwqaCGCas1cZa-TWi@Ah;g`W~blV)A_t6ZBgd8QXrUxy^5g!Ugwq!sVhctheSc*E3jDih@Bu)ig2f z(Rxla~9eG%7vBRhG z*~lo3RNMlx+_CB+o#xyk&1h9KgXlj&GG2Pp_NOKtG?I=jn$D6QImN5L-gQX9~057$*`(1n<4 zG`A6Mma8j?rK!hR%GEfx3KsqtP%M#-$$y?#c!BCl@|M4xZY(+c)JCkFLT}CUBOeiE zL_A>3QW{f)Xe6Q=4=PG#Fia_I(* zKVR3DzFp`>`z=+?F8Ta_Vw>Bu7Qx{ma%exkZsN!W!CRj?Hca#$#@s1?&9wXMKS}6AJ&sT$04=;iI%&N(~MWLvBj}@ zV|q9Fx2W=X7QH_sUeM*g(#wQPM+daq#Nle>YxT7ku3{EuG8TqUNg9uORP`2x({rlD zYSFE!c8=9mOYD>@b~+c|=Jz_1u{H3}R5ldR82B9UAjk#}oyi8T$HmhL3a4!nT@?fR zW=Fqrl)Y~x(V7~$-jenkLeuy}$<^5rs_5RQ&3t-_))lJh+A(9PT1$x)JEPt=9IYS` zgJ#{(`^bs!el7Nx7!FsSZawESqkmI#`z3_S z@-3~qlFk3HiW0(kZ{JU=3ESB>1|o6J>Q|O92!+n?2gAtpZ#XeYdII8~n7}*dDK$#(L=Qg~dG}(P8MbSkdHkXe`X$?4qkMMWbM+D5qfW?y_|Zemd5)=xeZ4 zR9)p*IxvhDTWl`SX_^6_u4&z7ZB?9E!|d5c8R9tQH(6KW2;krvDPIj}AziYfX&2$v zAsnwZWB|1WVUR>En_Ax=1z?Z%86N~)jIqv%=w>wzi!wca2I%Np7hQxXnini z>zBSCSQKfYFP2Dfb2rg#RvfrRkw@U>q&gY<#9R)wQZsEu!B>g#z-6y3uu{$Ct{vr3 zvu2x=wAbcg9EL;FS8dsanH_fLkJ<(njs;l$T*!8HF$#2AQI`gx^1P)>8gx=(pMA(d zVs@m*&*hywettx9JDL!TR}$mMZR4{SCq%p;IfOmgv~kF-Gw8jNx!07$m1MK_hc{gJ zwdd8iYPsjkIYmTjg{~E=^Ooegp|gE(ZpTrcBZFW*!cybni+r6gZh zb?S4vY2O(^ECjD@J2bmE;LZ4`6{_8IdT@w;p5lmLCRNg%aylBlR_7sRXO5937>^;b z-y4k%TrcRHeNJbG%_W=aF+3?fPtAIxX&W<5npV_SEALq*bQ+sP+PuJFrIs;8nX~8g zos_U-^#S}T4aSV->9s%Uc^?Z`U!`OEqg!X!l1qD-`>-01bN}&3XM12%%Z2bo8o#Z^ zfoR7kU1j)9hEvW)Do;belLqyIE7P2Q0Q;+}VkoMlDXyKaOzxpVUxy^8E{iE34;LkSDEgzyH@oi+pU%!E>2rbFsA; z@^EuYQS{@J%9rz=0rLpS5$_RASFOrDE~9Zp@sgi)si!zimw11x=4vm6k*rHNiCP-T zV(|`q24z-V3rAl@uQEHXmWwe$w-m>db$=Di-%us+q&#GiYFZ_2qar2o6qGlK{@Qsl zGQZHK<=#hRJ7r6TDsVlm?HO>Xp!85U@A!(_lD64@q$GmN%F^_6Oy_OribCDfeKuBD z%9MFb=zv{x5?^5&|4o*3* zKXq${(LK{#Ov~$d;z46>8IHuYuPZYrgnMQM9$I<``a}42H}m)9K%m*(TqI zN_EC#P9iqWWHT`oB<)}Qx)U#B6%abxYW8`m0uU(*{v# z>7=SAeoi*&;{Xqgkz=Ro`P6_}DwmY|b?CW83uhi<$3OR-N+&IR^rd|3bk?#hNA*Ul zHUfGKB8>D77ygoV>^W|{b`hxaNwl3WZbuD1lvPIGNOdqmzbQI9Kxt$PY~*)vo3#s( z%0e>|?@C;4Ep4j^f(pa~hGC zWr;rJa1^4@6*M7qjTg)0E#>9@-c-0i`wFWvj8)N0*P1!y7h})+$@g^Gab15+X43A- z5{11#gLTXDtN)nw3LSRE9Eh~kk4T~Hp5BS?3LjK{9jy=RolEs7N>A>x+OZQkwX`#4 zcBP*5j?b2%(Lm zwSiR`52PyR%hJtCUiV0-Qz=zAD^4p|?M%y?HGRWU`#9MYs%gQW*yTZfKP5Mko<1IO zWJs70+BjTpT_n5Ik@6*s`BUQfXMK59xtnqBTmYsaZ|3vC(-ho z_9W6rvpBLr`o+e>a+T*Xc)89sr(OkyP_#ai(fz?TA(!YaPukU{au3G#mLBa$n3NF| zfQ>1FPt-i#cSKTZDdcez$H0zU8+^)#7*qg6OZWhmv)AqTYeWr$6sEqJZk_GY@5mnPyjs6hggi__a8ZLK6 z4{zqYu4!3^?`06vD*j$Z#>MLdA?+`6oR;f1!fO~v)zJvyD{gIX^kAAg!TQ80Rq#`2 zy?3z+Q+&%VQOOo>e2sT9hsH!3qouX$mF|Vt%u3h1vx;ug9@-{zz*4^MF*Qh3QEQYwy5_=!!d3`O5rZO$w z4DD38x&jI!yhG27h%o?8P_1j}jbj-AQZu6;9y2t#%wyx?1wxf4So2s^m;Q5GHEC%c)b zZE_`d$P;3F*t%UjNS?@h^9`L4Ye>C!4mp#?TEWnz=`<`^TWg|_f$zfE*>$s5w}H43yk@t|4DhscTje zS=q1J2&bp^{zCPu`QV!5r3O80Er7TzeMHkWDiO7ChQ~k^HKsyU1^?@YjRh6j-Y-pN zq{CCgTcblNhmsXhd$X=vQ=F5}WqmsWVm_(E@*rZd>|4sM1}#l}5WjZSj|J}>Q! zAd6-6hBTSCNcWt!2oqc=j{6LY#iT2B2tH*f=_X&)+&2O(HZEvhNOht_mw{D*^oRjB2JZreA#%ThR}&potzk>C)l^6BLadqeS@9WOC-d@1f;B z(M*d;f9yw-0S2i+-R%0gc zkn~B@+WZEa`YJW1_o^+C_$M@T1ByGv@XMQ+YM zS;8cu=#z7ep3=GY)_oK*#{Wu|=&(St)V=UAYV2WG-aHlDqFO!PYVAOnRjy;*{e|NsT?M%LG$Rx~4Y-OY(}ErtaZWAy@DJOsQ%ZxQV3i3SGi| z3)JDSCtD3`Cgq;Y^}UZO5~fyAowB82vfZ?d=s9VYYsm9QJbn((B$PgK#B*D49zy0l zK+M0bz9~?2d1Yp$Yg(x!=%e0SeaU&U4{#$X7MsI$*?yE~@#+)Q(K(l=4rcQ`Lr-Zc zzyR#rUO7|mlNeJv+SS{fmK5R>mbE`^>w}1yrbDrOlSY*c9S5wYXdFLvFl7nKb~b6{ z>tavqjm6aWj$>PmfE}6_QxU`G=-EQS4}&dbeH`Vy+yh$rS{*-CM1!t8`;?TZ)M;*d zD{9xUz$SU9@LMxQOVf~ch;^K?YW!$5*62}alTP{R`^&SE96@`d=e88Hbdf#X>!xkp zSTRRK)>r&0jCt9Uc2NVklvdls*0U$ZQZl+tB5b6yt$*W#xNYqy7?~LD^;43gl9yispj-N; z|EtQYS-cLS9fDC@2#gJ{QllTHmF+wATdexbGOCFHcSB}G?e_ysJkA_CFYMt(u@C8cEo=DQ zXui`sLWKRZ+SB(%u0s{CDCgf!BYepBeVUC&Y=W=K$QC$n*%2cY^}G12SVY;-es1rQ zrjpx0g=-zFM2u9Y8SXK;+w0S;0>0Rc-B5G2n!L`&issm-LVw?>YGw2-Xxce7 z7=8_NbQ9hO3hsf1n@?sUl&`tW^Vnw2W0Om644`I}cu`O4_Ft~UZj+boG982cUmcNi zIKzG~@cYPZw_OLHiYpaG&(TR{D~O`@E*HG_AQrZl2j;9`3lZM!Qv% zPWjZ#*7-%$z$6xkJ|s$$atWUk4oBi38jcX>b%CzmGzkpRcsie@kf-xTE3;&1>(tM_ z#b*tf&zznUMG%Drcr+sa>~oXO-`F(@JKtlU@sf`xwC0rD_yZ^jJZ6laks6?5L*JU}$ zMvqcUOG^lOC@w1_V{Tyq_V|KL9Kj+V-bVhAp`ye@Idr@6pI<(_Ky99PBZjo=UYwtG za{C-a`PyAZoRT1M?Myq8E%^*t6sw zuGMYQtV1%bHC#y!!6Y7HG`8fpeU{zdyb&E|`67qv**8yX_WXAh+Cgjo`X2wpj)O{CaBE;zF}V|og0|2bXwm0SZ{Upe zt{OY9{olu|>{^7x?^a^;$mm6yw^@)VPu0Gzt!7Y>j-s6`F*g4pxvyk59y2>Ms=1~Z z-TUbS`KJFPCn?c6(p??&HR-LakRAQNvwl`S&(>O$Zws-N2;ys0!g_e@nPglZCFU8M zMwq(HPbKXC)O&hK;MQ@Kg_VisH`m9#w`RquF5WT9s7A2QDBg78^Bbubo z#j25EOjM~{{OrYZLHt4v{=)>r+v;r^j=2-8_HMn-Bx@DC>ypP}vF9*3-TL3$NGfl$ zR>`|haT;uAVk>RJxa)w3A%D11e;j^JrY5UAHuf>}zecYWxR0lqFjS7kF>3XF2NU7s z#w*Aw!SWG9iaXyGJ-7rGYqL)UH48Qp=_wgw>Cz`M95O-_#%d&)7>0iBa}VnfGNRT< z9Z9u~6CUoPKopG*GzGvBR(uhG$FCl>(3?L!#?L6Ci7nyNZGM|@CFEddq+W5RPcB0D zpQcz7uK%Nxg7-`VzlkQaGLDGKdsHxS90(@ax*mmzeB@P%DSjalG*V^io1-Elm;ZR$ zxIVW{aa<~8id`#eHNd(yWhSxrc3{rCv&(zz9O)~&&(6;eYgDtS9L`sdW9$;GDr@QB z(pSQK@aO^UkC(4s4(}l%&rnfb{(dR(SN1^}Eh{&LvfB6hG0*uq&y=}!Bx^yKiAH&7 zWfa=}`f^&Q6#uc!dh&kn$9>*oUUv6k$*1gcc%o~MaQ$$kyYE%qtJ<>qb*P%#r0V_V zZTwG^(vPRJKO_zR=GdExcdgk{tZSgSy!N}>+I07bgws48R0|oi`%)Ks@YnGj^~=XI zqYu8n#tB5?niD*Nym`WjKy!Bav{b!7BmXhCG>HfODzCHkl^6DM1|iQgjvo@ZBf`&j zW%WZI7(FpB2t0Frk4V{i_^K8y`5j{+;^E)b*U&)gssrkH`Wqlg`JcCB0B?yYPcm~X zAaMG4Et@P0nzNz*B0CDDut{zlsvc1`_3YA}=e||q*Gv0hZzW*6Y*Zc(~JPHq3fTAwwDxX3C$B0jkHr$VopY7 zd+v_C{crcn0|YYM$teS9cQRk=`L(dz|H-l{oyQis@cJ1Fi`)wSG12EW0XI{$(3r57 z5|2JV=r|%?UVFad%&k=6Bf9AJznhod_Po1)5}WJs(1lC?DGl#ECM;e!#~ZB&zFZG3 zKkTj<*O4i4eMxvL#VbRIkyrT23i}U^e(2=qPPFfI*9ZNNek(t6rVlQCvSsU6H9ZFQ zl>PH4w+6eKHiZuM@2RIFDyWI{OCO{0n)7w!^`lF%;nMY5+_Tw(k zZqE37=Z73RsMA7nFin+zc6hUBkrTnNt66w ze!Lgpx&Ng4F#~PQ_zNz6o(4q~(Rh6}GC9_s*UwaU?ZKKPGhxjISUI(u0Yv7u zmO#~}_@dI>&>;$n*a0Ax!H+kGWXLz1V`CQxQR#@lR-h7Fzi1=7MX{^fmMaE8+Gdix3n}+T$XIq z0Wt5!?zYkGSHGQE-!A|`uc?(-dmKJ}**ot`THV=qJ%6ox4|)CcUml(t#Jo2lr2Si$ zF`tnh;8d7F=UXDkJc8z$nzH7J!l-&p*<*25t!En&#&&lrinQ?g5et+a?+y1p(`@ zMt=#c0OJ2CNaStHsaCZv>#k|_dK!EWH?AbJi?+L0Gsdo2t17yqk?0l;CHLt@7 zzBj^KSxv=&gOC;f#Yz_zq*Ib2dc~nOYn>YC2|GINCrFf4RWZ>Xy@o!0xKhrWot@+E zb?u^Br2f7$krVJ8^bRUDid2D(55V^XPIq8n>u`QSKKP(*SSW^vJmL`~t>zr8TtadJ zq~y?n=9MOZI{?Vj+DrF)#Z#q=p`8HwA|6gcjv1z?q!c!?_!=9X9c=9vhy<*`rllrc zuM?U>H)2>FEix!(eL4_rPX+b4$ymMA@W^uGWabnHdpaj8ZL# z1>~pS3$G&(Cpp&Y)p6M!VgQhPDDn-sG?SUAftQL(&)213&4Cv%b^xv6*WYb`Dh}4P zj9VoHLw|F3fBiCrA51PSVE)CI6$5-5a~q2mYp&zp)lH(#&YWCH2$P2!P~;9^f_3~| zcWgk+dD7C-w&-)PaC3K#3zc{T|Wwy4+RE@zmCAt-b!{0 zgq4yZ55KBmzpK|~0{9DXlory&Neyf|EsGmXvC7m#^;zyPd!A=|t(KKhL7f1h<2mVF zr^7@?-+g%yDD>=70DuY91zHADy`sd)ZfSvnpPbB>h%oyp7i(ss~1!30n{D>R411d^1omKzV*zQjCc!W<{hXXVbRdnsrlpUCN z9Gn~ne~ltwj^}r}8rQ}{^i-cS4VT@yJ2J=Z#p*Tiwd040Y0FVVZ+GTXZlACuu<)k{ zT=ZSXBW_%GCtCq3lkEB+kbr=QGO0^ZS5@p+%}=lce<}D8+2z6h;e>oO*dd==>@mW7 z9y_q^?z1juTes-3=hjN3K3!(ISvIw032-}({WiN?M7HrsZ=o3Xnwx{FV(DuUr`3m9 zB{$@a-rioD^tXSTZb%95E6)#!NdJ?L`xU#@E#m0(Z{ohch-{WxD&2DXgmTA5#T@ zO$y{$vQPdAty4#43 ztHVtjiVHYpD%q{-(N!Lx&2JYDXepYI4CMeg7={RS92^=22w zJ2?=z3%>m2^Pwh79BTO#<2Tqq2=YmJWqC^WF04_1((Y9n5at+N=11Yx+y;^y3hMxq76a#5aCdJ>jQHtp3Xh2-mhiT>&7G?sLLX`dwbp|OO zOkO*FphYjlMFq>iWbGt`ORQwFB2rzT14~}8@1pGyI1Yd%!^$JjJH6i+2#Cm`V&sQz z$xy*dY=qxK>)JI!O@QI$H@Xu95fx8|v>O_n&o!Q4oHXYj3kVj&Cau##|MChnJ5oP< z=ocCu2CTtl{KSt!Ahl~-cg#XIfEah=cRlQd4S<@MB|*k(s|1<2)h#8U%Pbd|f_RD^ zB|}-JVIz_OO`F)y$;wKA&pKg&84e^DKx?l*9(pEuo7QkP?{4KFf={tgbZQ1kQix^H3UIT1z=Nmy8* zz-{I}fZvMS6Sst~x;}ydd^}#=;Q#Iyesq@zUF^~#a1a|BMuEYO_T=G<)6+YZMwLUm zA`}pQLC^(5+d$v^M`WY|NN)h!v3a1A6K=h95J{da;2h!?82&P%6Q6)2t)wKPey>i+ zj^m$nRSi%B;w1oy&dvBcc<~%^+!K)E>wc9S2%lZZC#0kRlgb?pn1=X|DGb>3Hp%c8 zE)KDX`5eAa*7Bm^mrh&X5&9=S0c8y@X#~+1V1EbPG>{ch|4T~Ef-eimiXe*vzEA*u zT3cI32_y&PAOHvf%po_tbD)Fh29RFhWVr`(bo?=3#H#f(N$*!CMNpSBZV@!8!&fW`15DR_>Cnc3_-wJ|g-!ia-#b8i;_r~$t54uZ7f0><;# zB}4E*d3=^AW(5UjoI7`cSNrHU0Q?T@Pe|I>yZ~wIyEhDdrZ9CpykhAbc9C=iK(5R! zETs6P9Xe*H;W5`k%gjt2DKk7a(i#${3aE%@Y8r&;m0A87;t{WcMSdnH8UjQUpceaF zwMARkd608?8i;|ncnKVInP7t(r zo~3H@x5qaiBLS*qkf^B(0GdmyDGcgLh7}!+hV}w*VPphwANm=v(hMkJG5|j_Fdejj z%mG;5GluT)OJW&cmy9vvdn9=<-=s)Ia!><&5-^E>QpD6I9sodk`)_~-&dMqH5m5cX zfoI_Wq%2l?EiGWC_-)SNu(0q3kfi~!F9W2C2?-itjlA?q^$Wy+x!&Gqz-0$$zwdtx zmJWG9^aP`yuA3fUP&KYf$#El$Dm7UXPz}y&Eg3qO?MXdWUafshI&>G18R&ia+@Cc` z)~&&xZ?<4+>KQ|vmitm(4saiU3~U69Lmo`3=zbtO2dUx$0Nv~WN;e=5vnBlb5ciRs z+--(*O0{Bmc=*BZ#df}PFxyQ-LcD-N8t|5RKOejVVO!)ay8A;^R8)TqlW*?;4~5Zo!olnr^y>^LtEQaiHbo0dwL#?>-SIjU;7pWCK2#` zVaJXlZ(mJKPXU?_UWE=-is`^yBj7(Bq|GB4fl>X?y%AJFO^3g$C8)5#7((u0kpc08 z!^s3|(^ci|M;3hjkuf!xeOaoFkzv9VK3GxB79(TNwu<{4}^ zV0*w*aGP)Z^KNzlV1|MUVrQl?aNTup#p?FR4y=$|#4h}C@d=M-!3}5~r`y3|Z*RtO zZsVLuND6hws+@}Ofbx$#Qig?Fc%Y==vi23=I;-v0f!zch#txft7?B0F9)o|dFov(fD*y+4XU__Ja)p*w zcWY}Psds1&)F%$GZ$XuEl=75}0{i*M@I>1S=6oDvQuAR`R>B4_Tu?q(W ztulI{T5yW<_)c^UiW>ly5|_7QuGLNrxVkzHk5>V%v=Sg(*`~yQ_8Ev$K_1ovN3PDR z*PAkuSWN-nAE!&8UtS*VjtjrYyAab9q_?CI^XClFvq2X$V; zgfGbfW@i}->t=%*12C1Z2wj^F(S4Q$_gieMqx(#O=X{X}`0DKd447kdOhH>aw9m9v zpXG-X6#(ci?w-$m1XGSGIugU{;3E)9D`27>HR<_c?0a=i|I|}o7>vyD+9YfGHoco& zTlNaNKeJ2;@WKLej=%;B%2cTb@6UFoJMR+d$pPO;VZ;iVV#DTEJBH}6e_i+TveyoI zvpmqK|6KLH)y>G$JJzO~K))Jt(`sk39x%+>wf5anO{0SW<Pm&1HjsxzC}}9jSvkVy%>U`Y6u*1^i#ZY`=1Yen25Z)@ z4?;}yY$r-n?_xbjW(--A0GCciR^D-CLII?+PxiczlMZWU!3ZPV+OBn<4s$v`QPfd+ z3`w&F`XgZSgiVHmcmmebz}A*|pEE}W1_m&skAY4X*3f>dMR;`+Mj`}{sgL7f{m`}t|@Yy{-i!jvNJj^ z{P+`1cXVGmZl=(^E^^CJUl56%~-C3fOY*dk)m|dYs@J zWi0PZH3kyl?L&^r9p(_luH^=^eBeK1<29gz+8i)@KPV{~rM>tHqGPmV4lN_2$u>ys zcU(eld_Wbich#+?p{}m)V7b+Bp95siHr7)$kvI^Dj&8LHD(9HW&7Sz}7my|b8(eM? zEkjeSsWX3dBx-#_?zAV|--qp#qJXU-OGOWVF z0CJZFWK${iu8s?XZ+^Wz18g@o(BWdh)tV9qx)&dxuPuuPxVX3yRM9|a3eti+r$ptg z8OR?Kn8w=rI*NFD=CFm!{%p@;hWPy;>Lo~LQd(WzmPrXEsXX9&wvUc-I36EoDoTRJ z7wUSXl+NH%Am~v=mazh}u=>!{pWa?Hu#kxuv1&t3U6{N347ir<>&u$;Rb4bJP@a5D z!}#^GG%hx-+~d^J+J&E5F7*%4CIPark+s)phg{KUx z{{@K`gFoxGL#;aK*6qp*+@Texp>9!t4+o~dZux+o_S2j8TP}PwJdWc@L$2jxca5Q` zx*8Jc`}^JPbsNlhrPP=x*=DAoWHWYgiF4v>Klr<`R3jfLdFutS$sVy-!^3^%-wFmD zXy}z`7QK73!^BKaj{gjZ74eD4ZlPA?>UXl1RfiPkJ*sGw61d;2ZD&+%9E9zg zpBHp?#KCMZIrPf}#Xeht*W|G?UkdQVX4&at<6KIZ(Sgzsh;hLC#62(vtU8NLR6V;W zf2$Y%K#60x8iHe{XT>5R6b}HFCxu3Vt*?N4Xh=O2ls|^BNl+DmZXNLMR8DX^ffx*H@SJ~mGG(@QR3;Fv>PPuANBgSr(YmkcT5 zfQk?Gywn#;mG}&lhH^|y8y6eP5lW!LdkVK{%)NgCA$ajbz}D3utp%?l9`s%7XZu6q zZ~+njTf6ld2?!%Vvtbsa36d*yLc$u**}a@Q_x%mD4|z_DQ$@Jo>8zRSHSVELdd=8K zoxe3l0PD%gt&uhMz2p z_<}|@?@BEAvH|E_&$zXo3ahz4x(90y?OblLE<4a7a}x%8`1bj&;x;WnfdR1nd)M7+ zpg>qrn?rK>taHytH2;lgH(cz{vh$o=CXoFR=Na$$2j}pi2Lnb|SFc)i$(&cs$pAn( z0G`-z;Qc)Prb0|)^Y}MCV9zAP*WE38{id?ia@D0~uH%L11#Tl1JJ95;8T(!JqR#-n zynyn0W2`yL?}NX1kV4s)xz+N5s`td;lkT>`(VT!6$Bvot_o|nle)IbU*}>2-xXe zB-QLO(;D^uOG5yxYg93l*w@sE2ZYJ(ZHtFXg9kzYnVQviL#Mt!It0iCz&2z<&ul4tWlm}@w>;~>7o9;hh_OA9m-vFmQz+IR(W%{8{6qbl?Yv0lo}~0 z;4NL-+W5FYdI}I}NGLkYx!euyAE`H?Ir=hUk4|GIP zT%w{6kyd40MjU`fE^uFP^KuWDn__nQKE8*z&;pUe2Lz%J^Y{!96hG&kdElOk5@=V>;BEI$H{gc;6_T17p>26If;JD z19(qE_`}DRpCmZ}+s^lUm#dBf<(dP;+y_H`*xF1N#OxQ3$(Kvp_ww@cpL;*}{v;dg zX9e!f=+{~(A@+3?SHJO3bXbTY?>k8_k$}VjWFxbxSs-r#aNTFbIDAO(W@GU0^6Rq{*6{-cIy@k|j&4hqYy-8;$u$K~B?E4d zfU0(#ZbIGlb;X5GJ+IZXCj#J8?}sOC_*IW4KvP#SO;8$e%1Idn%o`J8+?t(4^?tQl z^RBX=C^u`SJxdG6j|euX-UoDL4VOE!yTiNj0XO6_ONW3K!jcl;S14!l)RPrnyvpX? z%)>V6*N9gqS>9D*fO99Hl^CIt7yc@%lACX2W)$!@zy_Q(*tI?{8BuTn@~}X23%KGf z+XEt~(t_Us-0-RFW%%Cpf%CgE!dmC-rlY{GX$oKs?fKgPc<&aAiVpb7Gov4Y$XoPB zmW62Z>Uecva8OxyZ!>haG&?UZY@u27wSLyd;kvzNwe>S)lEmcBU%0Qc;nOGOfb0YG zTY%WHB%|}h1<(WlBE>J0btx`Me@#0jR+nkA05zyE6(3+{@$-P{J)kN6AjbgM8htRe z#ftBhmzM4{u}gpT3~+7M+&h(2xC9_6AR_?=04QC4IB2J=rlqEN#$tfN5Z_A&7)E{h zny_+uqlpsowga$DJjcfX10dzfwO+&TnHs>YDP@p@pIe@rjCEj?R~*3Zqse*g_pTfs zt{0mXU0g6>P`H#o06<9tRAbN54^ua-%QcTYd;sVQAW7c(J;DK~xV7JjjB9g;N24a7 z%D)6upTJq1R(l;94(_-{Mxs^l>M6dkn$bA6Y5}C$wu=lpm&<_DcX@pso&#^kYuq6Y zXe*bn4qi1bXq@vr0#>aLL19-di?{3t9;YdQB~UZ~*a7nFFl^sDVa)&GIpuwn*ac=LY!3gip}r9T;iVgSypz`CmFt9Jn%RQW1>SIW@ls;UO@vQm;c zw=Cz^4$CS)oqUKR4IQ0Mzrq5)y}e!d2)Irh5%;bUo7U-UVR%7!XPX6y! znT;CA=W#G-1|7*-JM|sS(Ed#4(J)TzzrCJ%AtqxX!vyS`#zT?AjTpYhw3!+0G@k>3=A(6XV$(O9j#HGbyn0oi z{uF79*vB}Xdo&gAYPLUh)lVSR^?(`R%nNuF1FFoZNC=xHUvK}q-ct^HuH?WnsW-Bt zAu%(*1XS6DuhIeE)sa;a45S6uArZ5EGn;O*m17by&n;SjgVnH^YMmIIe3v+ zaH9GGfQ0!L9+2*&rGenPaGU0K+R5&d9E6OmqN6wXhn!FU?09@;ZeZ#PEOvMN4q&;V za8c8NW7|vfEfkRO=n#vQE#(fK&H;b83zwnzsM zW_JYzYi;{YtLN=Sp4hdUiuCqP=7C_>23;@+o`s$9-tkYp3t-|pGCBKHK*<2Sbe-kB z;6d|g^rpyx(BiS{#lBc8kb|$z%tYlx(+%$YdwRosZ)?mgY`cugbuT8<0Gc{&wl3;L znrEb@aLk}(c79Jcwf9>4=H2jC=M!Ec;JgNDa6QzkR|jg)+5MHKLl5GTK~_zcghZCG zk@2aX2EYC9!bc@`P5==0#FMHDh74NfWHqKOLLNH>d88y{D^IaN zp7*Ko0PI6A$q!o%RD);NvuxI7UH9gs&CG~_8?SNS=5iC}^h?4xE05x^`LFqUefo$CATmK1AO;rWeB8+vCFk zhK<3=D;hIzn_ZBJ3#{AZD&W*Y&@lh-dG@QTFl!H7 z)kySnj~eS{qOke$@h9J!kWu(;?yp}7sMJ?bnWIA@qL!fLusTT;UmES zCKM`MPB(ItMs|;XWmSbhA>tM?r~uPiF)eQ;#|40@fYDp)H6B;F0cH@)f7&|N_}o%9 zPy%S!wKS6ej|Xg&La zfmzk$Obk{a4A6jwJ4L6`sd5CGj5YehD84yYa-b_XzP)Fk6$R*-!L z%!|U8KNs8y0b@)6amS15b`YQdBB7GHcD-|YvI2u;QIUl~6b0hEA>m zz^*ZOGKB1jc+_gKWd$s3=vEw>V1Lhp=>}i~1qEHJg-|TP_!MGc)3n#xkCrcq#an;B;D(MPq#Olj@E`U2edSmlc`u z@5U#O$)5=KQ`9q{WaZ+L18fxlRvgG_BMb(*8SfB9AX zZm7-wd-3j8R5)p#Ju97A8z*>jSBv+%Xh8{+nzNr*f64r^jE!vy5cB`*rzMpeqz&lb zs{-{@>D;9>@NXcE^m`SH!vUnf#^LQVfFdpJ&c?#|d)DA-g0CeXpee~GN*d_8e`%FW z6{`btRc}N~O;G-pME@a9&;Rd$;HwW>|4ZNB9qgm{Ym?zIa;S1($!XVLNA6TyFy165{ebupG5^Mz3piZZS|87<+8FpF)= zyvCdVJ=lMScB}0Iaf#)LLERbEh$jMD0$l|YSh5?r1tdEG6Ie*ww8Y6dIe9r{HaPh_ zumab7QTT}Vqr27Najc?6l--4&7li+QGZP@0%Q_!5Ks+gOyIPe|2Le1$3bje~lRC{I zN?Mb$tNElw&*2Caw+?^ciD_agO`<;M8CZcPPz*YAy~ZV#A0I~5gu3HMKBDmn7he3` zodL7nCWfl`x)PkqB%T-yRH5Z>G9Dc^99{9IU{C}NGN-O^CS$M$ncK5>2`r~E7#%G9 z_A3x=T5_Zs{A}7-0Zwdv^xR5(r%|*82zoiBJOX!107dE%enhmY>F*E&ge_;lK9BC0 zY3e!;=Z2~beaqON;*10I3R9@H+5Nfm*-}tY9*rKhiMW?o8G`24b78(-7~$?)OjnLi{f<8z2vY@7(&{7?wp7Y~ z;T6i}`DeEZx^MZlgK7$~|A{@X*0SEi`OqiLfq-W)zXyv8bmlTjUlSx1Le@XN>fx{* zkeC3Yb4}rK^nuipHWWgzSOPzhhR@z;fl0$@XYa1>K@$8j9Jv_KpK5(^am z{SRZ>fo;0=W}}aFjz{BhrG>`4DiVTIp{!G~9$hiL29fqmIrI0KJnMjd zfDO+D+`t)Zj}GHp+<{b+1;T-`u9IoY%)NLP#l_2@D89K`b}j|g-I#U0A%|3BV}S_8 z=XuTRFA?|@5rXWu8gO|@U*@f4Ss9}=SN=WSr!w!^{cH{Scv`AtY^8|gT zsu(bL9?emlB!3vg(U89gnz4(LI_4iM!*z1DQyDjjA^Z@IPMWnvq#O;2e#`T`|J(sR z?6gl`*&VIk&B)w}P9hRwA-o0$^59%cLT-$!{1he86W{)w6WRrrMnQ72xll8rbR|J0 zERNI@I07O$p$iCxg|nx(f3lbS4L-nG?q%7S7NvN;7*@ze00Vt{u?fo;sb_K71kbB*_3_|=oxyjVFvo^*tRQ#P##X)1y5H5+RghPR($sG1>WB;+KvHrlwG9tY_#r z7XeJ@6}U-S@bmhYNcj9+L7d3R z@?@|xvk$*|jx-7;{Xww>fA`9MR0>;Q2MT*<$|?0u0lWMy?kf?cF%^`o-#J-WEwH!k zn$+WP9QMH(1xUqQK`b9e&(tT0P4VBf%cWp~R90i#PVMRtX3P*IV+nt+UsDcGg3dq+ z@_1&!78$5X!3WfBLFtUT@956RD6xAbA0N-S%5KHj_A_k=x_U7nmHaqt?(Mm4p(Fel zJQ52>S(~bo#l>Zdk)4L@#QCUqGK^_2D@**ytfTgI=ZBoT+Lq)!md|O%LC93BbI99Q z>mp{K_;a4lil$)6IeQ{i`M!U0ckGmUgkq)*Bmzs=kCW$uo7!QV` zmw(~J%d3%H!}(3x1_4=)3e=koSs&jr6{}g9 zcx@jS`3$m7fioEB7nxj(Z;W@B%mg9C=QIuHQXnPt$4sG@9_EW0aZe*1o;FG?V3cUb zxC)AMM0kCKocxgu`aGz#2jsL=9?+f;T3|6iKe3>ZTnK9?-(S zIe-OGDs4iSNOJ9!Y3E*k%VoS5DgH#7L~b%}+(}H{#p6P;qfU5{xD|X9Z;xP)KqW*_ zBlUP17ZEUNkaVrnf@(Q=Kjaa7W4OfuMKDqf7ecRctHYdQ&S0~TK}P|7FT0J9M8&Kj z2C}jW*!0B!JozEwC3-dWEyqVuG*sq+uyB*y~5Xw2UgU2f{WB80$b%9+cod zw0BG=hUm$tSg}S&F8(5_Tk+o)kqqE^+S^#bw#;7+7z>1NAzX_Ay%2e2O^LBtxM}Z9 z>?k=}lh7noTldEmB;_T#Js+}Pr1rN^O9Ek0NCTQr*|NeCtI#QbGGMM?YnXNaXngp) z{dq$_Xwh#sb>>n!=Vd`>LkuEEpC~1Kmo-mUf7MH zSDvkokCe*xZLN3`IcHn|YFx6+6ooN}cd3eR{6M-vbw*ZBrqD-Zb51O#UT0pthCIcU z@5na|S$lMPaZx}mcJVarlAEKbO6PT^Fns59ltULnU73d{V>YyD@Zv{0>{5J-Ow30Lvk?*f;upF(?UWavx*GvfAP!=c5OOqLFwO84S>Hv1hqcZ-i8lyS zGUA)f@Z?dZgr4A|s(|MRtFhuV82q%za}R9x2M0}@pd2Qy-#R7Gq5wYZT^rMelmyY! z({;T5GKa{n8-iV(-B$=L{!R3#`(AUn-yV?&%vz^HqZ#?5mcVB<5-HTW)kUeEDP{Lk zNwfa@7~?0c_b2nuf^j5KXn~ix4|MQ8+2&*8FL$l2tMCsI`*YF03OX0Z>BtzeS_Qua z1$~)@MhSD=z%whpiMiN9W4s~MSX6ypTPWvlMGmk$)%ix;teQeu)~t%FPTSx%wxp`% zC^C|Zmn=5o-Ef{c;nm-|)CYqGQFj0@?ff9+kgs`6#R?-Vi4o4!!Gtf;ruN+rycf|E z!fjdF_b#Cp-=fE@95f5vWh+{Lg3oRY+VL}_Vd1ysuFa$|zDSl@;q>MM*UBZfUw-QN zGmM{_9&VSnAnlUecoO&&AzE1u6rb3*hz}rPv1_`jF?%~+GgnVL znHv3}3Z`dvj{R2d;y$phP8FIw1OkN4$3?0n>i5B9`E!=R7VM25D1 zMS92$__a^G=?&b(6&=wKyix=00bDxq-sCX)tt5h=EVIYJ+J2QK95dwB#FDFfT2qfk z6sOb3O;29@7F4^3rK=;y?MVjJlj!}kd>otMavqqO$tEu)i@1+vf7|M$1=<;8Z=dE) zwHPL;%-m^tEI$uy=d&CmoaBi#&?t0sciCcF7JmOJjB+?Ac`M+@CwZgb0o5_g)OgR zqC^sSTToTr!IaHigGQ^VJ0~$?ADMu>!ASc}j;c5t+sNSt4pf+u5e@6AG2Bz(CXUzC zl^#DL8^D6W3<7-7Yv)XdT-NU<)M-vp2Du&wy6)%#elNmA&F8=RPl(%zJD{6B;_^0Q z4+?xcMQ&{grOya55u0kDC7WvStXK9QrTEYS%FBcF?V9r{G;92`f5TJa&itE|NAH7Q z>SN`0DFLyr+VGRQ3>UP3+44YN zyUTZ}zxI1E^mz+>K@i2-Pz1$Qjs2$1MXC!a343vJ_Xd);ZxYF>^Wm%(`eC78O~0fC_n+WXeT z1?*T~@5w;aC8Nct;on=#duGXutHikjt#z^OZ)OJ~hcL}qS~bzoW?N4zmfDXBu-jD@ z>#O4o%wZfzXK?%M7Hg6LILIo<$}EXK#Xrn4;=;xy6o=AG_K_cng)j66s&Pd(*aof$ z-A}TQ3La~_XTsnJqsKnN&vrK>zewj^t>^51{k-)Q)ME7e+qIYb2KFF_eN~(bKWPdH z*JgW=%QTIU z>A|f&?dE+22Om~yoZ=Z-WLN@;n(znXnvxI(jPQVi5!1-$7_TG2Px&@{Zlp@R*blLB+lrnb#RAihRf6y(-q$ZZLBj z_wEtd{a~?ej-XOex$KXYmR;f@;Zt~gijgY}bcDlv1J9J;KMz2pKA(BFz)$3*HyTTAUnTq>YJ24uf+=3g;?r?eNr#Yq?9t7!F;bJIaem$vtTlLoU zLw8;)%G!N~fzu?;59IvbHPb}d@3SVo;NE0(7T*XzG!$E}m&eg5;_2Tv1dr3Cg`%Z# z@E@D>$&D4WFgml#8{2>oXrV;E#^O?V4baSP-N5hl_zzCLvC<@@hwPmy@wY!)V%&%T zB9a;2%>vc}|J{+B=Eo{%X@|MqR)E0`ruLkE;Lq=$r#Hn=quzb%FQ%hC$0`Qh%6Q(@ zVk^AY_KX=QXCK2q&EUlBcN$)BI(L7gPTPVy^g`whXYC(MZKA=lhqtnbQ@X~v?KEu% z&lX(=4m!uqMx%meVPn96E4qzs*_Rj4W$L9pBAp2f#}R4IwA4@-|0`F#tRJw_>`Iq- z-K4I450MVrAdN+|8Uhr}cK%dU=nO?r$*J*?&=tN9-QiJ^v7QhTdEV0PPz4Fti|gHP z{FuELH6xMv1g!|>1J1(xn6)-;+1ZxBw0ljV1{u$jTA4r|yM@**`CnC-bs++tME*oe zZQFd<*DNgXsG89o!`d@`m1n+_+`D5~mMPzzogG6uT;?006U=evl5{fcXo=&^Z)U|$ zVK*|KTd?0HOM78%qHsU)Y>T4kd^EqaoeFP^cRD>^LSB%av}uX@L**ZdnfB;}GNe?J zYH9&f=x&3!8skWg=ryPX{gE~=(XVfCGRPKvq#vd9={WV_*A89YuNm3DFf1x*y#Naz zld6kAYmHy2Z_wg(7bBD+7=)I*wDy3tpxm(?)P8-NMQgzPpPY_D+oA9lZ#l+Ad2tDxZExPPpu@F%s>{nWYmg0SR&h=ln3I z_&9soJNlA<7<$*R^%I`JirpPsd=|tnLY2xLK$RqhmO^@FM7E(AG}sXDKLH!T$^_w{ zf!^3xVz0b?opFWn1wrYeO_r*C88&QL_RFSOnJtMkmXfmF29__BffGDVSzFBOG{0uJ z${1b3^fE!;I}Mj*-!1EhFZ`)`2b@|F=KWkd$quKrV(UO1@jLMb*`<6*+VBzWHhb09 z+KJ=$9OU#GnaZJoF|hS09dl@AU<`HHRcOY2G{l)$-(U7cZ4uZ5`AZ5yBZ+j#)mNd8x+eBg3|Eq6H>uHS3)EX}IQ8_8GZ!*JyF& zgnxWAgE(WWJG{n_&PZ%#eQAut8B&N;xye*=2baSc)xRA0o@x)v`A>$XXmmrPe^sUg zM|kIc_pgTgNNM;e4{xFq&AoXX_x_L}5@ucD>QQd%doF^^K=k?f&=(G1gH2p}k3p(^ zax>{iL8X(z07uykTE)sj;XpXo3el2SvcHuPAe+Xy>$MfIY8~*zvuqkNIf_ z4aT=WLnqnceeFSIIwS$HY<{I?*V?6A7-I8H4VkxvJg^j2xK&%cd(!mZf-?B2pzILJ zti-f}ut~^Z4r1@vATsv_OtQB~!IpA#>!Q0TmtOJjw>QgR3e|SNGFs&WI zMl1UB@3pFoUkqJwUoX0{TN=5IiUja+_O*WEOSZus9rB;VENwdcCiMr?6z0BJ#kM>Z z(Tij%{Rk(+k~moLDgdtn0|NN71|97*uqnFIXYK|KpS!fFq44d-Jus+xLT*RldwX@46-)16L*CF_`D|Tl4`2z7{dSF{4npWRR0l$W=6d&z1NB zZo#+}j+^z6$oae9K%uo2{0tOqM7h(2EWh}NVLjZ8wE3Ns^72#}?9Ki!n(gP^B+9oa zNcclso?~6(V5DaG)saVKqk;0ECvbG_rQX)6P&mO!m^ng?(>WFedlyi{!n?%#)MG=TjvG|iw({?mdPM+)XT{@tcfE`&Oqv+qIEINU`V)?amJyuT&qElNki zQ_MZpCDfZLe%c!VaA)~g1+EF4 z)_;!mU~-g-(7(>!y+_}ZP&c#(%JM2L#MZRQsUzEDF{PUF^VJ^WPaRXryL5oU71Og- zR!@yhpt|o64+iyoHMB`qiAITN~IhM`w=IIR{BnQ1PTRoE@*E$u#x49%ksc;RwD@jlzguteJ= z33pl;C-IX9CvUTNktN>^=Wl*qodMa4Jq())k}lAMc%pEt^6KklT-7qB*QBI zE6cJt`h+%IUz!H=1%9Yg7wR(??s1MBdt5_Lk!?IM(@{6|= z_XA-RVKwi{D^N;)0)jOej(*5`cX@8hJNM?uKGMEW30NTxdLweIAJ!WWvW@hhEaW%% zZ3_b?iN+)?c^}orXx*9*S)tq+pF;OtcB=4ZS>cVWNLi4~$2HT_pZ}P(&uEv059HNN zK!df-M0I!Tb?oHh=woKrN8vCY_T4p;fGPxMWpjSUF;7HP*=u1s!-wFxA{2)T9o66M zdAQE{e~UEHp`ZH56Z5%vQ`=Etwb=L#g0)H@oAVRTeMt(Q4Ls&nfMqnTT=~F z(+r$Uj2W|9)*Yg``4(U4m$gEzevyQ$zNAQ@YKj=5nAU! zJVo7oYD)Ps^+T*vQ>zpwRQ#*JSA>1)K?C2=a4}Q6m?=oaw)EnngDPInf2Xg|%`4Ee z5#t^%8lK{%9+_lMnPd#A?kF5pM8(t$L1C8{PmGMy3oGu*?Qcuy$I=m*k zNMB)kW>hvg@gj$;OauulN>*~@RqvNIsFp}4{i-`DAD(4wf}oe#o!%c#Bz7cPuG?z8 zaaKgVv4Y$)uU2TWfoFf$Wj^3*dTX7%{rz!>ryQElzoS~X;bGhe&F6(pAt)HLQeAZA8mcfNt}^J`#eQ|h>DsmA#QpmYGub+ILmi*R_ASOI zl6$zcAZq^r0|d@j$G9C~t}?7P_&sHH>xKOEZ5(+Dt$I`Vot0aNb-3Pw z?1zwBcWRwQt}!d{bmhu^7ArsVoL|?l4U>7?j1QNY(~ZRf2;(;TWm+(0 z8mkeeWq8R}B==NqVccKABTDPHul|WUwGlFiXVIKus9&F9#BjP2;UQHXtbNQ)YU^53 zOONxL&ZQ2EHwcEsJF{N4_FZ4V;a4tYhA5MWA>EUg+Cz;p1ffTC!%;PRCe8APtC@~wND%U9_LZ1%bqoNV=`XhTC&W2(xUK4#KuuXp^b@TZ4|O z9|zvK;d{_?aQjc+Dam zxf>?7M|5EJ!w1>hlHI9qIXhXP?-a4| zqp{%UzD-irPa-`CYhz(aTZ4O%X>5O}reL%Y=jGb9<&D>fosl~s9@^vWRzG0$?HOFLT57V@)Do6weE2T3$W?y3 zLq1C^!b3ELn%nELFQ!8Y`I4ir_q$VliU@gKvA9RcKpiX|;~n;@CC3mgS9N+KbRx%pAc?QhVTaY09EWRNhr)$L28WKSr1vkIAi+NB-hqJ((SK= zuI%V|%kQtU<(l997fni{%dkswh2kdVgi+~A4CpRAtGt$AiiU~Z!8_TUf}`LA5!uVc z8SuITC0H8J?5^qfOO=@J2eAXSk?nBQHv$+5!@kP*qfr)7PE~I}s^38px9DX_OMOVS zXSHS!!q8YL;hL6?7yYLgH>&xXlokVHx|e2sAnq^b9B+SKTefnh-W)=>kfNFfT<_pN zP4g|WQwM;A>@JF=_{=q+YN1n;yQI4M;fMr)+Kq$2S4_{X77|u zK9A9=*DzJS(;GhFEL!K&F%$t)_Hu5N%|g!iR9-KD5C*yH+sT*%JJgK--m}gBYs*#$d;&**L*GC)h10Y78C&lwdk2 zdr|Mf%IcEb?(I+=jcyEw+jyX}g}E5i=_qQkFqKRMPDJ~prF2$A;YWNGgrl;o$zJs7 z1xGQ~O4RV5&s|hA*cZ>)eXNNBB0VsgyuSaMWQm!cx+OT$u3-0^C5#Cx)1qv`cs1eb zJJqj6k(!mLzjt;JdBQ@RE!xk?V@;fUf%E%(Wid6hgJNwH$^~!3I%$vb@O@P?ID`D9 z{^@$;H|HRte^QC9=~I=Os!nEt{^xyAMuUIn&x|4}Sp|FM40X=38J+bP9 zxoe0r28gJ7DY}Ze)Ngrqn9->%sV4WQ$kvAT97GI(< ze&m;jieMj z$EjMKsSU4@p1kHZL$m0wO)6D7rsPBN6*GUcZdj=ff_bg7WIJ43ph@1Bqmhv-$%gU! zSxg}SY*@!;~Db?b?%oe(jU{;z9z2p261;q@iAbeI{)U9(GxPicn z3Wc{p%)a68RA5&uoFbsqwax!xv4y6VdL@jQfnF?u!UIRB$8p)ebOLt9pU)aqYG2Y1 zT)`L^6u-Oc-;ZqN{E}j>9TNH;;gazRftY#RN1%*61JOJ`W$U$1Y|Sv~u(eXv*AYsd zIR)y$6NU*-tP0L1xDbz?=pe6n$0ov@IapjB#vAazC(da2Y&dR@ZR zW)F`dZCm884WprdnM^zm)=^ev&XC#$bDNd#=mayfenCK1Zfp_?S;2Hti$ps>`ew8@ zv#&Vk3CB%1Ka=rZG*lU7g>kViUavGrJusRy|BHA{5D!{2&Js9^TG!RweZ-QeZw8}U z7k;PSJMW+DgTu!pBfiLJV{x+1>2%73g_+*^>sv;e9OP5*xbT%~2J%h!E$uHbB|5~z zAB%ybLaCq#+u#lL0DCsOg*=Aj;j`c>y?1lB5)l$RET$aQprnuk(F}wE(BbtNrXcgY z{bU~OnyqhD?1K?o=i3vRljKb;!E0=a6>#NclFZh$(*W1U7phrBFBEnL4Bh|WnztBF zqMf#aozE+(N9n}Gx_gA#tzi=AnnIaoft_b?vJTN7HgBQF66Q`)l@>oY&t4ebp}u|B z*7|0tRiw;roFaY;zcxkdy%STJD5^eTy(?ba<^$=*1M(Thh=>zWpOtCOK@mH)I5E3* zn>F7gb^i)`!qHG3^hm1g{zVx-8VD|`>=-P3Et5nNH0(2cjU#+?P}D6HIep`fb^1uu z4QamhgE(B^hz#I5sAamLnEw8ycOI7;)qWcT-+~P@2${qN?OsKh-1Re&Gz-hkM6@)9 z`r(qK1}6Ijo8sC&_WV9$T8b~zWLOD&JB}v8RN?4T1ILK^HX2l8ww^DI!%ozhnxotH#0zo{J`?vOO3gv^Br^!oXd+f(@1jLPL^Rzrbfy{yC#vfl z63GXgyR`CIyg>a*^TRC{^IYoEhy7lAE1+sssjtnRnmrrri7V`}CBwnR@oqdlhqZNq zmB0QbbAPa`4k=3dl&sh{`qM2{+ctXONbvP#@+GEa3B)hv+KakvOsIYg<2mAZYcrZi zyEB=o_6*C$VVDwr7BfU-z-ZD>f|Y&vd$Uts*jpk?v*q4LVEhN_EHPW!riUFkh!shR z=O)3RkW<^{J&V09aG7yU7jDq3{@?WX=_&nrq1;G*q?=SS^{3%q;dz~#S5{LUKgLaz z_l|3vCs;dtL=z42Nm$|XHMu^<+ccyqkIt%h1MhH#k3r_`wpcqSpUqE|CUV~? z%jUUQ4isx;x>jNAPxY&`)+6A2-nXLQ*;u$uSM`fT$i-tDAie;R`;$FRu(b>K_7|zS zaZY-agDZcgUvP3KDaF92C9SK8)epbI7+;FLdn~;pn!D)6d3;H6&-^w|lhrR~u8a7s z$Y%tGUZDw16l<=Yl(LH!knaPG7^rCiMn}nCVlLizX^(iq zUxU{;)QN<@R49J_I6PS&+^N<@5%B$+O$zAd4RpH!e1i4b9n-QDEv*RA9;`}DCx$_; z^rOeyF>U+~xh&*heVxaNIy2gsq}V=Mq3*I8V{_3>043jWfE?mQ);3W6$l5`CtV%?h z%(m*j$DXVmKOHGm)oNd!JuSE9{#(U2W(NHZ ze%{K4q;pKEj8wshxz?4X5SQw@he&h`ErwUKDQEFW8Ic&1X8<4Pycx zK2i+|s#=3)?f-7hkHF^q^1DH)ifm`#bSdKfFwf2(n`cyF+h8mrJ!gH<-uY;XjqgBb!7L$7evBE)ZMRf z%cKm^Hzx!ch1i3fv89BuZxb^h(G~R(&DE$kyaZ%Zsrq*TxGbeN#Bsvl1uK#_W}u>? zh!(&XD|Q-=KNeq1b3R}FXtIz|oxD&@y3SJcx7TD>cGFxc?3u8SlR>|OT|J|8xb4?6w=$F~KfQ=; zw}sYOqT9d7XC3y%wq`djSw9xKW6UJE@-{ubk^4GmtU~yW3fn5h^tfz4r#KJy$Atao z=L+ajjD?#oZ`Z-}XrMy`#nAz_ID;t$-PAVi6XWUp73@;u(?u-SQus%ksrv)HMTQN5 zA0&i#JYt0oT1OP$aeOiNyl@(-!_$V0K2(bf$rSuh{zHHOo3%f0!OC{oq_E{31XoJK z>!4RIMz5e44w(&C=at!-IoSSL_mci6Mc1M-;RTX^Skeza2phobnCY=lP_L=Lk%NAr zs4W~O1<|92(#PUy=W)fiZnM32_^Q=MH+;ry);XiSa-}@X$BFX}s;WoQN!CFWzNw93 z&U-dN-?J6Gk8`R6JRo*8c{GJ7$oH8~BJSCe59UYT0r^qai+~x>giBjtdeV%A>F+=7 z!}qT4t6|Ved~G(X`K1#H9cs;rHC5uGoj*6)MdB~cn#h49hv(XJ?!O}*wW;}wp&hafQJCS5#P%a_POo}7T=Vw z9j<(I>Y2(R`^*$W4{k6@YRIHkqzY#v3;l%QDwbrg!E@K4QW&iew_s+zzb66LHdaP} z385paY9xF@anY8pl%HWI>ajtay?}#eq%#@nxVq4l{>GcVo0t5JiPKofzPH69PyJbc|2#)+UHh#k&nf~Oa48=MR>mjMep%<tA!IT3*rCTZCaz-l^mj?iaGC>1CXiW!W%y;`eHsD$3m~b#SG9f>{QdN z7a=9n8Ey_lNN=?I3axF&1zMT5$l#>HLM*O^(cD+PN^jXcd#yEk^BsVuowH#|?z!Fb zPB7gYO=bbDzAg5xJnsZU;hKk+dUn@7q|~%O)wrHhD$7=$9%&+$XzA#TlKz%3#Vd-50`gC-*Pi8$m)M)TaXQ!p0=F< z&yg5)N@^!7-+WivsSxf-xsKE9a3MF|Kv;T zKb|sP1XTT&Pp_2-5P`>R3JdcAVLeM}H8le1x}%0HMq*#F$BIs)x}(E&vGhmkqd-6Q zYiz41X(Vlc_w0Aw7yuq$73$J+n?F}^(H#w3eZ5nUxNs9T@a`Uuw$-jm!V3GijaOD0 zW<6SnV}xF#?XQXb^h$ZQa zmw94Mucj@Va4?W1lMdaj0Fq=tQoD~0^34L(l7P0-?Vw3t70O!y~Y;E2ToY}oS< zA=)_^n{~KvMF`P?{Lg^)ltqDjBYTg2PSu_XQx=Bu`;4yer+-V($pxx)2$8h{Gk?G8 zuIZv~UK3h9c_LSAzdc2;ozHwKw&N0hfp|P4R3w?-@F4#djDfcC)l2;O$kFOQ2n8Go zM4z`p+r%g7RI&Vh@O$90SwNU*KU}Npq{HbEfX0IPOsPbG^qUB>-PN;>HzrEKwS~_h zmLP^Pe3bjrqj32LtS(&-SGMgx5$1gEcfjE4|Yo!#iP=_+lIB+^`7+^IhY_R zMe=`#G0ftCDgdcTstkfrG$gU8RbRou5=ndm^@e|@A705vl9t?t3k*ntNV!OD5QqIq zw@{3mcdd}j!=lkX5JStb@pR-!JSlHN4P8E!wMUia5t?R*pxhK;wHCFYe3Br=ru{h$ z$I1vEYQg1r5OTkXflwf)?3yuQRfrRkgo=h&MEtA;F4U`*v&DZIE#FWXgd5W(XNhjB zjD)Zqzs?bBe{E16r5onnOOi;5UbU{7$}BQ*^Y4zL!RUOvVsW4_G?%FF=ayf>eaO8! zTlLU`oG2TRqQ9k_N2ZiDh5lJ-)voeqj%?bk8ou-_@FrUMHXXn?cY?z^`;ylU_YQTd z2~_0*cR8d>?LvHYDRnY$>ikim74r_^su2nTp1t}9#PH>PIlu4pRL(qW{dPm^pUrfo#elk%5>bl0 z;6TuPtIRvu(#sOd(Z^_Mh2#ZIZ8yV`B8FPGlkz7aRI8g06mwM{LV6KV$ULwPQ-XUz zI8(t7D)t)?XMc9xrK3481Yu1=1oJTe?Oe#eOCF3f83OEs*9Bh3&RCmnbtn@8)nKfjo=G{Y!VfYSXc(z~!d17a^u^f@Zba4p zIOIzGC-B)|{yh=JoFoB_FGiy+#w8NH8L0wuK&C&}tDNSLD$=gk{*1=sM=E0k6oibo zF!geYKMG8>5*agS6F6rv@0W38Cq*DvNdJf99!!dX{7bmI?dvA3!8RkAhb-~<$Pv6Y zm0IL*EC}`FNcB)C9?FMIuJ)rVM&~oh6W7{ZDLVSXe=a6a2Zw9;(`ER*ubo+Pc_%S% z@nBmzx_At(jy9Rnhu@(y!h)={&MtqqLoB5%#&juSu?*~d~zxRw-;d8#d z>2pnj!IQKt@EFFqxzAhSw@47fR8|=NDYt=ZS!+lKe;?2CaEg-%`RCF;EtjogWU%=E z{6oh%4XXJ+cj#ZA_jGms=hc$bCI0;1efjhm4tj49fQbFykLz%u{eK7f|E-DPSDZPL zAyKz4PWbq#=G{1k)9F6FeVgI>L0#i|B0Kgt*5Ll-;{&#D z`tKOUw&mfF?GVX;XzK)Q-z_(fTb;$e?`{;Cc?~It!Vh3TJ!m;o0#J-ezn|N5zezUp zc(iMdefWS^+8ty_ayK^FBB5c1>?0xqMhMt-rT8iv0_Z(Z`K~EX@J$ps4t-8^2I=-0MJ%p%QsruG(f)zI0qGgNb2(HB5^Yy&zd!Md*Kg z{Qt4{7G70#QNu6Y-5nw&bqEP*P(T_{>F$*7PNk7<5CIV+rMtVkySp3i;(MRx`Nn(y zg?kwebqw9-?6b~VbIm#T-oGER(Amro2Y}6FFIJbN+b~G+lI50X`&S8FLmiy(3S}Hg zz9||QkOR;zUVxw*A{Uf5F`*aFho-21V)0midgS!*qHH=@yn;E7d%9_IIjqUP-{=ww z888XI^mr&ICr!6-xXQ}+ zolRbB03}j9QBn${-b)c)lH`wfG7s|(8jy= ztLiJqVsIXr493_`r{JD>!82yB;z*I^$f>oQ5lg$;?dzC z0|ZYC1mdJ$QqeHb7U>ZhokcAn`6Y`Mr)JZ@o|o)xwo*`Vkjv?g$=Axa+j|Ec5Hv0= z6MOs6Qsq3wPjMF&uN}0S43{pyv*At8&;C$-b--7wN5qvZ*D0U&f+7?<{4G+TnB|sT zVeuEm;wc>m($06Cy#L+{u=-)ZIHsfH9l(za`bJ}0a?d%w7f~trG?*$VS^DuM5gJFV z^!wv~!^+o;58r*f;LVadCnpJ(uD2wm@(8yNch@U5FgXRdWV1&y6&a4(l=J#`RYEs{ z_SdHKmHP(=qZj7u^TEAOO&I`OGqm7D`gC4V9795sSzJt*F!nxsL|3Sx* zYtQT0`*wC}Mz}0eWyvkku0~cy2GzpCf=t*JC%8@Y&u1D63(uJo0q-+iFY55zz4cT0 zn<&>LaQZX*bO7fH{0TDY9M`tLKNko9S|bP{#M=te|2HaMGlFegWw_?VHiAO9WyGNC zx|{L|o96CvY;Z%+*aZ!D5yWuX(9}6^Zmg9*d~wrG~RX>s3M|#lUaSA z%a;GMZFz-&^a|ergo`ngA-k(IXB-Qwjuo5wZ4U3-t*4}iyUXbPy|vOKkA#DH?gqgH zf%D5MP#mq{#-s|l$0yAYxu?6V{2yqxN&;<$Ea`5*i;k7gudxQ?s*EH zFV$O)fCoEj$$c|B)zq@K^dtnnz6!VSrKhVW-$_#@&j!Kz3*Wo^3G@EEu~gn0ak{)b zXuyp@!$h~6`%{I35zO|tz52Uk(}UG0YN#Q{ld$_0IsKH{lIIg=!_a>J{@`WN!h|`k zEA34DIvtO`O`9%NEWeK#@_TDL`#kJXigW>LTO_*is9{;uhL>1#)!nV!m6mFbpQ^4F zjg9lFwj$M7zO(djOwRgwEEOkcYZwnY7TFIv8Xp{Kp4H`k?J%fLeHJv#l)2(sOciyQ zm!>*u0Eh)3$_-8}w6qklrUMeETw2=x`~}gBWzf{36DfDf!QbT8r^g(&H5=Y(+lz_u zbeiFZySk@u;d@i%MrU+DH*<5#^W@)QlZd`IWe+IJt?3l2BI0&1s?H zcYa6(dIUhuJMvy~XD10~%K6xMKT!-2p4+NZgYj}Hs_N=52qJM&;@AZ_2gb+oaB*Wm zGz9<(Alsn+_*sIPz`Z4D8o?hLpehbZQBymQnp^HmmX(>BG zu!PH8%Fa+*&cu%2_WeewMp{YoiluU>u1Rt3}}CSn{t4KII5_F*<92`v9@D! zc|7;U1s2FN3``9JY+RyudtU(t1g#Kd)%^YL*sVv&9)yO5Mpjc*=*oh~0=auuBcSOB{LVUi#;5cB@=j-3b% za5T!EmPI2nw&{|j0mU0&KUPosSaSe8ws=Y=OHp^~*@Q7QbhB_(pQ78`#9`sNRg}TW z!QBh+qY~NQYG>5}hH1v_#t1+<;--@IcT%zeopp4MM+891^_;Pe6KwWa026bY9mA1) zwUj=cDoKiim$&^J?gC(Tjm*sS)K*wrbcy}X!_wN8qm7MEzcn)I z=w+U=dD#zOYs$)FKR@)usRdJ1p%zR8P3=+RgyTfg12n5)S%+H-z$B_NBQzg(BS}V5 zZt1G1uv4+%0i-9m>mZ;vq{Wa5i+Ae;>>dPn>_B0ZWS9%-yKfcPkxjn6bz?R@la9L3 z1d}hOr+u=IHM^=Q!`Bx&eWpA(D~mcgCAnJvu5v4FOmIjjbZRfhey!6UVYrUM9SzJ? zi$0QHg@%A$2J#u*iWwquQUfza2?6Z9;wH+3xxg0FA6!HLCO9%TCF!idR@`tw06;77 zy1F(|CK(Gdo}T0u$th6X8)tZ@H*r1!34PJe{Nto7Kv!&Pf&-EQ>J0jXzJ}%LUqwYP z0OY*>4h|e}oDi#9HCLKS)9y_T(l@gG-52Rn5KhiEFfU@1l?5)_aWzY=m_Db3`z$E{ zDE+f?0lZ^hr6qO7(+2Zo(5+j2-`b!dhmtl$>w#T)ZVjhh4xU8zN#WFOhl|~n z^&}V1*vO*16}vZGnmm9ZigLsO4l`ISiD@ZqhFs7Hm6nHaAr)wsV0_H!tpt#2M-Wa!0V#GOXYEnPmb$z5bx|!g7naNWO7#eNklkijFXw=9e_>~ zF*KUlomp7FIZ#z_xPtI&Ku}@8Yv$q*Qx=D{`tye= z>#p4WDn{z%@r?&sWEf7kge_kh9tu2QZ3BRq(NOsiPQ=?DV@@DQ+T0`rkUT)G;&vt& zdJhH!^Ju;|g#h-A3gvW8VK5p~d<3a>pSVpt|qx1zIw_jg;j7d7l1eAPef&=(~KL znyTjW1ZZ@!Djhs?1puA>g{H`z8Dg&|=OsxH#kMX0eD=DtsuA!I+mEi!w!BZfz^P(T z^0jU~9-sy|#o68%CD`t4%0U4j8bJ9YHLl3t)6xQvRq0W)=;6(J9s?7)?ODN>)yT(V zOa>;VY;Rqkni@WUS@nMNhfVmgID_L2chG|M+Lx!(Hm0oGrz=e7waaR?kdErh!F z8e5vZ*{QOcv+t-*4bN=kk0BtXTs*GjXJBFJ(1q9x(F+e8=3SMPlyn;b?wkhCBEa}= zG`EP)Kb0fa065yShveu^_}LRSvN(u8R|&m*;iBqL0}z-mV+KA@yvnQnot$^I-?De6 zU#`7!8w{3Yst2w(aL;Q}Dlg!x95wj&Mx1~ov>Kb`IjoldiPwE*g~3e2{LkOFti zipJ6nMloQfFFrOcN`Eq<1(a)5=FUyIwEE2no)y~~20WDe{T0dUMNF@5K-!rCK@ot+ z!LeXSNSAI2oEr}@tm`(6L6sO>TkCTFjee%e`$_uYB&N%Ky&IdE05!pS(PMCpK`~YC zOV!*>T2(`w$Tz^$6QY={iBa%AJgdJ;JIc(hCGl?&VNJ;?Zp!%Lv8Um294RCMVC}x& zaV)t>>nOZa0qhu{IeT>;J2G%zF=d0)J+9a@Eo0GJI2gluWMt8+6CRPCj_$gO&5Jmp zucxw)ZLM>!m>yup!@qc@c-~IvIG^~iaB9Y7@YhlQnnL+%SRD~cOMsB*|ZScGCi_+hq~og_7|is+PWH}`M) zy@Yl~Su|WG(0PVO79)Br=~8+if}CwxMbAVc$NH1OskIXqo4N%qp4YZ(=u=}03*wHS zCZwUXKB>L;a_ubZG5uMYi%`|qA?&rEp{A*6=%wfTyElaMP&j3Pqp74h+CY*KGw$s1 zs*x0AFp7n3?%-88c_C6y&CRF?!yveV>;)jy0hWvO%_KH*@Qv}Cf&G1ETH3}qsy)qD zuX^)A!jdMhtfC?A%HYsatk!&FayQv$1{7V!<T$B@4j}QQ`T0eidl$pw(<00S z*>!mdh!k#7q{VgV6@OURrkhBM>f(WR{QUg#WC`;=%;ai8{Qb8`mbA3`!;0dZpFiR1 z7A}88&RJIh$x& z5J}&>VL%Opq{up0*9RP?Yrl|@0VeNMaH?Q&mAa%JE^2c-6dLSpBs46S{w-8%!=I}v zt^9)?GxD{#{du83?G-r#PA33tKK1UOg0QrBd^=^^6NEk;5BmsEzl#m-Y9U>&Pj`!b z$(zQOeWGXXOOAvY*Xw!DMuHO^ftz|BT#%~*jM%=gOH}03n(*-C><5oOwl&jbX1D;b z+Teb5@*B+h13R$a&0I{c&D-7`XgVKYfP@u76ke^#>gU^Rwqg4Z9%kJe;GfxW3ntVH zF;jI!!nP(4Bv{d0=@D@or zs)nX6UpqP=fEf!^Nm+_iF#~|tJ6QV+4qZLnKZuUTb`re2me#@Pc_}E^z}!EiY#)I` zNRRJdM+_W%0MSnsCp|JY1@b9?*UV7a`37j&-Q5hhF)@V}I(;C4GFV${*Dtl7r1mNW zlN+GAz%`!^{Vb?hmZ1RoywI&aT?iIR+{j2NMpaka3GM*%PZXQx7(Ct z>v>lTL$?>?g&K2C+U5Bf?hWNLXrBx40m{8^L%;17gTl>_9%zaL>d%y(-*I}_rjv&y zT?6sHM)WNI!cQf%#}H&GdR22O#uuMIeFmFE$VHTiiNc;c1gm+?DdTg3V9G!lp4O_1 zGmnf+$0^sdWot%FTE;&wF7%li=P#djyeJmW`V8KHHT^HN>x)e!@g?E5GTdHbFE5d&> za#hZVFsuh~#NbRoo^)^L-4~e<+}qtG;-blb2NG73r51lOUYjUjcmi|v+sEJ486N3k zkAZFZIXOhZkrX*q#l_Xjv;LSkNO0A5UU%^5nHhbikY%U3&x=yL`R&i5labN+eo$XB z8*?^2bn;-mV&b>DEC#u9i~h>3h4b-R#(gXxf{*sKG)?GJy`Frd*#E5hhoTKre8`#5s3&WdIQGU`K8gX z2L=QhOfWHp&LQ5XEl=VG;;`0LcT<}bf9DRs`rPLx1wJA}1!7=@3|IxdSyh3-;bX{? z=M!vLcsM&hkEB4fu9?|4z<*>-;HQ;+El`|W0hUAI-`LI|H_#Z9*RVk4E{MaWuLbnN zXB&mX8=Z68L|Hnpc);ck5X>*h_#P@&V|k!J@^jYLwOh{rtMC`^!AXqc9AK0Km5j^c z9*E;6pdQFlTy__}UpbqtWR9F`J#9@v4Grxp?^moMC&Oq zK?T}cMW+5JO*o+6xptyksp@j2vDgm++0>bFT6*lzR#Iy6Drd$MPmp8~017X5-z|C) zKH><2x{$p1_7CBF#)x4nIIu#!W@B^exXSxxrTp;7GK8~)@OljMiI#kCw&t;x{C-LJ zcF9Fh8z5Jk5ueV71`E=Fc_2^dj9C8!Zm!CD4Rh(qJ#oMo0U@~hF5_sWJmbEd$<7lU zkI+G&=If6U({)*U56}i8-TR3`(YPv2L z<~!mBjQynKbUi!sWKed_=fT|qh@}z1VW7Im@dlXAUVNxmWJiub1asD1q~&q1Bh*3p zuySPIbx`#|`BV7P(U!mWt%;%i%-O7txF@WNmMd+>^?2S)r6ZGZd6J~lf&Sg(pT8A< z>wg;b5QgZTplS!lbeZ#>*`o(-Ax_crkzr^KuBI3*RbMfI(lw(rTr8`3f1WJRL(eGa zu6XVG-){qT=$G>GshL`NP~{{62)sn)<>gz@ID2 z*!h6WEUS>Kdvj1enS}J@PUf@pPHM5w61WdR0@REEx$JOt2^tq~J*`;qH=5KJPA$1* zmSW zgoKVPB1+ywD(3@8aX?e=+uQ7)@qHgszs+c-LLac503jmZ$TM;N)#Ty8hSW@WFZdP;~e47dnPloJqSN@pzJCd4CUm?*vmDJuwvK=k40==isy5~f49 zsi=qmNH@|=t~g%5mOEsoeJ4NIE8yzEHqoPd*gazKbIfd3UBlGE$_RWnz|~+pWD~*G zE_8My090?X@^aW1lHk*U|FwDoXK#P@GNuEbZQ*b$;bjlomyEs*;2#17Y3m9S_%@#R zhwV`ui@8})8iOvIekre3a3of^1aN3>Bo`FxgLimr5tWdTRJllJEYW;nTvMF)=$=)^ z4!(PUJ?-T^1ll%|aQzB(M$AA^Ih!naF%r;3OX+eG_L*MSYs=Dca+Y(ly&89}(~1oi z1C3qqT70%YQVcoXySje;e#Wd6Et~VTLmy~V%4V3sRP}8UWx#vpUdN~N`&{05fEPKf zA$xXvq)SB&821>K0mB;*TPT3i#n=_PQ+ejV$wM2{%NrT+-+|B)v_(FfS9T@nSe)M6 zOKVv~&JBQGhq!o~AxFp5SBE!kqo)_Z3PBXF)5Ve0FMV*;e`@d#O7Aq~9WAf61jy`x zvvS|d7*pqN(|cG^XQ;rs+Bf3TiDL#0%)|yD+6HMiXbpm$$iy1grBMZDbvqBx zeeUk=GNL2&5S{`=JWy0IUqa*uJgzIUnx(0Qp+nQxJ$dpMw)X&))>XN09M%w(&ccdCqZHY6CItkP$~5 zxELBWL&Zm)83p z*MwzaQc_Sz1*4Ob1Kd97@~qHbEl6rvvB-so14?>^{gZZaFgod^{qZn$S4TI{u!LWHKvu7QN$|1mZpLxtfs ze#r}W=y0J6w82hCK*wITQZ-?6rNn+Af_(Y_12pbu=3S9N^mvX3PgmJbK3!|M_4TR1 zts(8-5?9*@1-QHh#>Vkr?w=q&Z9Tv2*yL=h`=J|s)q)*oczC$LBk;NIrz=GD7&EM& z@utdGYI*UIP8R2tuJn6e+;~_X)(5Bn+&ZYFJl2ndL#8w|1&VoT-na~oB4FO{i-LYJ zK!w}(6?|zuI7z*90jhV9qAWeMVDdR^gV3AK({vI(WMQJbMGGuhUiUE>B_-9(Mk!S` z7oSufd#BE$(<1Hmr)@#bRkh@X3i2)xgxwEoLn9aLG4C$PGjo6MhKU}_R8-~!j+`KS zoo76KVh%462m+ULoEsjTRhLFeIb`lX3O5{iQMepalVR}VHSajAI`EyidU_ngQfB7o z`+`IS3WH3bebMs{gpmE}+gIvSczXm*TSax(E0Ny)S>nMiyE}O^!y~1yP;untvqj$PNXvpvbZ?^Gy-#=<376TstP(REKZYcFx%gLw@k6~F|E?x1bggL+tHB*zKN z!TI^`4{yfvO4V7OIqI`>$k#H*ZiC)>Kx@?ws$6ymh$MhDcH~z^=QYIE9_= zv1|6d2ec63BfADDpGFXW2}xdi{7(5&`wf)76pJ?u8Tb7rJsV|;J|fLSdq*xT2NrYB zL7O>PNlB@tZt(`g>pGhfR6G4kOP)OWhA0IK5^5!}OqE}Feu)%Q$F1Uo0?m$gKcEBj3wp&)%8yT z8T9Y6?=swld0flS{r~)YGc*L6&lV?ZkAQOS5)V5$XI+z2VPyqwb=a!-M1fLjZAD5@ zp49m01#IXDXuN3{K*tAcJHSc+1Tdg6*|p&?I=2)FDk3}-AOU$Vl#uOdHP`zH;|sMn zRe>A1^p=@|e)&pSSsATH+Fw+Cst};ghsVZbUZv$m4XxSLJiDB+jx#(nlVlUMSc~Qx z!&joQ0mK{Z)}WutJe7~GSfgowEi0DA!ELRopk;;bE3)hg-7sO^pd?eDmq0jAB1J$}&12iF9iN!=Vtrq1I?28EFRWw)X5A0EPGdl5Re)Oe`(^49irlbFv!KBOLd@hj^0{ z{zluo%L1eb@}%zI9v5)Ey{KW6#7{C(AL28%VyNZL|LilL3t!Ul0|rA+E7Gb(4^FTw zObQFExk$j-J#*cwXw57v_$?kTIFS+VxwyuaRauRmb>HX+X6EMYUcHtp1;w>Eps5K) z^z1NF7t);U!Fl463R0xe9sP%!-@j2Ni!~%aeWFG1UkQW$3!DVMfB4B%S>~4g@Y_iu z2FiAfI`XC^1v$qFvkh7E-vwYH`vT>ai$km?YcTLC9N4W~x-?T z^fUE-o4W`L*ReEbJJ4G!&&oEKxJw?|y6K&293*VAW7E04Z~CCD6*#pgSZp9LH$>kg ztX6lw{`}{~UeA%jpRlA^vBT}F&=9xL)_vC3*stQ`{pk(bg<^(>y?2+oza$rcj zxmmwL@Ymbevu_fU#Ls4C~mmq*{yyCz8m5jai~3q z8STh~+uGYuxA-qvio9#grvF^%h}MZy$`g5Oc(H!U_Z;sxoRoBQoJTIp6&XP5Uxb;W z3rzKLwIPf6%74bPyM{pv3tNpA^e2Ip2YZtG^Cyb?i9k zbL@$8{F}y&{?9=mR|82u$TxwyLf6V-@7>Ih%}cSVmA3n~E+P5hqpe%==Q?~C{vWS! zbb>7O->==TfXEc+LhO$SAJcYsU+p{Hh0Z>rKHc*9`9d{*Dk43&aG4&T>1p!Vw+5pn zpQlWy@K1A(73rB{UvL3q!EFF!WF?JjDzjb>wT^5W!VMIdip$jP3A{1UjO}k z{@=WM{Qt$P|Mb5=_n-b3=>Gpd@c#>gljw-z74GN_OLwd5hQ#~#UWRQLhQ}LEQ#6g{ zKP0zn2ZPU}V>C)z^iaz^m#&Wpv4b#5pocBR-8e)Mg_{X3XyrIV{1uXn_Aes%+2#fc z^)KT!|4e)Uc258d@ldU5R1S%+tj*EIZS#0UVOR__?0g|J8!fAL;x8mn=-1_@zng6@ zBFjLl{tl?Y)!hkbCUV(pHb$%?B%^)P^v~*h@uJKekk7Q$f>7@v89mx=7A)}a~8G#nwMQ1GkooGSpFJ&9-9_E&11>IY(L@y)>XZDP$ z=w@gHCf@I=<;Ki>xV+zamEp?_)k<=x^}4Jb^m){%@L?li%c+9}IWTFRn2G5pf5J=a zGk5B@)8%Cz!J#dp$~3&W`tL35T7X$L@ui90kR;V@Mss;HRogo98saM-(cTlBR&+EN zJ_0qv09$~wm$!jl6JfkY)7#CJ%=+zH77!Z3pa^e(3K2dGEPXX?PuMS%WzY8C3lpY- zFRY_Qp;bW}v+HuqzR<5l3ifYXrw{{Agt#XU*&Lh~Td2^qHyTHHhpJl})G!9~C9Ybc zvG*O_sQ7~HhCP|(^MU@(S*p0VM1=)G$*082SS83_r_|NX!9~9R1YiK1nLGVOjfiNyZz8cS@3mG zk516sa<=&()Q0QkcX(rcZieCxtaRG=AqdIup!YP14I)Hdm!e<8cHI7ZzixPNHC!K3 zgKI3I+XDy9<|Ttd==wdt2k$*q2)@*Jc~-rCL!_E|qHxD$9r3Kn@UNx5vfDU?8+*va zu!+)Q)o4z=1j@^0G2NTra-da^e&~IuAsZ1P?x*ib{PQzhrsVDnG6vtnrv>(~e|}th z`rp74`ZhNCcW^YLl0mB@ujxT;uk&tvRFtO~?oc#B?G#JjY@|8v!t}3$;T%4h=RT?< zC%6=~#<_iypHB>RCU9N>g9Yce?n@H}{a&*$2R8klX}cPi`zf#}^uG^Q{}Lrr=Y0ca zGuvTqmzn~j-hCMCpJp-&z+*U#W!yE+j3e2EZaY02w7rqIO9EZnVy(91=+)xYW`<$K z37^-bfh$74zT~_>xlzqkHF2xNV4XxBj`oB!;etE(t#L*re$}I}K9Ji4YrEY&==iK0 z!N@_hV2wyuYNr~jxg#FQWrg9#TU}uPTKe}Dxu1Bdy@4smY*qy73sDY?Pw0@>FcQMC zRzU@iQ2m#o-l>$=tg2cihw)3P?mS*lxlj1%Fl6@2Y5^n045WzSjl5pJ@2EEerI5_0 z@FIo(UdBogPzggvdg3I)r8aA+(Hup(j?m2&9P3~zECED#9ineYd*pw z*5oIV?tjOoyI30foXN}#8Ua(!>ibfsQ~OejIOEb^IpTtaQ6N_Z6*WUG%G*I5YCZ0Gs|A z8CFofiS8{`m@sPe1B94{un(v5e3|^49yh!X7nxO{2ofu*z zCp>$L107UCP^kVTSg6# zPxUW)}x36w&WNwB;E`^I>$p%w^hT zU?(z5B=aMof{sAqn)EU9ik0GS)BPkEh9Tl%W>n6u>$Iyk{SY5|B zuTMBn??h~$3aX}dmCKf=;|(pFI?{)@4sMv{(B44hjy>=7A>FGk-76?O1SnMEUSeGz zI9i{A>-wi#B!M%UM6yPtu1m7FS8bR=Xyvd?zE?%4rUAVh@A&fyLaz+x(Pe~w5$n3- zhTQmJzl!hLFJfyk&=JT%XB$?mk4MEwEUInxObx!yT78|k@A}wQ0~h9nje{(88{)}a z0OOA>-)PNy@#^1z&K3@{t)|`5TlL z#zGPLj_x=0>ub&5ZvexLn0Wx@iE4xv_VB9QDY#k5 za_!oM#$aq>t7d^Az_~S280ij?TB)8pxR!^*Ku)iKB=hVo{oyDhfdC@Vq(If=lF52P zAG)KaLg^EZZ0z1L3p~zsoCs<_<6bnWU47v~>%z2oIoFG~Vdw)ZLKJ^ADnB_QPRnOk zxCVu&`b!^uLG zsP8M0U3*fNpLui8K=RL4p2!}T2;$)zj`?qJ5ZD$Jsk)HYG5+|n?+8ms=db-J5@9p& zH7n6%hjdTfvY=!Yv^BRZtc7J23=$dhUKqCOeSxz_5Ho-aAJXr+W00TmfL@Di8!v|l zqd$J=o}q%-cVVkuST6R##jqbyg z`(w-5W5kO?**%eBFROp2Mct;AEcWPHTr-^)K?X%xnem#yhM6q)#TjQ9YRp?SiB(o6 z{IwwwHPY(%JWa|wcO+6OC77Hz#U}jvyup%iG3#8S4?z#QMgF-3)QT9J%Gv}kB1O)L z`jrJt2$)=?b=}Ye(w2{W;xFVi2tM6@dz<{=e{eu0xE~E*I1VKM4tok*Yq)gCAt^GbTevh zGI5C!V`9w5)Wj}52N5T1<8+_=l+0yV6QsoUt%}v&G^^eRs<(A3Ns@V`k)>2^V{z}gnMFJIz*(VPpOn%#o$V0SS zjat)($@*I6oS#38(DYXo8fFkY?n@3u!S@co@$Cg9eXw=WZ8wo|bNuLjkzU^%`wbgq0-Qh9HnhH zKbQC9E8itv;dn+B80BnA9yPVO5D+kBUVdOO^N@!k_rHfYJka!W`5BP9XoUD?&Yd`jU8xozA+bf6RcyG31Y zwST=48+;_OGp3we_iov@PE7LgeZwIqPSmR%%r}k9$|Ng@(T3SPh8dGz*cN50m;PFO zD{cAG|3ILtwgX9sDQkvk8Oojp-$K|S*Ef`ULLqRkspmUw44MHlWuOg7J-5xRud7D{ z3PY-1X;VMhPmH#4R+rncK2Ldr^t6Cm0@V_qe2Up(SZBt>KOF~dLXxZo^a*TjZ}^cN z9}GDj`i0rwy6%06;bi;XhoMK#`<8n=Y{WcEf0tqZ=~YdAXe#a33qz##KDU+KRU*BaO5&iw5@8A)&zDj1H!7U=(PoF@9P&t34H+|1-+PE1ftmFTL zp5&@J22~Hw4YO%>{eiLs_0)0Mm8Xz@tP{1FO27twy_a!vk>>Wr-9G?D29+Vrq(^ zkU&omfo?SdoxGI+$pn!>abxLdN-=&l&o4e93fYJ8nh_efw5Vb^9u2e8!}Bo zS?3j^T|HQ+Cip#TzrG^DvoR(fu?hBZR9m0@2Rrwb9TK*P3nJQf6&w^~Wz9T54G!BZ$FGFeeK(55e+krX{dausKJW zh#^(tl>IecEvh$=ltb9xnz{vWwc9!5Q^(okf)AgF=3#K#qP~juA>1NF7*x%enVR_w zJ)+-Frs&O~Z}Cth)DJg6Un6ul3r?nOd^76cv9S({UZ64DJosBVkHW%z+%H;0ISr-k zAGOQxTIQ9%)mHL_sM9!oYzy7SQaDz{zYi{>o_z7-%W#R2Yn!7ij!`-ny<`v}8|gGu zViJ^be@Q8PkOY;E&Ddxe^tQgS6M0OuV-s^L=MsFK7vZfB-a7h$L&Z^^UcK+KK9+i| z?oikAF#*W-7q1)b(`$PSu5i^tN}S{*Z9B_L;gXk-Bv9dUdp=^=7FMO*{vKLW=V&&i;^!;Uf`o%u=ptQR{kGhPGzQmx*# z8t*0N^84PC?+OVm5G=A56OK_aRJ0|`KPpYFTa3_Qt#3&<6pu-_a{}#}EhMj=Al|~BZE|o8p|RE96|c;GvsrX(SBP_91TVhBqFJ<*IT3Kt?3jt8 z4|MMyd`yK_|COrNuJy}*IM1xw0G7ZRI_xZ}IuylYy}U)AH0Lw#5>D+|Gnpcys)f&~ zy}%6Y-{#9m(JVaKtS#XjW2jpy{+VtO@{eyq_Fkp;yo{0&yTDS!oFC}(G`4b27^r?i5?lphsaY@qb3dKHeDDC^Adc<2H1-Es2w22BuTS(q>G zujN=VxxaLrIxfKX`xzkb()nCrnW}}>)ljgWH8(r!S@VpO8`yVe(U$mi68TROl0c5)9fgX_SI)t`djbK_THRW zjRJ&3o%chj&X2KH; zZ^~VDs#%zvwBt&RmJMoMsWo|pwlT`gvVNs{vbJV&osKX0ZAqwjb;9mG?c-x%Fc)#+ zs%LwU#G;&y-N;obK3!Xc+NOS~4rt474FN&f5D)Te@ns>t?7H}`1(Er)tR#{tjEcE z#7q}-L?&fzu@(MJ7^a^S243{260z~n7OUncnD6kv1`QH9bxUGflMkBg&eF@s^B(qH z4sp@6QPgl(4i|XkmPbY#wEDPq&l75{83kG9)W8Y@Yrc+=86= zVHp9I0xbz5D}a$o?IX|J{FV^Gj_3n)3Afmsh0VlAU+0_teyf&rine4;ecPT;e(>bt zsgwgr+d6yLh(M4gUp2SLg~c(~g#W_*Q@QijNVL{P)=^X5rYmdy&rwa5i_Ca8o4IL( zIjc2je{zU%w+Iq*3Aw-cDa_G#o3q0{Eo9dtIvxuxJIb1*FG%7LaUWjYt_bKgQ$Fg-)@g}*xW(DlF1)!lEHlY!N&tF$pUYasV{p|HJ-wk9e5WN zul7PvtBjj}X-U&eWtGWie|Widy3!eXa!)bWTKHt)HP+!gg4d9O4>1*rMV+8ig5qIt zR1EPkC@(dgWlm~;6ER6bkOv>aQthWAYLnf0G>@k$zAU4!Y7JW;BTOuER#9?3q^k(2 z{wT%QJdZI~WKiDymInTtBvsna&t-~KJ|=UHs{B`aR^N8+#yNEhMR&UxYT#8#gTKX) zBAX&Qrmo||TFbThA%l=(b*t%8t zj^M_}f}kJ?1Xv7G-H%m;C~zZ=eSgdFGkvO9 z=FG2{FlPfnAX?+%z}JZ3rBZyb()cHaH@Xf;PW$eR&{`jrc6Dutby@xY&?3xPOIms1 znv(q5?VS1~0{c#U0xi>F_o)037As8G)-~B8L-i2 zKrfyn4mSn6^`Y5jx*W2XSrD15wQsKSrtydz-JKgubEmHm9oRg0BjyBtaEf-R({4<- zkTEkP`>IU+K9$Hw+dp{@RV&lC)HPyS6V0T@b;a46pNlZ-b*RwABwR^^1bB|dZaQms z)IejdEK~o^zhui>U-0^q{?XIXw3Ajby%!IBDHgQ^*_{MqM0u?J@%)qDi5iN%T>F-F zUg?vQX=KCSp@^y$R!^mxK?0=ByyZYjOKaAd{q{M7@ejzqs>JSKZ}-xyOI)%ZoJ@5P zo6-}*PN*onpJZbC5N9)K5$xIN=5l++~e-X1*3)(grvCI%O3HA$4icW1J{OC_oiLDo2fVLx9l(Waxzjm+O`f|~Ny zruiP02+uxhXnQJ-OVqee zD4)Kh*dv%o_kBGvSyfv_RpZ}<1+*z)sT9t)(-pQuE{Djf>E31;aq#mNv~Js?dL*^U zdPf(87=Rop7^~}+75e>*#I!*oBib6`R{*PyA!0~iNo)DmbWJc(EP}~91LxnzXWQR_ z$7iLJ(x|kO4Sr#cBR8YP5ip4x_^G0hXuwC)%8d7JbH&xpideg8&k zBGLfa*)p(d4SF!2}bmXyo8tM~d161rF~{Hy&0(ITv3sWEi)`BPdb zd|TLUxJq-RP754EHtjNNzkJd(D)Uxz7$DO=9}V-9e>WXBvC4xK@2n9uM6k6=D$UUKn}x`Fk*7+ zWIb+}L57I1(<(mH$x5@mAs0qOY=}iE)bO@vfpR*LoUBzu*dJ|0p<35zE^z4ez1g)y zB*j^Amz3~n3Ys8{`4I9iwO`DR?BhId7rhSi@Np6?Y!SK;Z0`hy-41;%nz8;~_uPn~ zg`+E36zp*Rs(J-&AkycARHc1QQs+kfLl}!h|7*pcq~l8~x0#F+J^A)U$={XaxokL7 z6~_IcTIXHzt9Ee1sIgy0AT8%k1X{$KDPzsttYxRa{%`1@`U%$+w|c3^LV}z_sN^w_ zImu4&J>Xt0QO1j*n(fJRbySY4&6j2%Z(aYZlqpN6l|AtVp)bxu zf*pDG<#@yO0%Kt~qpE##&r)!z0-IW^8DzGUxFBFOR5#f-h>$miw|KAIDkhXUF!_W? zfH$0wz}}6MFZWz1MtJW;(X(vlcy90+c%*PNb+FT&|PY6+iWGVL~24^S6;@>U9NuR@cmu ziq~qUg(4p^N(xlT;OfaWk6jb>VU-bmEAaQ#5n%WpI0Q2jx%wYT@WQ4)af%*Ig6rU_ zFLy>tKH}H!kOT}6@&@B0l_qO;tZ^=LY3q+zhvMH;$198TLRIbh+u#_u(zK8VHNTm* z6@`Q(S?H`KI7jhFuwo!{)TOyFF4-ixIaHQyizTvLV22 zF|h26s6CjSRTf7&7~*Wy60?~TOoM^vPgpMe{>|Ik+jPgd z#eV+C8+-?JmOS>=xOjjpvE?8N+l2m% zIkDxtk9pA(7jGyMpwHBf%3&A^mf2Sd&BsY!@vbW*{yT+EB2s6QnfxxbW)myJpGPr@=`MwHw5{(Gud=a;}kAiRC zS3q5ara}-4MaVf2x~&I1<4}L??G;Y8edMAs$mpd(Iqw!7^oOqhID`c2TU)%x{J# zXws!7CpIff_vbqc(FLqFB>xL^E0+mc_1_n-mwu;D7s43B-y1V<*$`O#Evblh)Qxjg zNUO(|+B@?cA{_`pm(}}Fz$i@%yEPQmh!hGBqxT`mF(k2N8sUJ1Xh9cA)IDHR9VxN_ zcNU?=2^Q`C#eRc(pQyAA-G=2aC7xa6?OWrg{?>fq7sC9VZi|>KB){0nimFCyx4dE> z@3I<5V>o3j-h_>4|6J)$pFmXgSk|FcE{$Pv8KRUh;|vc8dH>1mbrL&wY&ew}=~|Yw z9D9lR?-9lO+v(~|$jAApqLJO9Wz&x<{W)Bpl`3AnRz{7!<&f7{d7)r5+5B0|QS=pT z#aWOeF&go)Ull^*k9%V5f47=P!KfVrmEL{0*wbO2?r+#%&4>S%9#6fDNlX$f?ryU% zKQ-fhj2z~9d#6vxoR-8cAdf{ailDcTbe>zJ85W-&biH=l^#l!*Y3-kdy=@MkQrx|h zKei7?7T_xybd5vKbPx~@YdI-)e4F(pYJsLJ(-o<{p*bBjqZ}a&e2XRt%t#UtXK*t* zH{5}^2z|-g{Zy5MNGY)wZ~NtRgbZ^FJJNtr_YkbVWy%BgG|Tpd5UU}1qF^bAA@4;dcPjwfSAa(Ry-)w zw~VTx`}@TD`WqP~d?*eTl;b*!f8lb>Tr8t{ir_Z8`PKkvp;6S02r-EJ5#7#ydWifv z3#mylL$YOH4(m3lzTL%I;z62&v$Z8EeI`-x5&Gy@DaxO*t@($663?ieEegp2uI+<5 z+|7a8^0)!J#kA^uTZFs8b0yAU$Cb_N$@35Nd56J^LJur35X7AqvRAF?(cwkx_Fnj; zPOY;HoA0(GMa2cLd_}QH*c&_~$0W!|PV@dVKDcB9qz^vsyP^Azoh-x@OhI-|#6J`e zyok284E^7ZC_00|!dnQ&swfqinb>M_&HPUomV`G__e}y&L9ePGN_gS9l**D-E!BT| z=9Bl`GOJ&{`+wMb%fGC)w(pmcl2AZeKw3Cy1eBKUMmnXtyQND+x?uql5+dC#5+~h# zN_RIrgLPeN-S>X>{uA~)O~+;p zCK{yUG>7ypZP6uFP)z+3qxXkh;C+1pZF#BD(SH8HVIpW)ujI)u;*8v5n^iG|>?F;u zvnE)Qob*3CYxZY~4+xbx%)B}4Ugcuy*nUoUgEdg|#Zf?Fkw;>~i99IdroC0EjoTBK zo{m+kAbb#WmCugWl{i7OAZ$dIjLHH(d?beGX*Se9<5T#7ND&5NEBxTWlU})N5wzOa z!=l!<)aVjXWa;?CloDgH$h-_c>cb(r!17h z#$R?vZ0rXMRZtIQe3!XaKdfx9^`{V}CWSmHzoGAn+sa>y;y6N4>bqusf0^)0`q2EA z^-53l#_Qd#FSmnppsX7iJ~gf$=QgDyIlT~k;`3@afv_qL2}>Qy_#9Jc)#FFi33ZZD z*N|@0&({%+&kD_MsijZxe{vm&Sq4J=%`!YuP4OwlOEwntzdY$g5H+ZVbHTjL&~aaF z`e!G4wa5zCiTTr*f~7Bcs>4fC6Gfr1({U>Fiaq&5 zSDk?6Z*8RlHjd3P+gd0Wat5e*?xmOSQeRDAyy0#^tx)yvK}y!^N(yoG2=F#UAh7W# zkzI@yZ9w_{<$Zt5d&;NqC>mUg2>mQVp77Gy4a0PuiBO$b6dgVDW1;q-0;XK`o-^Z5 zx(1y7>Y;09h8D=9CgVd`8f@EDb}Ye#F~3vzlp~qe{0r{B{e%W=)a39Xi9Y`gJ)ns{>iR5gCkgl z%>3d_mKX=9UPJJXop?wF3AxFhSKN}~;VX{(GH!F&$80tNqE8bUfjI{&)LY+rLz6fbu%+m zNW||&b~(osMl;oBK5c0m-p`9{x?<1_#02va7s$zK|d-B5jzVIv$Xx<~3_Cs2Y zZ6Bd@ZbNs%a}UWN9p`T38=iSuc>HOML-CSZv1i4A{1f+&Fz5pfB)#Wrz~W-`IbCgf zE){Bko_n#V%nf}q#^I^g=_rBx({aYb)2#O2c&;^FSIRbCf|J9po>lt(MK2AQM0)eO zT2m>CnT9_OzAq&=?fLa$Kz3wsaW5W8<#`}u<8oWZhU`IbH3l`V3-V2mp(p8YCVLSU zR?Ha(3=Y`oP>hH+w>!e=P*mrTua6gu=<;}J8|4SL@SRfKp5EaTsDP9UmHNWoGi!lD zrNn5-X{cTKAQtyLnm#hR(=gl6_)0Gt5Jl`SD>?P~vJ^ZcVc<&YiPAP7DZofT5tsqj z9EDiX0gvzR!;&E+=+;rJ4-3xB6CEa}WX0O0N-2x~4jmR8_S?F{4{pOj!q*$*xyUh? zGZ!JKFtKiITHc5f^Gh_91G<5xH;?yajpF4He0qAZAr7d=+w2#1p$- zoUTRI7b;*)IHbCt&y1ztD-duVXBSMfYc4*uB!LLmp%J?_ zM_oQ=I*M};s+X)EERAo} z+_uU!S!#jr8A?>AoKy5+<;V}ITJ+WOM@Mh}mNevw5N+n;KpSg(YqC&vtemUFoSlo) z^h`5Bo}1-UT@tH&8X}Sh4E|X@`9XwmE_pGm=UCUMja~-c$y@7IN?Pw~|J2yR!>~5* z#8}_Au=b3vnoS>dQLlSvh-(Od|8JH+zQ(H)~cn>|ygSP3w_n>UX zMjPm03K!uLBF`SxZ)5z#Fir=uw~aX$d!CtYR<8s1GdKscR%IL9O}DDd`~BX3C?hDa zG)RNrz+i=g1QnrKk&}K&!6p`9w6lB3wJtoxSTh8J8?qR(YQ}Z+6aG1W6qBp65ocwThJ22cJUJwmEY(Jai?B2)~H5v2~cr{7_1ygYWq z&cuQz7{gFhCPR)m$))@=wM9f@M8yYuMnX;Fn_z~()<8T@WOsiL9Mv$pf~hmM1>|OI zA@toU84PD{|8@Um0ypv*SUBZMwolZl`B3UM7FaV*^! zyUMpb9h-1#zegPAhLiC9#F)oE?Dfp4Jf*5?+D_c>^C7D9dED=hQc?GacS|=S8n$^F zN?{TqGwL%TgRX^Se`@WT{zQ44R^xMvz904;`RfS%jVYlCol^P+UxNlBjM}+llwsU) znDlEa^*@ueizI_OyZq~rHtRPv2&}h#OjO-QktrX|15vTkcmy4(N$o3NHXa+#QzUly zfkbu_1Ag3WDV3qJtA^mIweC2mut0b>NkA&*w##AJ3R8WB1-kp_XNw+-(H((!_+8CX z=^!Cm`!%CH3&mf;%t1v))XNJYY^!k4?vN5qsKEa8Q^r^&(R|b3ysZqW{r?bR6RyKfVnc-rRC5y=CC%Z-jjEHxxqJg03ixe&9TCWZ4hGmP0j(;@;l7P6Ag^ltl!4_s-*qlTvdaD zU8=Iy5y^!d_E7wmuBe zApZ91bT^0Ko#3ajOUlV^wqz2z{G#NYw|rM72*Jpc(zwZ<2FrubHjzs9@=v^6jZ0sk z4n!H|B83nq4_vOROwUShR$VR(`_O#~YDlh{q_EDyyfn#hF_2WYJM@aaoOr za&Va^enuzs`rSv!vLfs35YrQD1O)eES_o$I+i(o`)FI|OgKi{l3i zH@a%k7vCfwf+E6!TC;BHCehKGbY@)jw2fW1Xd+}^lpcK{P2%n!mdM|c^C1I}6~RNP z(lwK>w|w{q78-9c%jlhLWSLwKJ{4fd@;@PDvfaJ6J%|QOZ+guc!&*N_%j_|tTXzwnV$>Tfs<`t6>y?6L+WinWy3jSa`FM8 z=mGxB_}PM(xn6J;&ai(UJR-KR1(8*~&^S?OpYC#{fw}8*8y{5s${HN)ah5p6S z_(pi@MPM~1#OpLUy`Mi!>gf3!zbB=7_Q^Tb@snr-sx|Yj4ZiTxPrb=AuZe@-$4nSS z7bK@G2NLWyE`P_?H5hDwjGugV5ve7B#5jRu2Et3uH6Mdhp{m%f)aNRiGhh6Xi8dK&zV>yE)p$l!t7QUlI)|&5l<*I%qqY3i&pUtmtDUxUv!PTFeMoeQWO}B z_>K}Z;udfXg%f8DX4B%eV2d45oKlLus)FTy(u34M^1HyNn zXWgCatA~9w_F~N5yHJ;S4VHLT@#)4p9+i`Y@gJtwgh3jDj890Oq9yo{22C>ioNtd? zh);)~w3Uw@#VjSectCnxBSlL`ckRJZb|CHhg#>KAZj{dc**aXtX$MpW7Ax| z<-n1Gp&)SObA5dc2uk3F9k}Ttp7$J}djMd?oD*FA;_~An#7Gm&y3$knI#|Bp>$gsB zzc^KOZ~Xn2iUVMA3O1?~$~yoa6&4xaC3&$fJL0wU_B{5*{qwOrH(WSAQw~nIu`jy4 zit7HhZ9@KUbb25^o$bD&DxL$WnK+wPtiQpd$EHUjog!zeXrB z2x)UGl_qSk*BT z?)(gob^>mn>$r&ASn0jSwyFJ}*9m9raIV^D#Ol`SR9qk6@#hKoY4LE=(997r2gcit z3(}_)WiUy}I5H=7pY4Bc`8NarZ@nD=IBw+Oxhs!~TQrF8)785Hw}6=^3ny^6LZ9C8 zN5MDy7orZd{TaK!kq@#ip(HqEXzCjE_Qpo@sprkChX{B}syRj(I{pm**N zg{1qHk;`=;J*1W&Bd&S$_5Y)dDb(3Zs7AboW#l*#6s}*&J~BqMKVc(G39cXs93j3t zVuR%1+tpM$3oLJSj;c*ZIAkV#*P|LW~iUgP1!R0)-mXFH)?5aBcw1qIx$SKBCi z#r*brwQW;0cVN)8yI{Bg4I@eM*r6YalwSkVC(UC>-30|gXsypRtcM-=IU_zlkU*l* z4UkHR6kb5Y6kkM_Rz;PYb_Ajayl_l`b4~XgT<1)VR#bzOs-~i*j%f@Zs)`uswwDrr zOI#?$vqrLhBO5~8(}XZYJD`h_v*C)m_qheUkf~#(-~?Y2@9}*Kz2Ht))eQCjyj*Fw zjwqM^unW7*o>;CZdxbIr;mJ4kH~2=#)+YuzNH$IoISich6#Ed%Z#&3%n7^kr6mu_s zs<WB^(5<_@yT=1s9gP%5b7V@1~ylPRMk%{bBs6r0PFl=tnwlIii%% zgO{OQ@LY`W1UkAw8CW(xvVBh^S>WExQmPMAw%x2G9l$5Oh;rdEN2z*JiWQ#s@2Grw zw(3HKw&}-$fq%Hizw_aI2>tTIt0aW;O&Z=q#Jk}iPfNMN)Bg9bM}R=8)ojo%&=f7` zfB!tXkK)z;`afvl+y9&JZt{Oq@00#t=zRSD8=bHD|3Bpat52@cuhs>9A|Fmu9tO0R z&Ru;SH=i-~{h?{CQ7-z?)YQ?q^dNJ)wsgysBDm`lA;R?3X>7@hUj#zo_S~K^4AiF1iWVO}pWV)T?-0W|Vx17=xPZT5F zyX0CBhsKhwdBxr_0{S-C2dCDWCM**|TaV=AqobPEVbcFH{Pm>v;mxh}!A_^a=MDApB(3i~ z0O4`e_u3P%Z?I5+6c1qh0vsIRx93;o!QSwj0a&^!^GUo&D7cR5J`ccGvCbj?&Re|~ zz#I>8%H@rivjSciZ5jf8ZyG6^dBW9oR=*8$Bh{JOU_i@fz} zyZR%oz}Yjyu^#gBKa}miw+A_Psq!kz>fZnu2T*j9f2Hu+Hb%2}AIav zEIr|JiT-V%v;V)1^#!`Gz8ML>O+pmXsR>a>7x7J?ZE%3bx|U#q)8GG7l+tWZA9z*7 z0_}%=@v>d8?ez%Y4VlmTIkx?tGd|-*ZjcRR>kIZfmYF{OB(l@&>gt`bXEq z(a3=IxELU5j#dxRdgyxC z=*0oH(5HEh#~p@Qx3E8mbT`#{r4ZE%)A5<`mCt-P=t(P5uaj#x$K`skPq&P1zjna*?s73aiZf%q1AsQY`rdK4h2r17GMcAKTm4Mn)^~fEv9||c5iPf| z*kg)n-g?}v_EWlM)f;I5oj)P{q;RaAW!{AVtb(p%b_Kx`Nc`B?c<~!RL%BKMH-s+3 z?b+CrYjmuh_#J&vWiYAfHj0Xgje`;>l3-E-N|)o9+|ODuhk6|ruc+QkTaq^Zf6fB9 z2hOCt#mAKa0D^RRI>7JLaav|@-J9?GwKWDH_9uK-LF9_xRRKkzi>`2UYrkvn+<-0Z zt@9-+T%ou;ZdQ73(d(`jelO51(c?QV^67kio6|fnT->jWFGyW^0}TA#7JRq?(JfS$ z+|KXL?SVv0scvmqxaDRuuQY#5V*p>^N;_+ryyf=ABnQzs#_sy%@FOwAvst*bF|wp= zHg@LYYIlwy82;jFVt|mSU3BE|X>R@$*dAHq=W3hzaQ4A(uyN^19#EKAurT8^G}j3h zkFd&GECq{;kAn(*yT%7F!n<&ggW}F>xI7yg>$XBjSb_U%ym#?%SOoy1Bjb3qWLeZn z{eYT)7A(?qQr3uybem>l!%19PO8wUP4=Yt+FMVPJCo$&iY%b^@IR1qNKsJI?{{jg3 zrXI&Af)rUSKz_l2=jHBFW9XtyGq4p;mH{i)jFuMGbg<~&gp);lnHR?U|GEQy~ZxL!V2D@b5URgFfhP_2W+3LJ3GIQ zz1qdV1=Eds@>U^7m&a+t#N7fU0nS_R*lL%q)m;y^3+wB{9qR`!Mblv-B7kCKs2Ihg zEAM)Gc9ghN-n(&P+hYwnt!V3Yrr*kwA1M%ebO7P9Dz6V&w3#!Htocn2oT~pU-qnpy z)Yg8qQg_nHgBilAJ*di{Ry?uo zah6ViPe4TUb}-Jkw@96VP)-~KAONMNT;wc;wh1&(FE_wn9gJ!*X4U%fl07Fgu`;zg?FGSDS|pjX@)pfMYiZ{xGpm$LYRD8G-FS~%sv)Bw>zxy($cD(O+qqS1 zePF$JmDEqeHNP%o1w3nVZB5G4qrx& z9Dc8%pNT(mhS?KV=|ZtaTCE5cbalbZ(IX`;(10wTTxn?P0-OoVnFpRwz#$MARcm#y zyIM%+Q?5w|17mCn&WFT?=8FbCf{v34m6=Zls-P%n!A)Eu|3A?6r{%E3C8xo*ZuG!Qs03E-X^h)0XRq=eSe7%w!OJcy|>dqGfJGngI z&1;n?*^Q^9WaMiw7_x%P?t>`6im8^UWqMv)0O;6?J#I-6UcGmWWwms(-i8E}uk#!b z!W$d7uf4yhP*Fvt3&_6(Omio-k<<3o8uK9w%;9z_g>o4pKU~x>BXtg1#pm3DeJsM|Ax5rSf=&Y z(B2$c@OyW@%*aHXqAANJ9zI$2>fdw%_iTVBBJfDu?3ik~QUDlrKugcM|6`|8q{_qp zt|!aq9*P#)q2qK0zvz4h563B&uk{^pusk+&4=A3Y8gLR{ZU&K40RsxOdsg&sC=MFk z2zF91Sg^8|q4%v&Tnyxyk*UzBos}Cw?}(fg!}Se<%e#jiL0nWMFv)K_lUh5dmTt%% zfp+^#-EI56kK-dBoi4ywuU9@rL_%)t=J#Ow{xVd7f3T83ziXx9q!MMncjriv9{+0Z z;bbgX&h&QzyW4`t2IFa<_;tusX1Q+~gKZn^PMNpu*jMu#59zVKmm;Ft+K=3!Z5P_Y zf~)PRmY#>Bv@D9zdD*s&PNPbH8 z^1#g3FpeNJ^y*gsmIf@Tcf7OQX0R**VYxiLlA}#n>`8%D+4`c_qLi5g3UgsRFmbIn zH-2p^6;*CfvVG5+47^COmaDx3dw_caC|b8ghnw{v1k7m5>WEzW+tHh)(4`$?K+X08 z9M=2$Nc}&}2Q8tQ`?h#uD=8b9Fu=kG$%LaV1)nd8iKyc7;jLGV093a0058%>H_gi< zS+BFcc?9#mD$!rN@V#)`T&fQ$uunFs6s1k8-^}&9SaiZ3tK#4koB>c9jDw~dTib>e zrnEVQbiQuxmNO=CiQc-s$y&$$_B22*3 zY5hmz9MH$clhqyMkxthVG%m;&shTo1hd?(H1d;v;>ARrMgFY>v#rK(N>S!5RdZzC0 zGdJ+^!t+%4k#`$~1G8OMZwHir;`ZFu(qDPa8M?f#$AA&k`GZYF zMNJK;a*EKM;vi%5U+w^JQrOH4CF5mA(_YP7SUN}5wGMFX0g$f>Di{lJsyVUzk`i9L zz|S2zcO`2&5YVDz0%S)p_lbx}&=|6y{deSdsCF&;?|`Aayu1HUYV2e1ARqu{8T;^( zf)#aOw~?WTNiacZNSJ79{X-skJIoaq9Xb5W*$Gg0+26kD-rb$o>^*YlBW>Ce2l5wN zyXJ*V#3oB*&Ewqwo&D&?0tGGb^m*5QrfmAZrlvp-P^JwYcPL;fF(i3x8e@-+Ey(fU z<)BymNoRbRf&Bgv&+x;EsJLhB_X17TPqlJa}%S7%ft6rc^rGCCo z^aqALuK=*=j-IK2Zv?hW5b4rX*Yt>xdwm9P1@7o`bR_pf;2!Vn(IoYsjE_MpQl*t% ze^A6DoL*4)tNu}xOhqMGLjikGPEOEe3G_1ngL|y@(On&)2>xQ?CjX0xxEtmQyx4=) zA>REqbI#-2SbYOeQ_~X{K-XhD@PamDoL=B!1#|U>Tko9!j}ru#sMbHhAK_vkfvLS3 zGiPh!Y8#UhZM=TsVOh<U^|GJ4F`+Op7D%2XI{y_y0 z5{+tSK+LQ09UpirASRKOgI4_b@t!umeam^f%4=%sb;55T%>>RnHuHo@qj}lV~*c^$S&*Io@#%U6A=$bJS--*9g;+ zhx<9c%9y=;gjLl(enZ;S_Qef=ZEG;$?~;Ub0vV+d^RAEVxy1}?jwz?t??6rgh^yE^ z07HGIba3~?11&TVIH5S8ogI0X_&t zWz#_3!!-|}`iUtGt0u%3%E$Gu=~v#LtdoqHciGn3=_QSrQuz~l(kaocw84e--7}|y^~BvWT;4P~s4dO`twTH$LH+NV2qu}_3Hpea z6p{#{EQki4Z`bbGC?q2=@m_~hEXI;+AP%IYI4z#=hMFyUY}_%$_G@rT%gFQ>Ijp(@ z(4OSvgkdTz@Xq>UIWU4GdB8m-ffDYznxEh4F7gZsMe~$^A!JVS@(}cFCIh}jLz$r_ zzFL*%$QdRwBGT>sTBSM!UsGp5kvYlZd}f2kcbDgSwC?50m&Qhpfx+EkvSWNOATOw~ zNKV)LwQL6jS_}#3fXjU8BXAsy&|o{fFaelqnv0W?)UvvK@}A6tKzM@0i(4^C5-2MC zG8VjM1It>5{~Ip=(K3?J6_)t0e#y~*jEs!PQ{rncat8?cg9cd^O#qf79dR_m^2H6n z_w~=6YZX{b#z2k2sYFD)A1Zqj=i&jn6bl>UbEdwAEeVc}^k!^K%<(i}MTTUaalUyo zIz0^35L%Y&Ui`b8R7-&Da4uk=%cm25ug28aw$p*&hkxqqSIZdV;NWc30lO7GK7j)% z3P9CC@c9n_EBq00J7M`EwpUJ<(xDFxGR6sX0@`Y9Zhgs%#*5Hp#gr8Bf<^g;c9nnJ zsNzVyHSVZMP{dn{I^&Rwm!*v~nIq+M4qI6Y@o3Zl`mxrC6uFym&P{!~#(R6RtQ!e^Lw3AoNP^s}1Skc=Kgod(s4QYHV46M;cL&Rl!cZ1JB zA`8%P;eLJmp<1j4lp`;Hck07VtKTq1g3hyYI@uxSjmQOXcr+vg&`W^#4NdvwM2gbu zKuAWmGU0PG-DoE$0jTmiMT#2I&$Mcyjayr&m-~=@78ied|7!JUS`$W{Ae~E(4w8pW zH@8M}|5=A-)_DaM{Ws6kt30!_B8$`Caz*Bk9-rJ_hSRZf-bKMA$6S<)@a$JA3yK+R zYa1uaIvg}KG^p{k+BoI-Y@u&^RjF|Rc^sOGfT863aP1m>3etU`#{8Y=GiTBY48OuT1Q&Q~$3uXFoS`|`4 z!jI0*yQMIW6zTR+CsC^BvvaeAWJK%QvA&@sWog;1t>n66Mdb=P7PC9j6;J<(pp9I< zAf2X}+i#+_x*v)4^z>dW2;SyZ?Z=Ae@!g%6xlc78bgj9vs1=n#l*~2pv63`3H+lM5 z+{!+d=hD*`Ysv8Fx7V3B$WuIPGa+ocK*T=uYCS3977$+J@ej(i&+Ix+nVTJ%>^Ym- zTV}-e%g}b+7gc)Ud%x>+JJWiN+whK8NC_1Q0VpBX*e(2Cx*ObB{A^RPrxkeR-FFGp z4LyA`{VvEKu&=q!9XDRq9!a!5Jj*c%OValU7QCPGa}73fV_5NSamdvPmJ*MhQ@IiM zFFWDRx+^Ex%l8?%TbZs#LwaHIq!(Hw+LTK_?|C9`+p;B|>AOzkdbjEUfTo4FvB3Kl z00B;4^prj{aquq5Uf!;OU z?bjZS_OqPiW%0FBE#1=kon1jszz5z~&&(^Bc{Sb!J=VGY&I6Y|2Pww*KaL)Neh$*L ze5XYU%30E@j`c|gel7=kAu(jeO94Ui4s$k0B7i%NgkCK@TC`gz}zVY zJVS5qT&}Ab8db&Z26;-olJudqM+)@V{P<7rRv3@0oPx^h50c;Y{WPT-r`R!qrj-vi zK^nX354Bu$wB2;eFlV$VUqHbYNGO1jwy-uARa2eU)*0^>Q??>?fY&()NQ$_2ku z&TAHX7fj+9ZcYRFJ&+vQnXa@U8IeTN!`&u63KM+mp;|N(*|pgwAawnG!gug(a0u^V62JeS7{osen(uQuT{T*HW(6u z(BZKS-vnJS-o!gBM_xk2~IFX_Jg;=M8xVPsi^c?z?Apzp z0C~*b;rt0SesIlP6_0X-b;Ujz>>%K?2?LX6STQAZP$73E+P z2tHL7wCbS^9%xkbC_l_P<_Fr$)nORdU+k_8C(cTMXUL9yJZQNS?RY+KOArHNWqaE< zKTle-H#|BDvdKt6@W6I86tIEobhUG0)TFe;(aZ|7_^3!>;#9zQs&HEp@YW;GQG6yh zMxQ9nQxjcWeCgd1S!SHCY{C}b{sUq?SD?ep;r<78O*z~hBJaaquhUnY4XKsCQ1Ejk-D6}fz%OVP!MpU zoaOQ~AYU@G%p4q^XFC#1nc6 zSNND}Gqqacv?pbsfdGv|o){6g`-XQcacNd2Dx>SRQZ_dV1-mTOZ&!sy4C=0FWC)7Xp$G0+^9}Yh1!`93mtsov3H{TF!M23% z^ZRQbYb{c{jM;MIP;Fz=fMQvukL?uEcg=r{2CBneym-3Z7yj}VY2c@kMKUSixHlvw zntFORycOUZ*qw&}AK#w7YyDnMR#x`-JCKXDWtOYd07_GtcPQ8pg|A=-T2Tzk+-C+} zvHtybCkTe(2iNJ7WPsX`e|IFck0shBg?6oV4`<2k2|;Vu=_y8vbt14lE$6?uB?~vC zsBv^!jc;Dqu;f?}`?kjJl+Vd?CBbC$eUih&rH-!<0G=Gy*@;2+w&QeQAc5$#SehR1 zFFzIXkem~!{w)qjvO`SSfmFcb^O93j!ECa>i`gR#0W0`Zps**mHApnw?Jm^DzMQLB zJ#tT+dwF>$z;$j*5hr=503IL_LuO)_!drQ{XEQd%R_P_xo4)V=Mz=Lr#T<+Y}Bx z5hcs;%iU1{py>jE$ccIggcv?Ue^S2{vh&u}JK0X~`X$is0~qed#!Zo3A%i6{JK9mu z(o(X|<6N&pjpJZD5awC!YSLnb7{yDx<>D?H9Ha0dU z^j*vEPZt^%={wO%4QhS*in@wlU`qJ5K1BF1{*U~7Nsy{gtCVZ=Ap-DIGcz-tYRUoH zy09)swC!Nyu#IBG{3{sFqode+u2{h%JW$nwfF#tb!1mcLJ32-Zmpj#j^~U|i*!6Y% zmh0;BBRj#njYlD?b_$mvRk$5;lh%2KVVj2O;X+~ z!h^TU;df7Nu3dcG3}R{rAhj5Kyy@1`KRlA>y)Jn7B;V+HZLb`J7*@u6ko~>drQYX> z5N+Dp@(TR@vcmmW<@zYYO;IYP`@;*e+_Rs;9!tDS?G0tjkD&IW`qn#b5ZS;LeSG=o z@tmI7bg^RK6L0`;KAD{Vp2zPY_#xOr9X=Sau*>g{S;lHBFPe7rlO!unLP*^Iq%Ezk zlnZuT_+Ap~X1u(ewDV5h2T#6;&sxs9UyE!yJ?;ls|M+S&R%4|}7uUmf6yInKPR~AE z(#avrgN+1!FL&3eve_fe?~}ArXIFK1HQF=tAh9F^G>eGzX7A9Ut(TNr^_**#Pei5w zsone7m^{DGE8~AVUauY}1hDS_;$L=6$$96=yRQg6yi6q4IU}L46j`{ock2uiBUC zGP2&>5}tA<-rh-?3jxtiL&H1h=ES1{AkaOKW=P?q8mYJGH$A@U&9zi2)9@R)3= zJe>uamt|%0zZ1|gF?(4{Xd{Xhv!p8>I+3?kia3n&ciyGla2smT7Ux!!Rh^VlThZg? zey>i@wrfcNsQHLs1hp~BXNQkssv6zNwe|m8cbw9(7W~l-6hJB${W|Qe#L6q`(gf{l*HOp4$RZBk#ii z{k)Q@ctuwCbt#205bswS-*9cKNP%Sb>jde#h3a$Cz3<=6d_-Q6MUFI=J@qfPSaoPD zlA+!-w-bZ~W!Uq`N=We5&U69sNDUTcSzAMTcH)v_v=e@4Z{CqzAnY(s(`$YBEBI zKv=>>H>1nAa?MHeg9HlP(~}cbrl+<2Vyw>$I6Gjxpng;$Xe<+*F~45X6uC}O$5ixld&sbL612HQtLUr`@27TV-H@(H71(0cD6NScjuBEDjqPZh9(nG%tor zKIPJ1zBcNZ{^u-!_u>ndgELQR^MBGAz*!2b{Ystv_en7IIHO7~DLZh+LF)|-g^?KW zaLHobwl>ZP7{2zK{9eNeexE6w?>Sj(@QH_@a~NbDF7M#^$jVipK6>(2QU5$9ApX0# zV?Aktv_}z5G*iHH#y^l+K6Z?kY7@+F(abezyNy7l7?c-!en6-nAnKggq)+E+>`77N z#*(xR9|Jxko6ks(r(R!mF(`gle~teXXpfCdPfN+%_w6s9h@QWxOBdBRg7LG+lVdNFhD%1S@iSc-NaS|Ow9u5gt zCw>nHifRew)RcDHWe9#3S5WXIu&Ll+yz0^}R%HP17@3#|p4$^vQe{sOLyOXQ-f15v zJBf?>2M9iP@15&7B6zyGCc5)IhVQI8e;hT@N;N7CSVhgu2sk)6{3+4QAKQW%2io!> zC2`#ptwZgvk}8!zicfV6$puoN19r}G=zlxPV7*d*KgNmC*#^Y37!vH$Wk`5qV2TVc zKnR)C9}H4Hi8KK(7(vFexOnyC>YFO~>(g?A$F_`D`+xe|vsm3Wdz@V_z(n!7La$U# zGyy?pL@ww)W{+c`UI$xpbm>WM$3ll2TsQ8dvBzg>ILGe$IAy9uafbh%LM5MI>C&sHN7p@{on~T_ z*y#WEzM21XATNwN9P#nQfLdg+1xP5?>@6?D0Y@|2f}x>c#ernAAq3P!Bc@`gq;A9e z33-zQy{WGte{N|W-ylQvckivrd5+oeVo@1aMakt8rAc$V;ZSH%EU=vPtO^O#qZAgb zl=PR|(Uzj2{Dh!~miga&L71A%-{03oVr}UffD3bK@-!!`m7yZW8d(_W8rtDnope!^ z>#VW)oxo7<9oOB>2W@hHCNhN@dTTv5EyYgO!^(+P@EQI6QDRJ1yp6%%jrybk4%t3V zbh~F`Ka$h+4BV|#PmRc0mt>6Dr77`gpT|CnL{gGxE*;0=4SpZqZ4WR#`#%R~9n|9g?j(mNZ?R}A}xxP`jEImf=Zh-cTP!4{Ei)ms-nVZ$NJxk zBE5te$$9y&n9O!W1={`pvXKmq~Cr8`*K9}g_!34cC1C}UmF_^jSF?U%zR|fW1kwE z`2IBzs1h~^^N@Zyq5@qMW|jJ%rN-FhKnm$!H-nPr`ibyf%(uK0nSx8!AE@+tc-EPx z@&}y;Ll<^V!aXvzAPpg=)Tck{%xdZSHO+0D&q ziT40_136Z+$HpKeyeetE(!S=l{Rr#PbG4pp@CH(Uutvd4c$WP|ISFl&hq+MS3UnHPBJP`Rz5MqqMc)4Z<`69PGvjth(Md%GJn-Si zU;>)Nf(I_ML?NPJKaUpO+TYI2uP4$?s{QzAyz6TECSo4faWGzliFl7`y@dqJi2ZU@ zc@fI3-Zl46+}My|%;@YTr^%`5$b9w$;JUb}fg0CZ>Dpv9cU<3EO1frtd7~IYYfovx zIf~O3Ct{EUNSd#Rkl(^_FS%0%w55cvfBa#qW~*%zY_;QkY~~V`)lcqcmH(s{WS&A% zP^1bsuEr(&(t3JA)&$n#?2~&!kU{#wfQw(kQ(&;F(Y3PDtYV*jq@TTexm9n(ykv0T z#NH-oFejDB4l*4E(dm8kW@x@mj!C2@nXFEyg4cyU^+J|n`AEIFTI~AKJWQhX!e`Oz zp%FyB(Mx_u0)2wFM+!XdhpZyKF<&$XmQQY^CMFz~nlCCUYm*c!CU0(Y1aFPO(gF%d zYxxUa!0E^y#|dh^%0aQPw5BEwhpV>31?Qj+#|pDdp^JBT=pK-{oV@SRwF?fsJ5v|W zu$}<7dw0RlUzern7f84ct41rb{sM`qrjyLZaIrjg&3WSE)&6o;KE463g9n<`@Jr43 zj|>rk1s3y87jy3G^}5~a%)>;ymF@Cw? ze^9z{j$vHXUM&yF+3y4B` zY?}$vX(n}ToaIDiJ1Bq*|azZ=^*FR87qZzIkIm2?FIraG2iL7ru69+@n#E zp)$D-bcXyM88{@h22(pv;{!n+11CSZ-Fxj+T93Haa zKCR3tAzDs{=CwH<%a!t%#nf@xyKu9(p*KzVIRng4a!CL$G6zb);<45 z(+@P7dH7h{CYkQ|F57OB=){~!L$&P|`xcvT!n=)hfbj0|lGQ|8X(jrmRV&I*n>nyu ze^dPpwnZL1QMHK^+uB@uuy=Q?JOd@~Pn|hyM@JozETE$s${tk|4}Y;L@LeI1`yRGe zd*jFB)&rAS+4CPatL{CBcZXeM$GU!4tDbeJ4cEZHLH)k9NVxgB@1fBu#RVDv1a$4YrO1ahSN(>g#be}_QU;Z?L%^Arlww*RuOxed|na5 zLPEsu^czQJFr=U+Y@!K{`(bqQ99+7PhJs^|0!egu=qrx(^hv+rK-G6vTl?|Uj*_Zn z{4+A1E>LC%iJ2ssA=uyh!+9Ts;cuG?u4@RCM|$Uo)+_Vpaqrgq0^cbiLTchCoVk_s z=;x@FlLnT{I$5sRT>1@b=&P;?paKkYXaqhH$X)+lJARVnMj8svEC+~$f{_w>#}7(U z--;V_D!nVWwZ+s}F>b#D#t1`wiV1E_lP|V|)qY zl3nkS5EmnTn|&-zbJTMP4yC|??q_xO79d|yOpe1fMhbe>k#jJVHZ!uZ}e-7@ln9Oy-*ucev8EY*6mPI{~_m-NRfFGWiX$M7p zL66nfpi&JgGC1~+KDo}xKkGBcKei>43ppkxuZZ|a@-VO;1yOI&ZApI7Wy%%qOZYFx zv-RNJxAtFS5Acm5AoZvjFx@XBLMjYZk*x_CV&3Az4HOKF{>;?0tW9N8kPLXmv%FsR?>0 zR;p=vFVG}F2V10t9#RtfxkpViuB!_Z_$8G!RR$hnEJrxrapyAbY&XYKUO3ya)n}Jx zBy7z$LDXd>g$VI``+OADcBktqet!mRlZ5SC2tk4>i%CGy$-P0}B4vvI(%~5i=5hMN zZs|MNR9U}*$x(}3CnC1`Mnno*h(NUaa zTQL_nABtw@ILG;bibic9WO-?r2W`nq{{T`-d){6i=AeocY%Cxn1T^TA6bambCr-zd!kV|_tNe|-Jo7eG% zt3Q(6S1)f=HR9^(c;H%az{!5@AUCHjOrffs-O%H!C0%%rx=q`c!40tdL8%A_F65V{ zyzrN_^gP|-KXjj_GC-CB^faO1P=oD$7?>tWGc(#1$Is6BuleFPuKuDj%JzgwKRdg$ zdnqg%4xe{-c#RCVh+x=NidHC88o$Y1whx0_U|qsw+m3^(lRRJMsx`{pD~3ZBO7W5 zDrZji*HqOdnr5~hijRs^&Tk;-iGhlL{#eDWHyV+ zfc?|UJ%rfED^W62T-$>2&exaNSGj`&HB{1eVSX40|4F<_*=aX9$ewT6J%JtAP|Iik z=Opncbrt5%d-<}{nsNI)^u=HGB7DeB%f7UosJvQH`A~5Q<%s1zh44)DY}-3z)X@Mo zHSGe1pdN;+v*lJG}CvJy7NFi_64Ot?@9n1mEZ33?ruhq4mB9t z-rsIrJBCiHs>t1V*|)ecmL4t)KU~hVfMquViZovm(Naa2ko>b@c1)dpFjR*#Xz*p$ za%k97uCK4Z8d0IzI`zB!05T@PC(0DecOs5XvHi>?_R_9vU6?LrrknYm0(v9^i9#jIkd5{nV zJt8XteCX&OThbi`q&ZZ{Z>H?#WIs#^Eq?6>N!S2!NPIuc#Yjpfi;wr-R!@IQ7V+(K zPrMmOpTg*HFa5S+e}3!RXt7C>m16GlJ*o}Wb6@=QeuClQtabrJ>Oq81AUY_wpt7bK z4;#78{sx?W+nua63&T7jmq(o;pjHGCK>}3feEvi$-M*q(?!e|pIi-vdy>VKVRhHw2 z4{|x6`T{KEdXr`6y1zHRpcXSnGmA9)krDNxJfyQ=QI~mI}vm+|yE%Lf%(|Anb_<&oiFKR%-`J;@@$3 zPWrMcDOs@8xb<&Vn1Zk)5T>2tW$JAMJUEL2=Zu|f%J```2X01H&PHHA((OmEbwy#F z7g{grf5fqze3!-Z^>eIzr#6LNO@CL&xyV*j1Hj|n+izruwu24hbHx9mUzQFE-##N> zU&N$sb!o?Z`5aQa)-7uKwe=0WZYC#b4kxL|k<0pt3^<*FwPuu=4Li(z8*H+}o99*j zrm=kYGmKk z$YMENl?)Cy^h*+0%ufec-wAR!2F?VtFr$B%ul$N-poECf?4qptpJ*m*UoHO6zS1b6 zp-HoR3e`_<&DpCpKwd6Oc>ZOOP>_!ci$zHXiHQkt&RWfQykrwfibVvX()$MD6_^J1 zGej&gq%@03$7{VLuo(0w+<585K6LQuP^R(h^)oWSv5SBb9m&Nf*b^4UGgd(gb1Cg8 zTKC+apnHUU0=dIV=&X+1OFZeZpSy2Uo*m$HzK_o6r}E=M?$Q%PhK29T|NVFD_~4MD z?NV;0&M3^6n&k0ERM0aiOa4n|IEeQ;bZ&qnxOd~40N3M}XgcZtI~7E4=#E*~zG|e0 z*Ert_{QqNojlpzxENrQC51o2~AAh32LYE+b!1Le0qmInae;SQdYjR%yspHk&n%*`sn%okB3wpBmx-; zweLB*>N`|yY^iGk0z-SChhqIImXnFi0yFR#{$H5*{$J9eLngUo<+%2FydrRWbFJ_Q zoL<2KcCf0;hyue|Vj4o3w!L$3KANyb>foTuSp7C#t(5boZNoWp?>|9p-g84)NlkuBpRe&Oz8@4T9DA&~(P!MvW3bL4TJH%hx^@Rqc3i;OaYn)XN`>{qm?<<=62US^oJ!c@RRCgQF6>?>@Nl zlC_4bbTAb|0P+7L9OI;Hf(Rrq`y2{*B<0WI6cXR$N9I}~2DK@cWN2%~i9hYVy@dyr z%ld3mb^Ef;zNYlAD-?3xbnz(ph^G5^Fu<$?=Qn@D!H@U$0-5bT@Lq<&_y)_rphBoY zcaCd}%ZE#`0%$;VQ;nv8KIC&c`hSrT;A_xaOjnRt@=yoSS_ z;-v(29>MYCH}q}I5))*y&44JVn<**lP5C+psv+qiI!9c%;_KR?U##C_Ln6%-5z||sGaGn{VvzA5 zqrNe3SKRs=njiY_^|(=csDqn~Pz>Qjk=+Qw?5M^jV6V%1hoM)=!tAD5?! z8-s#W7@Ly(DY-u;6iy1CgS%yxuc(lZ?jTdQotr&wn3x}-%VIe!)zO&vwZT32khzg3fpqhbs8m}jZYI4;j;?@1DVA*t(+CbvX1?FjoO#@1{^ zWx+%5xKt zoMPF2pz09W&&(0?wV*KgL8O9ImD=dt4AlGuI3(hpk*-QZp~ixTg77+)pAr$YgWs4W z+(OMdg_lr{2@sd|FYwTpL+kb0&?T9W+>&XuKDh12?BuO<##rA-8K5L#s{Ox7vjdYB z^-|Q*7R4?FmHCP8kHduA$*hcI^NZjA{;8Uw-|_c_N_!^0)4ZT zPp%m~G~NH$etS{{>5cxksgGC}`f)>VkYFjG&n^ZSMe9P3s^q}-O5Et+UQq;*m}Wna z)|bKrH4ZZs;?5s?ENCutG3r;Ao~>m3qU`V~v7iJ9{!0)QMpqw{=#TgenhCZ6iwn@dg1;UF zTp>MTaG@7%imf3c9Bv}NK6K=X`d(lh-SA-gU~dQE?`7muFFv?mEjE~pV_~3eFJfdn zgswOJZ3|`lO&`;Gy7VdCr=ogjtwZ&>lsAs+J^8OCoEnS?y_eLR$9}JA|Sd95`8RYTjwk7Vy^Jo&_DI7Is z3H)CQgf3HmjF7IAZ~Q<`af`D38q!pi=e3LfWl_7q7j?S@O?S9_=u!+>_HU(|2PPo& zX}({w*?TF5fl&c%Lc2ozX&fybflcwfoqR#t}s zMR$4mP`5E#FTfAu!-e=hJU+3xVPH9XYb#ZP036^Mn?hlf%EtHnUoAk$Q&*JvGY(hw zR2fC}zjy9s$$f~EoZ}e2Qbt`>R{|9ON;%4q7H^(x&(UmEVl;ZXQfw9RM{aq?dY14f zz-C$}c?!3*sp;F^XAD+Gm=e4ISy%1Cu=te;zmSY{nK2oY?o1j^Y12jVOzbSk7$Pf{ zNb09?v{iaBWl~3F|55qw^4=u+q$2c$_kXnFtO_NY-nJ+FLu&jtRd$V2+H6;2H@?I9 znLyiWCf^k>u z?{!+{Pw(g`yhw6mBv|0g2%-HNjr6(Q%s)>aFs3?1Eo=Ao`%Y7sY6;~j0*=jfeBc_< zx7~~-+t4^I+{QXQkX{&92Y8^^V= z1ZbLcvt+L0d`q}u$MwOHezW{0vjjVO>o1FjWfnH8_1E&kcX`Y_^aab+8;$O>$xUOi zgT#97Ibx66;G#|F&|4L#|CsO7{_$GUqw0@R`&a6~DaF39udK3dVoIHBw98@YC!vnF zg16gr=$wC5@JqZte}^A8f5!3#jw_G1oFo3Q+)3&qa<03pJOT?7F03}Jb+c3gvnJd|ECR|RJOT#e ztA34(yYIWxXrCv7CaVdy+};(a7Vigk9knly0h}2Ei=1jUjq(XDdcV&J1x{W{ygAt% zHw61P@Ntz91q+Zi5<2?~0xO2C=Mw*t9rvG*_&)ia*VFmwgf7yD+-AGsyDV~>f`2LH zst9gTUIq%227~b-M%AaA_GgyJJd2Q8rwtdnQ+ghU!0?8|$Vp_obKJkZo=T721MG)Q zw1&7*as86!&9z_lPsxvOlsHKcb!qnAk&=;_awl`{Vp`_6L!j`V5I9Cr_UR=eJNt;x z{HeDQj43O{P%m!_3vIK#Ay^S`7Zq{X?Rix^qVO28zvMDYiAfxu88t;qUEY&>340$C z8hr|5AHA%K&oF_1=1H;}RO3rj|1a~2*PMOG!Z`=L>p|$*M@N**I=slg@*MvDH{!mqGPslVDQizt?U2U(zN;>zlZ2D1h`TUK~yRb_>i8aW1MAtk%? zH1)6Ti`S51oQ~n@_7KtSQj`k>nv)zM`=!-WwdO&)KVWz}^+!&*q*2IM&_3%VNrJRJxi3QrDbuThIWIv6Ia52hvDVX4u zTTP{M7^)WworgCt3e6Wo8qTh|L4FAAjQS8;dxI>PZjcqHLGcRd(MKcLI5)uWb$j%l zH-YzDxDd1yaBq|sJ_He2Ph=Diq4I(zyDdLh95t`a)gO63v<$T^Lg2nE!^g`jWXY?a zq^X%|Q#s8h3q+AyxObA;e~X^GSgf{+<+F3>Ik>Hg*>taYMK)KyCiH5IP8lBu^auWs z|Gc`0@4a?=4|x^9Q(I~0n-+sY1@ClmDc*YBe7&(XKxBi#U&%=n!GT8_fGi*a$BmRx z4MAv%)U(5EXySlk9Nl8oUiikZw50(gacgcntR{h?uivbqmU+a>aFAzPUCB2?ge`3> zJKpgGWW$ji28S5-Cdd!Ej?Ou<=Og2I5NnS(;s_kHLLeRZ9HIvGzSLg3R@uZasP-pC zDtSTfAfGOH2py{hQ|m<+`O9jjB#VTV&O}X$2fmbB2A;|hfd$!|bFbQ}pV$@oq-4#A z-S7eonQ&fyXG%of$ioBbSjya$SpImJYBQ=*W($kFv$i3&_6dste5=u(zbNJ;y@~w| z3(D0)iMQV`hh1`?vmb@{U6b5yAN-xZSy>Xp7W*gAsS%z%?!9AYY1X#F_EuX&xgoAP z#PEA25p)UO=HT?Ug5&rD6yo-EFaP;GhWC*HOF7(jN*AB?HnJQAvX@}$O=*|A*7N(U zXCZNKXDvHwQ<8{dP@WlcNlB4ob*E>46IS3eM7uzq#^?-^HaFkicz9#%MBvS*ek=Cv zWc72+2p=@WOPw6?1=D?V308ekXA;60_PpX@v-e6t^|$kwCn`f@!cbX04$MQ+Ys@)m zlrsIM?&4d)V%KM|s777d^sZZnF8_;1+`(%`+6?v&ZF>F!3VcyCXG$6xXG{XUzl|q2 za=3Ngpp^+i2kBL-FsC=6F@maUt(6cj1ffB6WHFv4NYqqN_9oZMX@QJPu8tTtfc+jD-8Q#4`h_=aVT zBh=7BBJV{LngLwgOKePW$iTTkfz8lulI%!OF;+^|vU4DJgs5m(Quv!93r?J`q&hnO zjZrBjWL<_R_q*K5s&>W=WGQaAG2*7!QeG6i=>ps_GXWBLJzo;w3#nuI{rimSWRvrm z!m)!yBMRuBrq4@y+lUizdxazEB9Fw#j#zo|L!ljxlgTq28Jcyysu>`-nDYb(|j33=;vQ|xE&oU9n3gE`B;2=!gQR7zN*N4k7*%EIev z#bEM5miOmFIF|S<%=xpCf-LW+1KePo-rlh}f&`#kz=-|REnZAyNpo(y3Z^Ds@ItE4M7o)mOZ zX#>@G2JO;!=R|A~o&#Rpt?QRlU9$sbCFk}MT+|h(8iO=7TtVA9=ZG}^_wiP?6L`&5 z&VoDpUrbo9w){CW@GapL3CH7R#2kpF^n47D=h-9Yq zmwWsMt0L0YcM1{@?y|{kKX{%{IE|iF)RgM`SYvK}6URpoFUA;nf9Z*oac1OJQAg#*#1GfK z8GWtI6m?-9XXjvAiF3b`C_dFd|AW{-Wx$XY%W&4N)?xfn_OuUl{Ov`jDQAOa0Y=-2 zx0J2yP86DUjOaHt=%a6TL}pqzg|>13?-5szIQsjtM};HO%G73?hwvu@Am<)&c1`i> z@~9vY6ttf97et9?TFyT`8P6y_)%cMuK3K$GOC0{x`Ftq=RYIVuE>1X>DCBe3+)X+^d`$!Raw27Qt7XxCU>O7#d=OL~zd`ReJ}8_}iNTDqNyB*5#u7 ztyhqN*OK1+b4mb8_d@=ZG$uaiU;%nM3>~Y`AVox$8lX3&uszC!dLw$}M$}mf#;xIE zN~rLAq>%5QS_@?)OSGq$;%%EhFViOWD|lKvjf-NnhP~_lAbLBC(_d6bScZVIlZ7vK zU&Svhf-Oa3d6e5V*>n{V=)4H0k3+F8K-z5)@WtL~xcy7Yr!;%zT%|~O%ivXS5g*(_ z&+ms9_AK}dU$~@hB(N`Bxy?=_Alm_p3M9V?(#H@6rr1gv$afhNOVM1u*q>}yLv!zN z(*x7&qfwM1Z#J@RvWHf6OXF_1XPj|BDK0fk`nB-FmGo2adq~53amzZsB9Bq6Q$<v4B4nR)iS=4# zh)bMv8wv*WeAgHBnkGYeAgIrW2)v0nbug+6S8&{H<;n{UhZyTrVWD_6g^G6}cK^a^ zKm4XP#OYdZ1-}UCro%O`5wnPRPnYX@C1N=6aV}A4%$?t=Fe-5dt$>*UI?~w9oLeT_ zf#@pKd(&nelJo7)A^eXrS>rdMtAjz>2*YFzcr~#&-id#emlX|zp6@QeHX*e6gkE(l z#FcJpga-6#ruw9U)xRzVL`fDSbq>gWvcpG%n&qgq)~Lx|KIT0gjJcvf<_O@3v*c zj}xJ9o&H!%&G^h0s~4)tio!~HO}VGAPvX_VEOl;3!Ef^?M^n?+Q>hg)+yrneeTs(df=vj4lXy$91yMQo<6pNVBLx6B(6|r$P+~3vVC?T*jRF zI_=N7u-skQD1~mwl!$8Hpb96PrgrnbYbPjo$ZX>6RbGBGNZ^XiH3JD*IFfNfuKu{I z@A6ZLbh90gt749)#0y(Kr zQ^%i#ziAIR$TI{atMMI8I%FAB6G&Kw^e3N(pXaWirVbF|@5>A>S4!+Xi9SDg$G2|q z_W8SDG|ZITSmphJ-$RiO8W1ly^3E5_@~ESU6=L30jIPyzvvQo34ov)0%B?Xp78%^* zVIn*jYc~6*S5M1F;G!Wj0TTxlZ+(tFj7C_M$HlEyGUK569eaFh$_qcw=g%RtL!}&sBxSO(s8s410kS&x)$7sRHW9z}#Rgm;hEz7IfAwkP2AzsF)1p}%rrt&t&n-PeaTnOhC1PIVkZ`?@) zL9y;cYuz9kmRxiuN@C%o;65SLkY7<=zo-=2myIMpmPfma!b$m|Ne!E%lI0LWrw)-m z+$6f$9);L6gu5kLNIISoPCqPgk8vY#oLP~)F)8st=$u?$sNFxe*i0k|n4yCzVEERG zV0775Qm6=PEWk_A$Wk5`Pf%!SSXu_Z!&LP6KKYac%ffS)Vb^#P{?m4LB4AY=o}0$z zUwmUrtN3|(UqW*DW2inu)AZ0+Q*!#;a^07e$Wq%5w-BDi%By=+wMH}(Bt$7560Qis zJi_p*U$F^MW0lByoP+m*m?D@`isb2m*VJv=haq{Q$iw$EFK;NBSfZV)rdqhXE45}>ufjX3L1hOqv{-FSbd2M zTF|_8d9X#c9a^;^q8>NIiJQvc8OrR;YF)}&mg7araOaQS6mHW;yJq>+j73B)C`0q( z^GccE$VSB%<$wj5XK?@sak*@k<_S^-%DmgMW#e>wOvHobvZ~sd!mFP@{c|%2pBDKO zmRT0YYfHS)YLkW2QmK)8GuE5KlTyX}lUM%7!1n-2ecG)2X+kVtFXZk^{GH-X%MWH+ zr_dX_)#K-tfln;Pu~>y$wcX4q4-ZsHf_5EnQ=>D}#iD1v(fN#inn-C)*bBW!kmlw* zt7m4ZT(Lbu{P0Qwm0mf70xhNXa~27AnHD`tHioTchO}xGhr&8RiVyrR6eHFvKBl}( zLI_e**7Eq!#<*1%9-|szS4k!T&u4^cu2Ug02|rei2MlREru?yA_)F3|n&GE~6;N;g ztJf5)Ha%7jftv;q2l~c4m*#>zrb)Ui>P@%zPJwxZseX(@ZHP=kKRZz5FJ1=dZH1iS z4p0R55r6Ks8Sx}6nrKiIeR6>7LCkka`vqN!M^@)X<+U}&<~yY6Xk2n~@vxBcnKdRe zEdsy8*B4e7nKd4c%uk?1@?F@mRAVdQNSV2CDOA_<4Up7<95v;~?Vqa@>ra#iEUWpr z$tYUw5_(*pI>7o=_Tt zg9E)`rn6RAL=|U3YK`NV+HqSY0H=NNX2tHZq$x$qKeKuDm(idag+J)tR@df5cX>r( zpXn(lw%*a@ja2qh?!D|kQw&tM8<#chkF4Kf! zwh|s?E)kU_M{-Km?zkG%d3Uh{z2&+Ggh4myZ>3ykxBRtUE7l~`%=dVCo+#OO#w7(g z$GN`r7~cLWfe%kU(;3$W-(M^-I0}eA)rTvVBcZmI(L}EtzZ}sy(= z_@fb_@d4TU&syoQk+(A=HdiE^-9@DA3|!CBjb{(cnwx_un?h-DKXsDaE(x#T8zCg4 zypH=@;?%n*&YCZHJZjW-FXms(mO#;E*gG;Y8T|2Q3~5Aam>uQ*uE=ZOX5>MAI0^=7 z{K;U%DiNb*M7T4wrz)Z?L1w<8Xj(>5-ZHPkNHwBIWQc{dV(3y4u%*Z&hr~^Bb^FJk zmSl!llLd67l$1&uQPS1ErG!b4QDE!br_@0)?1D*V8`*d zsT{tD)-oC#MY3DUX)9A|_KHBk5k(`8^x4btK#OW>#^LOf zkKtYUQ_BtH1C&tj$gwJ^Ur7qI2983~oN$Jr1wj{VA%?y`=6zB&t1kmbTz_np1ezlT5e8E!AnO> zN7KA;Htg&zMy=vTs)E$N{f5&IuNpC)&quRuiwyi?7ti_~r1de-4re}UwUo8R4{!qr z8wGqV9T_na?-78axQ-0q3fKo+Y-P+KY<{b!=cR^oBgc%EJbli*mFjWxL43}{F=T0! zQq04w*N1OUXW^@cCZW>Uk12!tsGO;IYY~|3Usb61h_yX99&G4)=fpO}0W%IvD)8Hi z&yijSX(zV@hGR2|=5h)YZDSJooFWrwV;3STj3ZJ}|HS{v#9`5=?zS8QwQIm9yA1Ty z%nv5Mr;z=K$UwM>H9*dbPVje#{HZ}eS4u}=dO!+JY6rSGR>trBGz2vCkPEk37Iam@!H_m>EZ3lk8t1q58G91@0j^Dyzvpx*{1L7UzOnWOl9e7eRI3BGb-9hI)_e zl?LT9_Zme7I62lzI0Qf4CZB6PFf1bet>DOBP>LPbq*{lvt2=4WHG#QlJ$;SKX8xRr zHQ!(NX{~oq;d=y)7IL`{{J}rrOUPT_2{x#2En*bA882Ymi!9riY?Q6@?+a`8ipAUlXA3M`%rVyM(U^#sK3p)Si@1sZw!*2#LRneyN zGjZmzzEqfz!s)gWA=|tT&Y)%pk&iWJSZ;mzW0awezB~u#C9;0%k1QloM|_Xo^+kNE z_!HIVNeN|~MY!G_W{wvX)6VJ{pkTK|iko31Ca?utp5EB}7R)5!Re`E+P4O>FRSh(^ zoA8+5w_S2Q6Z8`6*51Z*X{K+n!xNVk&?+Sp=5P7V0_eg;5XQxCgfdFZte~fx zybJL2zpt;Ou(v(R299mTdHo*@JZ`sE#y#zyi|W?Y8^5^HH90zf2oO>4xpG4I*VQxV zTE|)&OUQb{A!MyOFF&xR8y*+fyl5~lK=Na?t@7PJhaPA6G}~p4p>8O;e*dw^G}Wem z*ZYpEzrU29%=-mxmG)3U9~wST`RaQ+qm#SlbDK}+xf{+i6>L>%he?m68pI*M8h*1W zxyrj{bVmSXFn`_Qng|pXcqFJ_Yqab8{uo-M#kK9qA>7^-(Pt?hIeqW3G8{e}dK2#E z8&sSk@A1nqCx3$kYVgJ!-iyrJu{(76nRymi~a1>Z7{G2CoPCqCX&8_N~> zITPK`i&YAn@0Z)}88LiF8PK76NEEqE^sIv?<~tvM?98(Uw{2Lnm)w8Ir|8+;Ae5m= zA3mLTxdBM|l9^?BW3ECANvCly+RA5UhYK$svnE@iFzY`?Ah)K=v?x^?LUz)b_%kMV7P*lWBl>wb zKVJmgbVhSLts+KWe&$c5T);K@O6ODe5^R1-zZV9zOfVyeueM^Kz0`A4CRDj<@u_)Dg-5v1w~_uEL_l+UZ31@EER zC|yyxSeYisU2wXHSO`cm2&{qXeF(_tNs3qo7Trm@?a zaQ!GlnuC9+s6k6w$-SOuFq7FU(Pwt{F*y~Tur{PT z;Fy>bR^mT&FlxCqN{(%v1i&EM-f_iYWyHg;4OKwWFbey0IF7D#S-gi z)nBob#;AEjA(=!;v;LmO&rs}W3PSb7)oDlqRT*nHRc(+h4|YOsKH|AIW!Em)*au~! zQ_SKBLxh)YKj}T7M-Q)Z?e}O>)}IXZG!irHJ@xoBl4dg? zArV~hLrWBamvZ?FI08Z?4A?UaD7i`xi+=1?{NC%}jVb1y@Fd^$`Zd~ z+Z05S@Ul4(*Nw@<#%ibgo(NpglX#&6)eRchRpB1tl9&61Kl&iKTGg{n9%7e9T$Vv} zxu!67Z({io=SwE1gTzSR)mH!Zx_JL^cHx7S&=Gu-C`vfh-+->CgQrB>ze@NWta>rO z7b6(xj@4C~)e$_64;fOVoOF5Kre-e&W(>959j!RWj~_iFKDU@ysI&yG$;+z_*ZW0V z<)RF6R5hM>y3!XGSP@2l46rI+c$2%x!lb0|M|PaDFvb9ml3~#R;2tt> zcz%@&O;O)QW@Z{^N*F+|I(|uz8@6U9dz3xuO>$IA%0oPk*ej=EN*j}H44)c}q(qY( zrph^|C^{X$YtOM@JK5!}R`a{6b!Z*(vm8u!9jBHq0Unp@hdQ zHH7IJvGRCk9zBJ+o2O}!q!*jp_bOW4Nc;=YRf~gXJwVBGgWr{RnASt4D>C$)#Jha@>X_i z53P3L+c<~!c6F$*@%?(ku#V-W0%jw;i12cBi_{X2TPM#PcUrtD!|th&k~2BTr(%Og*ZT=NH%m zJ3aS4*%P$?h<>^Fdduy+K3;M&XJkn6PjFYx7G@^U}+D*cWs3 z5o|B2oU=0&)8jF|P8B>f&R7*r8QIT~AKaM7JeH0)(7}Ox^5=+AP6Nu(66|dLv9K4c z73D%Kh6bme#s9|i&@!}Js=boH?P&h^9hIJ+UZZBz{L^W=kGgQ;E`1E^0(%71>Nxjc z+WtbtPf_l*;-miQryT7#i#ZU8$BQo6dSX9sd9>M!j~6?=63Q)<6D{SH^m;)#pECsp zaAI)8UvS!}1}yw=aw@E{Rv&F?FFDnn4eo68v`WFoHfKO~$0qr@s~Yw)LurUm*oO^@ zYcYp=Hra^9*pA+dcZLSeX4w$0K65$o_+%s4F>tgLj*r`}a6^D?z4FxQ<^Plie6m@| zxw%DcVoc=g8MvFBpXQ`%i^V_A?ey*CzU)}FZnRmk)fSm}X$?EF)GI|1?3KBa^@uh`aEDZ(A^J{i$ln3SbW z=J(EStCD<=mJHkFDq7fd_Rdd9#U0G+s;a9JeHShNBktJ8X{X#U+EzB(cJ_8fu;>-Wehw#rrskI8$p7OYZ;;MV+xdte|94rf5^8M&G%5Z6a z5WWAdVZ>%nB>u<~cAxfdk8g*xXKQah{#SNGU??|8kL{gdVUb+^V6^j(5!mc>b}#kl zr5@?S?~HEgVI>W_`#pLjg8z|>t#HZSLXj$vEN=Ye<(1Z!uo3WZ{2pUBT{Mq+S>wa# zQ7kk(`UD0E%r@}hsBVC;Uq32Cyg`ri3!1Y!SC-)(ci0V_?n~en z(dS^d>Qs0W_@A2Y|K7V3iG~*DmFc@rlBK#f%dzw`F@bxn{%Lpwg6Zs{2h{>uetzp} zA2+7_f=WeBm_Up7=u-zS(B@JqdW*`ae1RJ!JKQhCtF%^#Bi7y~6^a(xp)D_=(+N(wb#|>M#j(JO88{OhQ4%5T|^6<98*82(LLlG5*&@>~xHT zxTb2hrsdQKyc(AfpX^Jb9`hPCZS@YUDWjf}Xlwv-4-{?bs(9FCLepUSz}?GRYG7c< zl!wHzKIP?K^~<&5U#<2P#WT4{xnC7>Ja$|BdUx(W0$|>ee4)TLA>E{8&z{AmUj=`* zr%BkGZqXUNylM}A=mCDKy^$T)pQBdM)M9N@RChujma1YvcPHTYYPl0`>4)|3mZVZ@ zXlgod_dZch+h2L7g5%-dCKnITB1eznzxFG3}0-QF^6Np5f5mr z*Ke}mcW5}*`gpAUF|Ovwmt6a3QOZt<7x0exDFK2bmnk+wVGlr7D=C!Py>?u76g>wT zv)i}M;Q`b`q7mw8XRHbrmyj%9a@UTds2~J%^z*S z1u=2$EjH!z^C!{L@^pAWKjs}f&Ou+@sv!&3$!!Gt$@H4a-+UCYZW|Pw5&Yfv=I%d2 zMUR~T>K|w*cDUR60Ki5}oUOw(m}N2w!Y3!S>>Cet!2ltkkNG|Mj&e*9@lE14fJVQ&pL{YP-gxrprE*nE%fTdR$`(|rS&!xM2nh0B)O_WO=)Mt?}db-;?c)*FsW$equl+xG04` z08W`O<-9f52MBxP)w98XFT7#X*a&>u;G$O3hV7s$8A(kbA;U`sAlo_bgHY0@Dw|cz0E-JC=>fT!NK=!BrdAdJQGlgkno#hJ zDMS3A(`i)KZ<^RxbqavwUed5>-Ob1#5BjS35Zk|^#>U1re*F6suuDoxNU0HkKN0y2 zxm-5;0;vMPXMjwxJell}o0CK8zs9KSyx)oTPx&&N2|X#dybO19V#+8lCnvFfR+srD z6{NenJN(9X8@0{{TM0ok4|GHU@C(pSzG%$UEat{+ZP*1EoOwt_cHB-fA6t#``dmh&l+Sh&$e`9VB9&WrZ7Tw7m8VwY@aaMZ57vT+W2g54iJHlJNSv_9N+8D$9J0?4H1o4dSi ztl)&i#El4}D?3|0atsU%pF47uzrAKLE_>^Ab8~a$IxIl?FhHKO>z_Qe7H0Wd-nD=6OQjHzO5c6-c*H4kNd^`VfT*fo0a3g?TYNDw;1ey<4Q#a8WyjW z0mYK;t7M&GtwX;XL*~1WAUOW?;k@bS^t>m%Rd0n}$Ean~eRFf`daBfiuy8{1Qd8Rr z)@}^;)cvrBHG(!aDO| zDqtUhY3Sb@-Z+&uv0RFr?#@fvNI1YIr~alymQxyOw-*jy&#LF#yU%Nz*@Th@qJ4=OdAGgl~Ox zIP(vpNo3?;YG2+BRBXEnIoIunY)MP$*&q3exua;_D-;o7_}%5Omp@!1qzFy)DDmqX zVFqI$InS`fh~5i)IJn`o_v@L<$3}E)(1)>+F{a%zFnW8{U8XhE9Zc#u*69Nvb$-u- z^Qr4abrq*QCH`X1>@GR#2jm@B^q8Iw3#xwv0G0=^j2-hE{S!``dw4lz;CxdT&h zeDb1{i%+!8g8Cm_n=x+k!ceAEsHLrK#^{m7-0(f7dqe8j-5oF_CwYEne(N2w|8=>5 zcl8WZ6mX5q)<@|%GzD+w%0d7DN3GYTJy-|)i;k2v^RBdBO=)|jO+Pf4y8wMpAK=V$ zZ@}tU{k2wN&`^7wOFmQXD_oGZ?A$O7e!=m%qCE?dL@Z#=FDQc10%qrze;s~#_8gcH z0-4OLtUwjN6MRf;YykM!hLip=$@{P#1Cl<~0~+a{f~^d2qk-<}J>5dUMFUn*78Ae% z{h-ZwtP@#!dou;F7uq+R+2W6;7hx<428!N#RXbfhc=w6UD}vcN1^Ms zn6&N<=M%;BJIqNg+G60t0q|x(ua~o=0+@~XlCcUW!gH-OY~Wn$E2ypXG~f0W^Djw* zcMwXA2AhHKMROF)4^O150_KG{cr}RaDCuqpvADEm>wgf$=lQv*5#o_y?KDs%IWiHWO|BdmKbQ&OpylLA}+QLRowo$ z7x)Xyrw$9PpN`7eX_+4C;!0xz|EH}p0f%yL|M--moKVt9Mk?_6psDa zCbGxit$1xYOkyw;G4`?VV>ul;h`}U#64Tfj`!e|7qxbyvUe|kFb6qo@d6wV${J!`7 zjPIv^fYNqQ?6T805pZpX0)7kHbx%S$?+b%}pO?Mfc)(l=^>^No@xD!_|Dm@QSHz*_ zpwk~70PC2~?Ev=)!YM1QPZabmO}Q7CuersC$eDW&Rq;Qr=y#duYY9pas#^P`EyAmo zb9eGB*yJ^4sB7FDk}onm14E%ZtEni$pH`z!qz-1MUB>i2Fq6jT8al*ii2gaa=Y==6 zZsV1sZH*@C+lxgvMWBgooC3fIV=x#Or;#$V zyTep1Pq9A}0*u5h;bCX_(3?ZMe)=XgOO-`bfG}tS7|} zrQBQf4$OD;C9jPVS`%p!$^q{&S2qwU&seqgvHl9<)UQG#XwyHC|TwM)7&aBdSw9H*|XWQ7a zl@+e&BZ30ox`GZqUqwHm5Y||-_QhcnGb|R{-}V`J65*K&iYvpX?0`ka~6h+4{h4NXm)2j(8=JcP<8F$u zRzkQ9tb`UjMHr|cQKGP@bv8DLx{pU_04EmA1R)C`9I>aY?(2Q34EIqMECLqjuwKWq z-MYF*jvS?RHQ<^qMe75t7H|fD(E1Y0si5En@G8Iej@C9dG4>74KK7&~gBI3?yt zCq6degh1E@kPJhbOpb`#yQ(Sm3H|*@M~a2CxwHUy;)(GF@rKj^hwHRrj}EDGC|41* zf|Z5KtHB7Zq&9xalrKO)xZ^wBUsQfK@~`(P9X3=B76PzGrf* z!GiZL6{NZMdLHJFCR*v!0TqA_puwW@Z_6hDrMRW`dav^(85ouIn(?L{9x-5mt|Vmb z=$HVWPt8`>bX%B9&I*E1DX=GnsPOs81H28x@<)k4cr8m0ayWNRX|~J!Ihr8M8w4@- z=qQ)NnJ!HcUO|*oq>YTaaKv#~kBe>zo#G8@&t2XyEWcnXub26vy!=59`Ma%<&xDh) z&*UXww1B>4j^M3X$tZBc$}CsdtD~D^phxU9FM3e=eM}iN$V``9f~gs}XD4-~LMA0% z!6&x6+Ysi;s7rf!_U>qE!+R6o(7ZgSZ;Z>M8UY8zo zsEY_h@vu_y|MZ`Q=WTO(V$gRyaObUb}=Zn&iCt}wo4@bNue!#cX} zTxa^(GwF=C9A7AqkMo#XVPld8n1U-;cRVxJ)J;iD-25cg^|>$f?eGU5I|wI_M>o$B zrm^8DCJt3Q>7=c1RF7fykSYh2hn*_Q7GoiK1lpyev!1m6o&H#1!XAS$5z5Y@j2jarl9Q5>`Wr%|kGD{Z$3c+wc{MdNmldbwi9?kuACQpz`j%MDwA>gq*$lgWHprMr zJYhijG(Vr(iEFXoM;@cg`L6v^r^P4}TyS+|{#7w$xup9j?m_*_MK_hXR^oD?FH$ING(=AA7~K@Bh2~p)5NG2Of|2ydxARR6}#tI?cx~Adr-we}Cu5FYgMH*?@HE z<8V$d#BybUM`Z>JWR;f#bR%r`pF@MO%1@z}nE}rHP*3j>e~#Bp$`VmtY3b>yC%XL5 z#K>kV(0-6(P0PtKzTnj{=|=783C^Hundq~qZ!n|5FtE3nE4;qI`$-8hr}`zt-=N|# zdr~IdkhQB`fHrZ*p@|pp8UUKgzmlJk5p!46kvu9Ii$vlR@U_4x&m!H@Jv25xmX?`a zXIliBk!1*WYo;=DlFTmrwHpA~IvhKh^MROeO)ZZF3J^p@ zqR9t9KHYh85c0aZS~iZ3-^HeU#0V8`znNrdPAsjJW@O?LR~we#QuU4{<`?2tTG@DV zGtI@oj=G@xuZ2$IrsCJ0Afn3b-7d_N-nsV5hJLs>Nt=V`^Qp-6>~ztnhI^w+)KU*) z)O-!wMAaDF)8!CLeXe3RaS^aa&w93wy6EWX%?>S99W3c3C*9rYk9dly2n!0@8=1}* zoMc+i{qLK>cI|5j1P7nm^(#8&8Wj8U&x;Kt3LSetEH1hgUiAmGI^19ti!t^3vsLzX z4z!ct@avzEacKIt)2~$+0{d8O7FZi|_jBW#=nP#QNc-J^)o-f#obvg@iakA2NLKpS zBH!>;osS*H?!A##o)U>V_$KeIe@VZWIFO-1#d5|5)K8|Sr#r1g?{+MS%V~MUSGY6C zf*0rwcU@IgLjSp$>~S(Y0vyh{%@TJM+36DpfBmuP9A(4JYai6KBi-0es7kh~VrqU- zwdFZSLZnCQjqMJ)CK=UJ#nqylnGqd)CuQ-{ipQI<(#ShSuxVTsv*lg2F+I%-wH=VwS!#NNL6BAusJenvkFW<1S zf#v4mnfqG%tgqY^NcVQ(%Ha3BETQUaDF7pA)LS8@$tjJjbjczxsY~=IUp6)q!09AT;P7JF_EeUFR+08{@rS<+)ZVxoHg>0^6BpD(*Ou)NpG{g zY(*<+=@)%fwyh#~j>NFu5q_e3TDLyPT=m;3+?xYCWwthi?SHd_^}*&jf(zcb3_jA+ ztu3L?q~mnicf5((WyAWi##^N+OVHZG~Ph!Qc`IA(%&CXc)4$< zs`y^kMOyuA^(_R-~4 zE>*<^4LAXUP8u+2qKS8E^C97mB*wLUW=D*CW+rm<+~G69RaX!;r*;Uy?gFioi|vz( z_aE{m?y!*zyth@K);&MI%Z=$w&y*%659xG#I*ure{838}zBgj>@dQ( z*1D-fIBzD299nPvQ`HM&tvr-I4h~`)8@jg7kT$M>bB=U&eqEk$WV?_>*nO5HlL3< zqV++`e~m&J(+i2j1l=Qv1S{FNpIS4-lTa=|UtT`lQ7E%r%I|ZA8P4&8gI5~w`?0?v z{AYl=JorAmEVYEHifdT@siV^}&L&f}UWW5XyYAvZoICZS{=XW&GnU9NEVS5%cyNbR z6hC$e5})BfU!!&>yP=Vh99-?wMbURI8~@aV3IwzQA!;6eKK-US zF;JA%L5Med|M#RqsGi&^B@ETJr|_sKdu#8Svhn^>r}vy&f5cb#vIQvQ|Go6*jjeg9 Nb_0Dq=c?(y{tqdgf(ift literal 0 HcmV?d00001 From c9dcecbbdf324feae4a810a0057de264fb33b759 Mon Sep 17 00:00:00 2001 From: Dustin Richmond Date: Mon, 28 Oct 2019 08:38:34 -0700 Subject: [PATCH 09/31] Fixed missing extern C declaration (#467) (#473) --- hdk/common/software/include/fpga_pci_sv.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hdk/common/software/include/fpga_pci_sv.h b/hdk/common/software/include/fpga_pci_sv.h index efcc4c96..0de0bc98 100644 --- a/hdk/common/software/include/fpga_pci_sv.h +++ b/hdk/common/software/include/fpga_pci_sv.h @@ -22,6 +22,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** * FPGA_PCI_BARS_MAX: * -compile time tunable via mkall_fpga_mgmt_tools.sh, with the below default. From 1f67d8e375be81176a9f672544d870dfb24303e8 Mon Sep 17 00:00:00 2001 From: Deep Patel Date: Fri, 13 Dec 2019 17:49:47 -0600 Subject: [PATCH 10/31] RC v1.4.12 (#474) * Added supported versions for BJS AMI's (#589) * Added release notes * Added re:Invent 19 workshop link --- README.md | 7 +++---- RELEASE_NOTES.md | 4 ++++ developer_resources/DCV.md | 5 ++++- supported_vivado_versions.txt | 2 ++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 91447488..8659e9d3 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,9 @@ Before you start your first AWS FPGA design, we recommend that you go through on ### In-depth training and resources Once you have completed your hello world examples, we recommend diving deeper into a training workshop or application notes + * Software-defined [re:Invent 2019 Workshop](https://github.com/Xilinx/SDAccel-AWS-F1-Developer-Labs). + * Lab modules will take you through accelerating compute intensive functions like Inverse Discrete Cosine Transform, Bloom Filter, 2D video convolution, etc. + * You will learn how to identify functions to accelerate and use profiling on example applications use that information to optimize your data movement between the HOST and FPGA. * Software-defined [re:Invent 2018 Workshop](https://github.com/awslabs/aws-fpga-app-notes/blob/master/reInvent18_Developer_Workshop/README.md) demonstrates a 2D Filter acceleration and how to debug and optimize your accelerator. * Custom hardware developers need to learn about how the hardware accelerator interfaces to the F1 Shell * [Shell Interface](hdk/docs/AWS_Shell_Interface_Specification.md) @@ -192,7 +195,3 @@ The documentation is located throughout this developer kit, therefore, to help d * [Searching code](https://help.github.com/articles/searching-code/) and [advanced search syntax](https://help.github.com/articles/understanding-the-search-syntax/) * [Finding files](https://help.github.com/articles/finding-files-on-github/) * Simply replace github.com with gitprint.com to generate a printable PDF - - - - diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index f500d1c6..11d7af45 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -24,6 +24,10 @@ * 1 DDR controller implemented in the SH (always available) * 3 DDR controllers implemented in the CL (configurable number of implemented controllers allowed) +## Release 1.4.12 (See [ERRATA](./ERRATA.md) for unsupported features) +* Added support for Xilinx tool versions released in the AWS China Marketplace. +* Updated NICE DCV setup instructions. + ## Release 1.4.11 (See [ERRATA](./ERRATA.md) for unsupported features) * FPGA developer kit now supports Xilinx SDx/Vivado 2019.1 * We recommend developers upgrade to v1.4.11 to benefit from the new features, bug fixes, and optimizations. diff --git a/developer_resources/DCV.md b/developer_resources/DCV.md index fe749823..3d28203f 100644 --- a/developer_resources/DCV.md +++ b/developer_resources/DCV.md @@ -52,6 +52,7 @@ If you experience issues please refer to the [Official DCV documentation](https: 1. [Install NICE DCV pre-requisites](https://docs.aws.amazon.com/dcv/latest/adminguide/setting-up-installing-linux-prereq.html) ``` + sudo yum -y install kernel-devel sudo yum -y groupinstall "GNOME Desktop" sudo yum -y install glx-utils ``` @@ -83,19 +84,21 @@ If you experience issues please refer to the [Official DCV documentation](https: * Disable firewalld to allow all connections ``` sudo systemctl stop firewalld + sudo systemctl disable firewalld ``` * Open up the firewall only for tcp port 8443 ``` sudo systemctl start firewalld + sudo systemctl enable firewalld sudo firewall-cmd --zone=public --add-port=8443/tcp --permanent sudo firewall-cmd --reload ``` 1. Create a virtual session to connect to - **NOTE: that you will have to create a new session if you restart your instance.** + **NOTE: You will have to create a new session if you restart your instance.** ``` dcv create-session --type virtual --user centos centos diff --git a/supported_vivado_versions.txt b/supported_vivado_versions.txt index 5b4d35c2..b8bb41c6 100644 --- a/supported_vivado_versions.txt +++ b/supported_vivado_versions.txt @@ -6,5 +6,7 @@ Vivado v2018.2.op (64-bit) Vivado v2018.2 (64-bit) Vivado v2018.3.op (64-bit) Vivado v2018.3 (64-bit) +Vivado v2018.3_AR72667 (64-bit) Vivado v2019.1.op (64-bit) Vivado v2019.1 (64-bit) +Vivado v2019.1_AR72668 (64-bit) \ No newline at end of file From 5e9f4cbb3cfaa136dbf486d3d8fd15220ac5eac0 Mon Sep 17 00:00:00 2001 From: Deep Patel Date: Tue, 11 Feb 2020 22:57:19 -0600 Subject: [PATCH 11/31] Release v1.4.13 (#478) * Added Xilinx 2019.2 toolset support * Enabled Vitis Runs * Updated XRT link for 2019.1 * Update ERRATA.md * Add errata that CL cannot connect shell generated clock directly to BUFG in CL. Co-authored-by: AWSkhanasif --- .gitignore | 7 +- .gitmodules | 4 + ERRATA.md | 3 +- FAQs.md | 4 + Jenkinsfile | 399 +++++++++++++++--- Jenkinsfile_int_sims | 149 +------ README.md | 29 +- RELEASE_NOTES.md | 10 +- SDAccel/FAQ.md | 4 + SDAccel/docs/XRT_installation_instructions.md | 2 +- SDAccel/kernel_version.txt | 4 +- SDAccel/sdaccel_xrt_version.txt | 3 +- Vitis/README.md | 222 ++++++++++ Vitis/Runtime/xrt_common_functions.sh | 117 +++++ ..._aws-vu9p-f1_shell-v04261818_201920_1.spfm | 26 ++ ..._aws-vu9p-f1_shell-v04261818_201920_1.xpfm | 20 + Vitis/docs/Create_Runtime_AMI.md | 34 ++ Vitis/docs/FAQ.md | 5 + Vitis/docs/Setup_AWS_CLI_and_S3_Bucket.md | 26 ++ Vitis/docs/XRT_installation_instructions.md | 149 +++++++ Vitis/examples/xilinx_2019.2 | 1 + Vitis/kernel_version.txt | 7 + Vitis/packages.txt | 18 + Vitis/tests/test_build_vitis_example.py | 117 +++++ Vitis/tests/test_create_vitis_afi.py | 133 ++++++ Vitis/tests/test_find_vitis_examples.py | 113 +++++ Vitis/tests/test_run_vitis_example.py | 89 ++++ Vitis/tests/test_vitis_scripts.py | 56 +++ Vitis/tools/create_vitis_afi.sh | 286 +++++++++++++ Vitis/vitis_xrt_version.txt | 1 + .../cl_dram_dma/verif/scripts/Makefile | 16 +- .../cl_dram_dma/verif/scripts/Makefile.questa | 28 +- .../cl_hello_world/verif/scripts/Makefile | 7 +- .../verif/scripts/Makefile.questa | 35 +- .../verif/scripts/Makefile | 4 +- .../verif/scripts/Makefile.questa | 16 +- hdk/cl/examples/cl_sde/verif/scripts/Makefile | 13 +- .../cl_sde/verif/scripts/Makefile.questa | 27 +- .../cl_sde/verif/scripts/Makefile.vcs | 2 +- .../cl_uram_example/verif/scripts/Makefile | 7 +- .../verif/scripts/Makefile.questa | 29 +- .../verif/tb/scripts/Makefile.common.inc | 62 +++ hdk/hdk_version.txt | 2 +- sdaccel_setup.sh | 2 +- shared/bin/set_common_env_vars.sh | 3 + .../aws_fpga_test_utils/AwsFpgaTestBase.py | 174 ++++++++ shared/lib/aws_fpga_test_utils/__init__.py | 2 + shared/lib/check_src_headers.py | 2 + .../tests/bin/setup_test_build_vitis_env.sh | 36 ++ .../tests/bin/setup_test_runtime_vitis_env.sh | 42 ++ shared/tests/bin/setup_test_xrtpatch.sh | 37 ++ supported_vivado_versions.txt | 3 +- vitis_runtime_setup.sh | 206 +++++++++ vitis_setup.sh | 292 +++++++++++++ 54 files changed, 2724 insertions(+), 361 deletions(-) create mode 100644 Vitis/README.md create mode 100644 Vitis/Runtime/xrt_common_functions.sh create mode 100644 Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/sw/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.spfm create mode 100644 Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.xpfm create mode 100644 Vitis/docs/Create_Runtime_AMI.md create mode 100644 Vitis/docs/FAQ.md create mode 100644 Vitis/docs/Setup_AWS_CLI_and_S3_Bucket.md create mode 100644 Vitis/docs/XRT_installation_instructions.md create mode 160000 Vitis/examples/xilinx_2019.2 create mode 100644 Vitis/kernel_version.txt create mode 100644 Vitis/packages.txt create mode 100644 Vitis/tests/test_build_vitis_example.py create mode 100644 Vitis/tests/test_create_vitis_afi.py create mode 100644 Vitis/tests/test_find_vitis_examples.py create mode 100644 Vitis/tests/test_run_vitis_example.py create mode 100644 Vitis/tests/test_vitis_scripts.py create mode 100755 Vitis/tools/create_vitis_afi.sh create mode 100644 Vitis/vitis_xrt_version.txt create mode 100644 shared/tests/bin/setup_test_build_vitis_env.sh create mode 100644 shared/tests/bin/setup_test_runtime_vitis_env.sh create mode 100644 vitis_runtime_setup.sh create mode 100644 vitis_setup.sh diff --git a/.gitignore b/.gitignore index 721773fe..b5abe33d 100644 --- a/.gitignore +++ b/.gitignore @@ -39,7 +39,7 @@ fio !SDAccel/aws_platform/xilinx_aws-vu9p-f1_1ddr-xpr-2pr_4_0/sw/lib/x86_64/libxilinxopencl.so !SDAccel/aws_platform/xilinx_aws-vu9p-f1_4ddr-xpr-2pr_4_0/sw/lib/x86_64/libxilinxopencl.so !SDAccel/aws_platform/xilinx_aws-vu9p-f1_4ddr-xpr-2pr-debug_4_0/sw/lib/x86_64/libxilinxopencl.so -!SDAccel/aws_platform/xilinx_aws-vu9p-f1_dynamic_5_0/sw/lib/x86_64/libxilinxopencl.so +!SDAccel/aws_platform/xilinx_aws-vu9p-f1_dynamic_5_0/sw/lib/x86_64/libxilinxopencl.so !SDAccel/aws_platform/xilinx_aws-vu9p-f1-04261818_dynamic_5_0/sw/lib/x86_64/libxilinxopencl.so nohup.out @@ -105,3 +105,8 @@ vivado*.log # Patches patches/* + +# Temporary files +.batch +.temp + diff --git a/.gitmodules b/.gitmodules index 7c5393bd..6d9dd010 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,7 @@ [submodule "SDAccel/examples/xilinx_2019.1"] path = SDAccel/examples/xilinx_2019.1 url = https://github.com/Xilinx/SDAccel_Examples.git +[submodule "Vitis/examples/xilinx_2019.2"] + path = Vitis/examples/xilinx_2019.2 + branch = master + url = https://github.com/Xilinx/Vitis_Accel_Examples diff --git a/ERRATA.md b/ERRATA.md index 6bf60595..64257416 100644 --- a/ERRATA.md +++ b/ERRATA.md @@ -7,7 +7,8 @@ ## HDK * Multiple SDE instances per CL is not supported in this release. Support is planned for a future release. * DRAM Data retention is not supported for CL designs with less than 4 DDRs enabled -* Combinatorial loops in CL designs are not supported. +* Combinatorial loops in CL designs are not supported. +* Connecting one of the clocks provided from the shell (clk_main_a0, clk_extra_a1, etc...) directly to a BUFG in the CL is not supported by the Xilinx tools and may result in a non-functional clock. To workaround this limitation, it is recommended to use an MMCM to feed the BUFG (clk_from_shell -> MMCM -> BUFG). ### 2019.1 * Vivado `compile_simlib` command fails to generate the following verilog IP libraries for the following simulators. diff --git a/FAQs.md b/FAQs.md index 46aec1b9..c8b25573 100644 --- a/FAQs.md +++ b/FAQs.md @@ -501,3 +501,7 @@ You would need a valid [on premise license](./hdk/docs/on_premise_licensing_help We have seen this issue when running RDP in 32 bit color mode where Vivado shows up as a blank window. Please modify RDP options to choose any color depth less than 32 bit and try re-connecting. + +**Q: Why did my AFI creation fail with `***ERROR***: DCP has DNA_PORT instantiation, ingestion failed, exiting`? + +AWS does not support creating AFI's with the Device DNA instantiated within your design. Please create your design without instantiating the DNA_PORT primitive to be able to create your AFI. \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index 71a1d172..e6006785 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -19,6 +19,8 @@ properties([parameters([ booleanParam(name: 'test_sdaccel_scripts', defaultValue: true, description: 'Test SDAccel setup scripts'), booleanParam(name: 'test_all_sdaccel_examples_fdf', defaultValue: false, description: 'Run Full Developer Flow testing of all SDAccel examples. This overrides test_helloworld_sdaccel_example'), booleanParam(name: 'test_helloworld_sdaccel_example_fdf', defaultValue: true, description: 'Run Full Developer Flow testing of the Hello World SDAccel example'), + booleanParam(name: 'test_all_vitis_examples_fdf', defaultValue: false, description: 'Run Full Developer Flow testing of all Vitis examples. This overrides test_helloworld_sdaccel_example'), + booleanParam(name: 'test_helloworld_vitis_example_fdf', defaultValue: true, description: 'Run Full Developer Flow testing of the Hello World Vitis example'), booleanParam(name: 'debug_dcp_gen', defaultValue: false, description: 'Only run FDF on cl_hello_world. Overrides test_*.'), booleanParam(name: 'debug_fdf_uram', defaultValue: false, description: 'Debug the FDF for cl_uram_example.'), booleanParam(name: 'fdf_ddr_comb', defaultValue: false, description: 'run FDF for cl_dram_dma ddr combinations.'), @@ -44,6 +46,8 @@ boolean test_hdk_fdf = params.get('test_hdk_fdf') boolean test_sdaccel_scripts = params.get('test_sdaccel_scripts') boolean test_all_sdaccel_examples_fdf = params.get('test_all_sdaccel_examples_fdf') boolean test_helloworld_sdaccel_example_fdf = params.get('test_helloworld_sdaccel_example_fdf') +boolean test_all_vitis_examples_fdf = params.get('test_all_vitis_examples_fdf') +boolean test_helloworld_vitis_example_fdf = params.get('test_helloworld_vitis_example_fdf') boolean disable_runtime_tests = params.get('disable_runtime_tests') def runtime_sw_cl_names = ['cl_dram_dma', 'cl_hello_world', 'cl_sde'] @@ -122,7 +126,9 @@ task_label = [ ] // Put the latest version last -def xilinx_versions = [ '2017.4', '2018.2', '2018.3', '2019.1' ] +def xilinx_versions = [ '2019.1', '2019.2' ] + +def vitis_versions = ['2019.2'] // We want the default to be the latest. def default_xilinx_version = xilinx_versions.last() @@ -131,7 +137,11 @@ def dsa_map = [ '2017.4' : [ 'DYNAMIC_5_0' : 'dyn'], '2018.2' : [ 'DYNAMIC_5_0' : 'dyn'], '2018.3' : [ 'DYNAMIC_5_0' : 'dyn'], - '2019.1' : [ 'DYNAMIC_5_0' : 'dyn'] + '2019.1' : [ 'DYNAMIC_5_0' : 'dyn'], +] + +def xsa_map = [ + '2019.2' : [ 'DYNAMIC':'dyn'] ] def sdaccel_example_default_map = [ @@ -163,6 +173,15 @@ def sdaccel_example_default_map = [ ] ] +def vitis_example_default_map = [ + '2019.2' : [ + 'Hello_World_1ddr': 'Vitis/examples/xilinx/ocl_kernels/cl_helloworld', + 'Gmem_2Banks_2ddr': 'Vitis/examples/xilinx/ocl_kernels/cl_gmem_2banks', + 'Kernel_Global_Bw_4ddr': 'Vitis/examples/xilinx/cpp_kernels/kernel_global_bandwidth', + 'RTL_Vadd_Debug': 'Vitis/examples/xilinx/rtl_kernels/rtl_vadd_hw_debug' + ] +] + def simulator_tool_default_map = [ '2017.4' : [ 'vivado': 'xilinx/SDx/2017.4_04112018', @@ -187,9 +206,16 @@ def simulator_tool_default_map = [ 'vcs': 'synopsys/vcs-mx/N-2017.12-SP2', 'questa': 'questa/10.6c_1', 'ies': 'incisive/15.20.063' + ], + '2019.2' : [ + 'vivado': 'xilinx/Vivado/2019.2', + 'vcs': 'synopsys/vcs-mx/O-2018.09-SP2-1', + 'questa': 'questa/2019.2', + 'ies': 'incisive/15.20.063' ] ] +// ies 073 is not available for download // Get serializable entry set @NonCPS def entrySet(m) {m.collect {k, v -> [key: k, value: v]}} @@ -888,7 +914,7 @@ if (test_hdk_fdf) { // if (test_sdaccel_scripts) { // all_tests['Test SDAccel Scripts'] = { // stage('Test SDAccel Scripts') { -// def nodes = [:] +// def nodes = [:]git // for (def xilinx_version in xilinx_versions) { // // String node_label = get_task_label(task: 'source_scripts', xilinx_version: xilinx_version) @@ -914,86 +940,340 @@ if (test_hdk_fdf) { // } // } -if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { - all_tests['Run SDAccel Tests'] = { - String sdaccel_examples_list = 'sdaccel_examples_list.json' +// if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { +// all_tests['Run SDAccel Tests'] = { +// String sdaccel_examples_list = 'sdaccel_examples_list.json' +// +// def sdaccel_all_version_stages = [:] +// +// for (def version in xilinx_versions) { +// +// String xilinx_version = version +// String sdaccel_base_stage_name = "SDx FDF $xilinx_version" +// String sdaccel_find_stage_name = "SDx Find tests $xilinx_version" +// +// sdaccel_all_version_stages[sdaccel_base_stage_name] = { +// stage (sdaccel_find_stage_name) { +// +// node(get_task_label(task: 'find_tests', xilinx_version: xilinx_version)) { +// +// checkout scm +// String report_file = "test_find_sdaccel_examples_${xilinx_version}.xml" +// +// try { +// sh """ +// rm -rf ${sdaccel_examples_list} +// """ +// } catch(error) { +// // Ignore any errors +// echo "Failed to clean ${sdaccel_examples_list}" +// } +// +// try { +// sh """ +// set -e +// source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh +// python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_find_sdaccel_examples.py --junit-xml $WORKSPACE/${report_file} --xilinxVersion ${xilinx_version} +// """ +// } catch (exc) { +// echo "Could not find tests. Please check the repository." +// throw exc +// } finally { +// run_junit(report_file) +// archiveArtifacts artifacts: "${sdaccel_examples_list}.*", fingerprint: true +// +// } +// +// // Only run the hello world test by default +// //def example_map = [ 'Hello_World': 'SDAccel/examples/xilinx/getting_started/host/helloworld_ocl' ] +// def example_map = sdaccel_example_default_map.get(xilinx_version) +// +// // Run all examples when parameter set +// if (test_all_sdaccel_examples_fdf) { +// example_map = readJSON file: sdaccel_examples_list +// } +// +// def sdaccel_build_stages = [:] +// +// for ( def e in entrySet(example_map) ) { +// +// String test_key = e.key +// def dsa_map_for_version = dsa_map.get(xilinx_version) +// +// // dsa = [ 4DDR: 4ddr ] +// for ( def dsa in entrySet(dsa_map_for_version) ) { +// +// String build_name = "SDx ${e.key}_${dsa.value}_${xilinx_version}" +// String example_path = e.value +// +// String dsa_name = dsa.key +// String dsa_rte_name = dsa.value +// +// String sw_emu_stage_name = "SDx SW_EMU ${build_name}" +// String hw_emu_stage_name = "SDx HW_EMU ${build_name}" +// String hw_stage_name = "SDx HW ${build_name}" +// String create_afi_stage_name = "SDx AFI ${build_name}" +// String run_example_stage_name = "SDx RUN ${build_name}" +// +// String sw_emu_report_file = "sdaccel_sw_emu_${e.key}_${dsa.value}_${xilinx_version}.xml" +// String hw_emu_report_file = "sdaccel_hw_emu_${e.key}_${dsa.value}_${xilinx_version}.xml" +// String hw_report_file = "sdaccel_hw_${e.key}_${dsa.value}_${xilinx_version}.xml" +// String create_afi_report_file = "sdaccel_create_afi_${e.key}_${dsa.value}_${xilinx_version}.xml" +// String run_example_report_file = "sdaccel_run_${e.key}_${dsa.value}_${xilinx_version}.xml" +// +// String description_file = "${example_path}/description.json" +// def description_json = ["targets":["hw","hw_emu","sw_emu"]] +// +// try { +// description_json = readJSON file: description_file +// } +// catch (exc) { +// echo "Could not read the file: ${description_file}" +// throw exc +// } +// +// boolean test_sw_emu_supported = true +// boolean test_hw_emu_supported = true +// +// if(description_json["targets"]) { +// if(description_json["targets"].contains("sw_emu")) { +// test_sw_emu_supported = true +// echo "Description file ${description_file} has target sw_emu" +// } else { +// test_sw_emu_supported = false +// echo "Description file ${description_file} does not have target sw_emu" +// } +// if(description_json["targets"].contains("hw_emu")) { +// test_hw_emu_supported = true +// echo "Description file ${description_file} has target sw_emu" +// } else { +// test_hw_emu_supported = false +// echo "Description file ${description_file} does not have target sw_emu" +// } +// } else { +// echo "Description json did not have a 'target' key" +// } +// +// sdaccel_build_stages[build_name] = { +// if(test_sw_emu_supported) { +// stage(sw_emu_stage_name) { +// node(get_task_label(task: 'sdaccel_builds', xilinx_version: xilinx_version)) { +// checkout scm +// try { +// sh """ +// set -e +// source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh +// export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} +// python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_sw_emu --examplePath ${example_path} --junit-xml $WORKSPACE/${sw_emu_report_file} --timeout=14400 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} +// """ +// } catch (error) { +// echo "${sw_emu_stage_name} SW EMU Build generation failed" +// archiveArtifacts artifacts: "${example_path}/**", fingerprint: true +// throw error +// } finally { +// run_junit(sw_emu_report_file) +// git_cleanup() +// } +// } +// } +// } +// +// if(test_hw_emu_supported) { +// stage(hw_emu_stage_name) { +// node(get_task_label(task: 'sdaccel_builds', xilinx_version: xilinx_version)) { +// checkout scm +// try { +// sh """ +// set -e +// source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh +// export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} +// python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_hw_emu --examplePath ${example_path} --junit-xml $WORKSPACE/${hw_emu_report_file} --timeout=21600 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} +// """ +// } catch (error) { +// echo "${hw_emu_stage_name} HW EMU Build generation failed" +// archiveArtifacts artifacts: "${example_path}/**", fingerprint: true +// throw error +// } finally { +// run_junit(hw_emu_report_file) +// git_cleanup() +// } +// } +// } +// } +// +// stage(hw_stage_name) { +// node(get_task_label(task: 'sdaccel_builds', xilinx_version: xilinx_version)) { +// checkout scm +// try { +// sh """ +// set -e +// source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh +// export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} +// python2.7 -m pytest -s -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_hw_build --examplePath ${example_path} --junit-xml $WORKSPACE/${hw_report_file} --timeout=36000 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} +// """ +// } catch (error) { +// echo "${hw_stage_name} HW Build generation failed" +// archiveArtifacts artifacts: "${example_path}/**", fingerprint: true +// throw error +// } finally { +// run_junit(hw_report_file) +// git_cleanup() +// } +// } +// } +// +// stage(create_afi_stage_name) { +// node(get_task_label(task: 'create_afi', xilinx_version: xilinx_version)) { +// +// checkout scm +// try { +// sh """ +// set -e +// source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh +// export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} +// python2.7 -m pytest -s -v $WORKSPACE/SDAccel/tests/test_create_sdaccel_afi.py::TestCreateSDAccelAfi::test_create_sdaccel_afi --examplePath ${example_path} --junit-xml $WORKSPACE/${create_afi_report_file} --timeout=18000 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} +// """ +// } catch (error) { +// echo "${create_afi_stage_name} Create AFI failed" +// archiveArtifacts artifacts: "${example_path}/**", fingerprint: true +// throw error +// } finally { +// +// String to_aws_dir = "${example_path}/to_aws" +// +// if (fileExists(to_aws_dir)) { +// sh "rm -rf ${to_aws_dir}" +// } +// run_junit(create_afi_report_file) +// git_cleanup() +// } +// } +// } +// +// stage(run_example_stage_name) { +// +// if(disable_runtime_tests) { +// echo "Runtime tests disabled. Not running ${run_example_stage_name}" +// } else { +// node(get_task_label(task: 'runtime', xilinx_version: xilinx_version)) { +// +// checkout scm +// try { +// sh """ +// set -e +// source $WORKSPACE/shared/tests/bin/setup_test_runtime_sdaccel_env.sh +// export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} +// python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_run_sdaccel_example.py::TestRunSDAccelExample::test_run_sdaccel_example --examplePath ${example_path} --junit-xml $WORKSPACE/${run_example_report_file} --timeout=14400 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} +// """ +// } catch (error) { +// echo "${run_example_stage_name} Runtime example failed" +// archiveArtifacts artifacts: "${example_path}/**", fingerprint: true +// input message: "SDAccel Runtime test failed. Click Proceed or Abort when you are done debugging on the instance." +// throw error +// } finally { +// run_junit(run_example_report_file) +// git_cleanup() +// } +// } +// } //else +// +// } +// +// } // sdaccel_build_stages[ e.key ] +// +// } //for ( def dsa in entrySet(dsa_map_for_version) ) { +// } // for ( e in list_map ) +// +// parallel sdaccel_build_stages +// } +// } +// } +// } //for (def xilinx_version in xilinx_versions) { +// parallel sdaccel_all_version_stages +// } +// } + +//============================================================================= +// Vitis Tests +//============================================================================= +if (test_helloworld_vitis_example_fdf || test_all_vitis_examples_fdf) { + all_tests['Run Vitis Tests'] = { + String vitis_examples_list = 'vitis_examples_list.json' - def sdaccel_all_version_stages = [:] + def vitis_all_version_stages = [:] - for (def version in xilinx_versions) { + for (def version in vitis_versions) { String xilinx_version = version - String sdaccel_base_stage_name = "SDx FDF $xilinx_version" - String sdaccel_find_stage_name = "SDx Find tests $xilinx_version" + String vitis_base_stage_name = "Vitis FDF $xilinx_version" + String vitis_find_stage_name = "Vitis Find tests $xilinx_version" - sdaccel_all_version_stages[sdaccel_base_stage_name] = { - stage (sdaccel_find_stage_name) { + vitis_all_version_stages[vitis_base_stage_name] = { + stage (vitis_find_stage_name) { node(get_task_label(task: 'find_tests', xilinx_version: xilinx_version)) { checkout scm - String report_file = "test_find_sdaccel_examples_${xilinx_version}.xml" + String report_file = "test_find_vitis_examples_${xilinx_version}.xml" try { sh """ - rm -rf ${sdaccel_examples_list} + rm -rf ${vitis_examples_list} """ } catch(error) { // Ignore any errors - echo "Failed to clean ${sdaccel_examples_list}" + echo "Failed to clean ${vitis_examples_list}" } try { sh """ set -e - source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh - python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_find_sdaccel_examples.py --junit-xml $WORKSPACE/${report_file} --xilinxVersion ${xilinx_version} + source $WORKSPACE/shared/tests/bin/setup_test_build_vitis_env.sh + python2.7 -m pytest -v $WORKSPACE/Vitis/tests/test_find_vitis_examples.py --junit-xml $WORKSPACE/${report_file} --xilinxVersion ${xilinx_version} """ } catch (exc) { echo "Could not find tests. Please check the repository." throw exc } finally { run_junit(report_file) - archiveArtifacts artifacts: "${sdaccel_examples_list}.*", fingerprint: true + archiveArtifacts artifacts: "${vitis_examples_list}.*", fingerprint: true } - // Only run the hello world test by default - //def example_map = [ 'Hello_World': 'SDAccel/examples/xilinx/getting_started/host/helloworld_ocl' ] - def example_map = sdaccel_example_default_map.get(xilinx_version) + def example_map = vitis_example_default_map.get(xilinx_version) // Run all examples when parameter set - if (test_all_sdaccel_examples_fdf) { - example_map = readJSON file: sdaccel_examples_list + if (test_all_vitis_examples_fdf) { + example_map = readJSON file: vitis_examples_list } - def sdaccel_build_stages = [:] + def vitis_build_stages = [:] for ( def e in entrySet(example_map) ) { String test_key = e.key - def dsa_map_for_version = dsa_map.get(xilinx_version) + def xsa_map_for_version = xsa_map.get(xilinx_version) // dsa = [ 4DDR: 4ddr ] - for ( def dsa in entrySet(dsa_map_for_version) ) { + for ( def dsa in entrySet(xsa_map_for_version) ) { - String build_name = "SDx ${e.key}_${dsa.value}_${xilinx_version}" + String build_name = "Vitis ${e.key}_${dsa.value}_${xilinx_version}" String example_path = e.value String dsa_name = dsa.key String dsa_rte_name = dsa.value - String sw_emu_stage_name = "SDx SW_EMU ${build_name}" - String hw_emu_stage_name = "SDx HW_EMU ${build_name}" - String hw_stage_name = "SDx HW ${build_name}" - String create_afi_stage_name = "SDx AFI ${build_name}" - String run_example_stage_name = "SDx RUN ${build_name}" + String sw_emu_stage_name = "Vitis SW_EMU ${build_name}" + String hw_emu_stage_name = "Vitis HW_EMU ${build_name}" + String hw_stage_name = "Vitis HW ${build_name}" + String create_afi_stage_name = "Vitis AFI ${build_name}" + String run_example_stage_name = "Vitis RUN ${build_name}" - String sw_emu_report_file = "sdaccel_sw_emu_${e.key}_${dsa.value}_${xilinx_version}.xml" - String hw_emu_report_file = "sdaccel_hw_emu_${e.key}_${dsa.value}_${xilinx_version}.xml" - String hw_report_file = "sdaccel_hw_${e.key}_${dsa.value}_${xilinx_version}.xml" - String create_afi_report_file = "sdaccel_create_afi_${e.key}_${dsa.value}_${xilinx_version}.xml" - String run_example_report_file = "sdaccel_run_${e.key}_${dsa.value}_${xilinx_version}.xml" + String sw_emu_report_file = "vitis_sw_emu_${e.key}_${dsa.value}_${xilinx_version}.xml" + String hw_emu_report_file = "vitis_hw_emu_${e.key}_${dsa.value}_${xilinx_version}.xml" + String hw_report_file = "vitis_hw_${e.key}_${dsa.value}_${xilinx_version}.xml" + String create_afi_report_file = "vitis_create_afi_${e.key}_${dsa.value}_${xilinx_version}.xml" + String run_example_report_file = "vitis_run_${e.key}_${dsa.value}_${xilinx_version}.xml" String description_file = "${example_path}/description.json" def description_json = ["targets":["hw","hw_emu","sw_emu"]] @@ -1006,8 +1286,8 @@ if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { throw exc } - boolean test_sw_emu_supported = true - boolean test_hw_emu_supported = true + boolean test_sw_emu_supported = false + boolean test_hw_emu_supported = false if(description_json["targets"]) { if(description_json["targets"].contains("sw_emu")) { @@ -1026,9 +1306,12 @@ if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { } } else { echo "Description json did not have a 'target' key" + test_sw_emu_supported = true + test_hw_emu_supported = true } - sdaccel_build_stages[build_name] = { + vitis_build_stages[build_name] = { + if(test_sw_emu_supported) { stage(sw_emu_stage_name) { node(get_task_label(task: 'sdaccel_builds', xilinx_version: xilinx_version)) { @@ -1036,9 +1319,8 @@ if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { try { sh """ set -e - source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh - export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} - python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_sw_emu --examplePath ${example_path} --junit-xml $WORKSPACE/${sw_emu_report_file} --timeout=14400 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} + source $WORKSPACE/shared/tests/bin/setup_test_build_vitis_env.sh + python2.7 -m pytest -v $WORKSPACE/Vitis/tests/test_build_vitis_example.py::TestBuildVitisExample::test_sw_emu --examplePath ${example_path} --junit-xml $WORKSPACE/${sw_emu_report_file} --timeout=14400 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} """ } catch (error) { echo "${sw_emu_stage_name} SW EMU Build generation failed" @@ -1059,9 +1341,8 @@ if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { try { sh """ set -e - source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh - export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} - python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_hw_emu --examplePath ${example_path} --junit-xml $WORKSPACE/${hw_emu_report_file} --timeout=21600 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} + source $WORKSPACE/shared/tests/bin/setup_test_build_vitis_env.sh + python2.7 -m pytest -v $WORKSPACE/Vitis/tests/test_build_vitis_example.py::TestBuildVitisExample::test_hw_emu --examplePath ${example_path} --junit-xml $WORKSPACE/${hw_emu_report_file} --timeout=21600 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} """ } catch (error) { echo "${hw_emu_stage_name} HW EMU Build generation failed" @@ -1081,9 +1362,8 @@ if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { try { sh """ set -e - source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh - export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} - python2.7 -m pytest -s -v $WORKSPACE/SDAccel/tests/test_build_sdaccel_example.py::TestBuildSDAccelExample::test_hw_build --examplePath ${example_path} --junit-xml $WORKSPACE/${hw_report_file} --timeout=36000 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} + source $WORKSPACE/shared/tests/bin/setup_test_build_vitis_env.sh + python2.7 -m pytest -s -v $WORKSPACE/Vitis/tests/test_build_vitis_example.py::TestBuildVitisExample::test_hw_build --examplePath ${example_path} --junit-xml $WORKSPACE/${hw_report_file} --timeout=36000 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} """ } catch (error) { echo "${hw_stage_name} HW Build generation failed" @@ -1103,9 +1383,8 @@ if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { try { sh """ set -e - source $WORKSPACE/shared/tests/bin/setup_test_build_sdaccel_env.sh - export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} - python2.7 -m pytest -s -v $WORKSPACE/SDAccel/tests/test_create_sdaccel_afi.py::TestCreateSDAccelAfi::test_create_sdaccel_afi --examplePath ${example_path} --junit-xml $WORKSPACE/${create_afi_report_file} --timeout=18000 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} + source $WORKSPACE/shared/tests/bin/setup_test_build_vitis_env.sh + python2.7 -m pytest -s -v $WORKSPACE/Vitis/tests/test_create_vitis_afi.py::TestCreateVitisAfi::test_create_vitis_afi --examplePath ${example_path} --junit-xml $WORKSPACE/${create_afi_report_file} --timeout=18000 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} """ } catch (error) { echo "${create_afi_stage_name} Create AFI failed" @@ -1135,14 +1414,13 @@ if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { try { sh """ set -e - source $WORKSPACE/shared/tests/bin/setup_test_runtime_sdaccel_env.sh - export AWS_PLATFORM=\$AWS_PLATFORM_${dsa_name} - python2.7 -m pytest -v $WORKSPACE/SDAccel/tests/test_run_sdaccel_example.py::TestRunSDAccelExample::test_run_sdaccel_example --examplePath ${example_path} --junit-xml $WORKSPACE/${run_example_report_file} --timeout=14400 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} + source $WORKSPACE/shared/tests/bin/setup_test_runtime_vitis_env.sh + python2.7 -m pytest -v $WORKSPACE/Vitis/tests/test_run_vitis_example.py::TestRunVitisExample::test_run_vitis_example --examplePath ${example_path} --junit-xml $WORKSPACE/${run_example_report_file} --timeout=14400 --rteName ${dsa_rte_name} --xilinxVersion ${xilinx_version} """ } catch (error) { echo "${run_example_stage_name} Runtime example failed" archiveArtifacts artifacts: "${example_path}/**", fingerprint: true - input message: "SDAccel Runtime test failed. Click Proceed or Abort when you are done debugging on the instance." + input message: "Vitis Runtime test failed. Click Proceed or Abort when you are done debugging on the instance." throw error } finally { run_junit(run_example_report_file) @@ -1153,20 +1431,19 @@ if (test_helloworld_sdaccel_example_fdf || test_all_sdaccel_examples_fdf) { } - } // sdaccel_build_stages[ e.key ] + } // vitis_build_stages[ e.key ] - } //for ( def dsa in entrySet(dsa_map_for_version) ) { + } //for ( def dsa in entrySet(xsa_map_for_version) ) { } // for ( e in list_map ) - parallel sdaccel_build_stages + parallel vitis_build_stages } } } } //for (def xilinx_version in xilinx_versions) { - parallel sdaccel_all_version_stages + parallel vitis_all_version_stages } } - //============================================================================= // SDK Tests //============================================================================= diff --git a/Jenkinsfile_int_sims b/Jenkinsfile_int_sims index 76523548..927e0e32 100644 --- a/Jenkinsfile_int_sims +++ b/Jenkinsfile_int_sims @@ -5,100 +5,15 @@ //============================================================================= properties([parameters([ string(name: 'branch', defaultValue: ''), - booleanParam(name: 'test_markdown_links', defaultValue: false, description: 'Test markdown files and check for broken links'), - booleanParam(name: 'test_src_headers', defaultValue: false, description: 'Check copyright heaers of source files'), - booleanParam(name: 'test_fpga_tools', defaultValue: false, description: 'Test fpga-* commands on F1'), - booleanParam(name: 'test_hdk_scripts', defaultValue: false, description: 'Test the HDK setup scripts'), booleanParam(name: 'test_sims', defaultValue: true, description: 'Run all Simulations'), - booleanParam(name: 'test_non_root_access', defaultValue: false, description: 'Test non-root access to FPGA tools'), - booleanParam(name: 'test_xdma', defaultValue: false, description: 'Test XDMA driver'), - booleanParam(name: 'test_py_bindings', defaultValue: false, description: 'Test Python Bindings'), - booleanParam(name: 'test_runtime_software', defaultValue: false, description: 'Test precompiled AFIs'), - booleanParam(name: 'test_dcp_recipes', defaultValue: false, description: 'Run DCP generation with all clock recipes and build strategies.'), - booleanParam(name: 'test_hdk_fdf', defaultValue: false, description: 'Run Full developer flow testing on cl_hello_world and cl_dram_dma'), - booleanParam(name: 'test_sdaccel_scripts', defaultValue: false, description: 'Test SDAccel setup scripts'), - booleanParam(name: 'test_all_sdaccel_examples_fdf', defaultValue: false, description: 'Run Full Developer Flow testing of all SDAccel examples. This overrides test_helloworld_sdaccel_example'), - booleanParam(name: 'test_helloworld_sdaccel_example_fdf', defaultValue: false, description: 'Run Full Developer Flow testing of the Hello World SDAccel example'), - booleanParam(name: 'debug_dcp_gen', defaultValue: false, description: 'Only run FDF on cl_hello_world. Overrides test_*.'), - booleanParam(name: 'debug_fdf_uram', defaultValue: false, description: 'Debug the FDF for cl_uram_example.'), - booleanParam(name: 'fdf_ddr_comb', defaultValue: false, description: 'run FDF for cl_dram_dma ddr combinations.'), - booleanParam(name: 'disable_runtime_tests', defaultValue: false, description: 'Option to disable runtime tests.'), - booleanParam(name: 'use_test_ami', defaultValue: false, description: 'This option asks for the test AMI from Jenkins'), booleanParam(name: 'internal_simulations', defaultValue: true, description: 'This option asks for default agent from Jenkins') ])]) //============================================================================= // Configuration //============================================================================= -boolean test_markdown_links = params.get('test_markdown_links') -boolean test_src_headers = params.get('test_src_headers') -boolean test_hdk_scripts = params.get('test_hdk_scripts') -boolean test_fpga_tools = params.get('test_fpga_tools') -boolean test_sims = params.get('test_sims') -boolean test_non_root_access = params.get('test_non_root_access') -boolean test_xdma = params.get('test_xdma') -boolean test_py_bindings = params.get('test_py_bindings') -boolean test_runtime_software = params.get('test_runtime_software') -boolean test_dcp_recipes = params.get('test_dcp_recipes') -boolean test_hdk_fdf = params.get('test_hdk_fdf') -boolean test_sdaccel_scripts = params.get('test_sdaccel_scripts') -boolean test_all_sdaccel_examples_fdf = params.get('test_all_sdaccel_examples_fdf') -boolean test_helloworld_sdaccel_example_fdf = params.get('test_helloworld_sdaccel_example_fdf') -boolean disable_runtime_tests = params.get('disable_runtime_tests') - -def runtime_sw_cl_names = ['cl_dram_dma', 'cl_hello_world'] -def dcp_recipe_cl_names = ['cl_dram_dma', 'cl_hello_world'] -def dcp_recipe_scenarios = [ - // Default values are tested in FDF: A0-B0-C0-DEFAULT - // Fastest clock speeds are: A1-B2-C0 - // Test each clock recipe with the BASIC strategy - // Test all strategies with highest clock speeds - 'A1-B1-C1-BASIC', - 'A1-B2-C0-BASIC', - 'A2-B3-C2-BASIC', - 'A1-B4-C3-BASIC', - 'A1-B5-C0-BASIC', - 'A1-B2-C0-DEFAULT', - 'A1-B2-C0-EXPLORE', - 'A1-B2-C0-TIMING', - 'A1-B2-C0-TIMING', - 'A1-B2-C0-CONGESTION', - ] -def fdf_test_names = [ - 'cl_dram_dma[A1-B0-C0-DEFAULT]', - 'cl_hello_world[A0-B0-C0-DEFAULT]', - 'cl_hello_world_vhdl', - 'cl_uram_example[2]', - 'cl_uram_example[3]', - 'cl_uram_example[4]' - ] - -boolean debug_dcp_gen = params.get('debug_dcp_gen') -if (debug_dcp_gen) { - fdf_test_names = ['cl_hello_world[A0-B0-C0-DEFAULT]'] - test_markdown_links = false - test_sims = false - test_runtime_software = false - test_sdaccel_scripts = false -} - -boolean debug_fdf_uram = params.get('debug_fdf_uram') -if (debug_fdf_uram) { - fdf_test_names = ['cl_uram_example[2]', 'cl_uram_example[3]', 'cl_uram_example[4]'] - test_markdown_links = false - test_sims = false - test_runtime_software = false - test_sdaccel_scripts = false -} -boolean fdf_ddr_comb = params.get('fdf_ddr_comb') -if(fdf_ddr_comb) { - fdf_test_names = ['cl_dram_dma[A0-B0-C0-DEFAULT-111]', 'cl_dram_dma[A0-B0-C0-DEFAULT-110]', 'cl_dram_dma[A0-B0-C0-DEFAULT-101]','cl_dram_dma[A0-B0-C0-DEFAULT-100]','cl_dram_dma[A0-B0-C0-DEFAULT-011]','cl_dram_dma[A0-B0-C0-DEFAULT-010]','cl_dram_dma[A0-B0-C0-DEFAULT-001]','cl_dram_dma[A0-B0-C0-DEFAULT-000]'] - test_markdown_links = false - test_sims = false - test_runtime_software = false - test_sdaccel_scripts = false -} +boolean test_sims = params.get('test_sims') //============================================================================= // Globals @@ -121,63 +36,16 @@ task_label = [ ] // Put the latest version last -def xilinx_versions = [ '2019.1' ] +def xilinx_versions = [ '2019.2' ] // We want the default to be the latest. def default_xilinx_version = xilinx_versions.last() -def dsa_map = [ - '2017.4' : [ 'DYNAMIC_5_0' : 'dyn'], - '2018.2' : [ 'DYNAMIC_5_0' : 'dyn'], - '2018.3' : [ 'DYNAMIC_5_0' : 'dyn'] -] - -def sdaccel_example_default_map = [ - '2017.4' : [ - 'Hello_World_1ddr': 'SDAccel/examples/xilinx/getting_started/host/helloworld_ocl', - 'Gmem_2Banks_2ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/gmem_2banks_ocl', - 'kernel_3ddr_bandwidth_4ddr': 'SDAccel/examples/aws/kernel_3ddr_bandwidth', - 'Kernel_Global_Bw_4ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/kernel_global_bandwidth', - 'RTL_Vadd_Debug': 'SDAccel/examples/xilinx/getting_started/rtl_kernel/rtl_vadd_hw_debug' - ], - '2018.2' : [ - 'Hello_World_1ddr': 'SDAccel/examples/xilinx/getting_started/host/helloworld_ocl', - 'Gmem_2Banks_2ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/gmem_2banks_ocl', - 'kernel_3ddr_bandwidth_4ddr': 'SDAccel/examples/aws/kernel_3ddr_bandwidth', - 'Kernel_Global_Bw_4ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/kernel_global_bandwidth', - 'RTL_Vadd_Debug': 'SDAccel/examples/xilinx/getting_started/rtl_kernel/rtl_vadd_hw_debug' - ], - '2018.3' : [ - 'Hello_World_1ddr': 'SDAccel/examples/xilinx/getting_started/host/helloworld_ocl', - 'Gmem_2Banks_2ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/gmem_2banks_ocl', - 'Kernel_Global_Bw_4ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/kernel_global_bandwidth', - 'RTL_Vadd_Debug': 'SDAccel/examples/xilinx/getting_started/rtl_kernel/rtl_vadd_hw_debug' - ] -] - def simulator_tool_default_map = [ - '2017.4' : [ - 'vivado': 'xilinx/SDx/2017.4_04112018', - 'vcs': 'synopsys/vcs-mx/M-2017.03-SP2-11', - 'questa': 'questa/10.6b', - 'ies': 'incisive/15.20.063' - ], - '2018.2' : [ - 'vivado': 'xilinx/SDx/2018.2_06142018', - 'vcs': 'synopsys/vcs-mx/N-2017.12-SP2', - 'questa': 'questa/10.6c_1', - 'ies': 'incisive/15.20.063' - ], - '2018.3' : [ - 'vivado': 'xilinx/SDx/2018.3_1207', - 'vcs': 'synopsys/vcs-mx/N-2017.12-SP2', - 'questa': 'questa/10.6c_1', - 'ies': 'incisive/15.20.063' - ], - '2019.1' : [ - 'vivado': 'xilinx/SDx/2019.1.op2552052', - 'vcs': 'synopsys/vcs-mx/O-2018.09-SP1', - 'questa': 'questa/10.6c_1', + '2019.2' : [ + 'vivado': 'xilinx/Vivado/2019.2', + 'vcs': 'synopsys/vcs-mx/O-2018.09-SP2-1', + 'questa': 'questa/2019.2', 'ies': 'incisive/15.20.063' ] ] @@ -194,12 +62,7 @@ def is_public_repo() { def get_task_label(Map args=[ : ]) { String task_label = args.xilinx_version + '_' + task_label[args.task] - //boolean use_test_ami = params.get('use_test_ami') - if (params.use_test_ami) { - echo "Test AMI Requested" - task_label = task_label + '_test' - } if (params.internal_simulations) { echo "internal simulation agent requested" task_label = 'f1_3rd_party_sims' diff --git a/README.md b/README.md index 8659e9d3..3ae8f2d3 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,6 @@ 6. [OpenCL Development Environment with Amazon EC2 F1 FPGA Instances to accelerate your C/C++ applications](#sdaccel) 7. [Developer Support](#devSupport) 8. [Recommended Documentation](#doccontents) -9. [Github tips and tricks](#githubtipstricks) - # Overview of AWS EC2 FPGA Development Kit @@ -28,7 +26,7 @@ The AWS EC2 FPGA Development Kit is provided by AWS to support development and r | Development Environment | Description | Accelerator Language | Development Tool | Debug Options| Typical Developer / FPGA Experience | | --------|---------|---------|-------|-------|-------| -| [Software Defined Accelerator Development - SDAccel](SDAccel/README.md) | Development experience leverages an optimized compiler to allow easy new accelerator development or migration of existing C/C++/openCL, Verilog/VHDL to AWS FPGA instances | C/C++/OpenCL, Verilog/VHDL (RTL) | SDx/Vivado (GUI or scipt) | SW/HW Emulation, Simulation, GDB, Virtual JTAG (Chipscope) | SW or HW Developer with zero FPGA experience | +| Software Defined Accelerator Development - [Vitis](Vitis/README.md)/[SDAccel](SDAccel/README.md) | Development experience leverages an optimized compiler to allow easy new accelerator development or migration of existing C/C++/openCL, Verilog/VHDL to AWS FPGA instances | C/C++/OpenCL, Verilog/VHDL (RTL) | Vitis/SDx/Vivado (GUI or script) | SW/HW Emulation, Simulation, GDB, Virtual JTAG (Chipscope) | SW or HW Developer with zero FPGA experience | | [Hardware Accelerator Development - HDK](hdk/README.md) | Fully custom hardware development experience provides hardware developers with the tools required for developing AFIs for AWS FPGA instances | Verilog/VHDL | Vivado | Simulation, Virtual JTAG | HW Developer with advanced FPGA experience | | [IP Integrator or High Level Synthesis (HLx)](hdk/docs/IPI_GUI_Vivado_Setup.md) | Graphical interface development experience for integrating IP and high level synthesis development | Verilog/VHDL/C | Vivado (GUI) | Simulation, Virtual JTAG | HW Developer with intermediate FPGA experience | @@ -37,7 +35,7 @@ The AWS EC2 FPGA Development Kit is provided by AWS to support development and r | Runtime Environment | Hardware Interface | Host Code Language | FPGA Tools | | --------|---------|---------|-------| -| [C/C++ Software Defined Accelerator Development](SDAccel/README.md) | OpenCL APIs, [XOCL Driver](./sdk/linux_kernel_drivers/xocl), [HAL](SDAccel/userspace/src) | C/C++ | [SDK](./sdk), SDx | +| C/C++ Software Defined Accelerator Development - [Vitis](Vitis/README.md) / [SDAccel](SDAccel/README.md) | OpenCL APIs and XRT | C/C++ | [SDK](./sdk), Vitis / SDAccel| | [Hardware Accelerator Development](hdk/README.md) | [XDMA Driver](sdk/linux_kernel_drivers/xdma/README.md), [peek/poke](sdk/userspace/README.md) | C/C++ | [SDK](./sdk), Vivado | | [IP Integrator or High Level Synthesis (HLx)](hdk/docs/IPI_GUI_Vivado_Setup.md) | [XDMA Driver](sdk/linux_kernel_drivers/xdma/README.md), [peek/poke](sdk/userspace/README.md) | C/C++ | [SDK](./sdk), Vivado | @@ -46,8 +44,9 @@ The AWS EC2 FPGA Development Kit is provided by AWS to support development and r | Tool | Development/Runtime | Tool location | Description | | --------|---------|---------|---------| +| Vitis 2019.2 Development | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Software Defined Accelerator Development using the new Vitis toolset](Vitis/README.md) | +| Vivado 2017.4, 2018.2, 2018.3, 2019.1 & 2019.2 | Development | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Hardware Accelerator Development](hdk/README.md) | | SDx 2017.4, 2018.2, 2018.3 & 2019.1| Development | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Software Defined Accelerator Development](SDAccel/README.md) | -| Vivado 2017.4, 2018.2, 2018.3 & 2019.1 | Development | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Hardware Accelerator Development](hdk/README.md) | | FPGA AFI Management Tools | Runtime | [SDK - fpga\_mgmt\_tools](sdk/userspace/fpga_mgmt_tools) | Command-line tools used for FPGA management while running on the F1 instance | | Virtual JTAG | Development (Debug) | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Runtime debug waveform | | wait\_for\_afi | Development | [wait\_for\_afi.py](shared/bin/scripts/wait_for_afi.py) | Helper script that notifies via email on AFI generation completion | @@ -55,7 +54,8 @@ The AWS EC2 FPGA Development Kit is provided by AWS to support development and r | AFI Administration | Development | [Copy](hdk/docs/copy_fpga_image.md), [Delete](hdk/docs/delete_fpga_image.md), [Describe](hdk/docs/describe_fpga_images.md), [Attributes](hdk/docs/fpga_image_attributes.md) | AWS CLI EC2 commands for managing your AFIs | -NOTE: For on-premises development, SDx/Vivado must have the correct license and use one of the [supported versions of SDx/Vivado](./supported_vivado_versions.txt). The FPGA HDK+SDK [Release Notes](./RELEASE_NOTES.md) may contain additional information. The following links have more information on on-premises development: [Vivado requirements](hdk/docs/on_premise_licensing_help.md) and [SDx requirements](SDAccel/docs/On_Premises_Development_Steps.md) +> For on-premises development, SDx/Vitis/Vivado must have the correct license and use one of the [supported versions of SDx/Vitis/Vivado](./supported_vivado_versions.txt). +> The following links have more information on on-premises development: [Vivado requirements](hdk/docs/on_premise_licensing_help.md), [Vitis requirements](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_2/ug1393-vitis-application-acceleration.pdf) and [SDx requirements](SDAccel/docs/On_Premises_Development_Steps.md) ## Overview of Example Applications @@ -123,7 +123,7 @@ Currently, AWS marketplace includes multiple versions of the FPGA Developer AMI, | 1.4.3+ | 2018.2 | v1.5.0-v1.5.X (Xilinx Vivado/SDx 2018.2) | | 1.4.8+ | 2018.3 | v1.6.0-v1.6.X (Xilinx Vivado/SDx 2018.3) | | 1.4.11+ | 2019.1 | v1.7.0-v1.7.X (Xilinx Vivado/SDx 2019.1) | - +| 1.4.13+ | 2019.2 | v1.8.0-v1.8.X (Xilinx Vivado/Vitis 2019.2) | Developer kit versions prior to v1.3.7 and Developer AMI prior to v1.4 (2017.1) reached end-of-life. See [AWS forum announcement](https://forums.aws.amazon.com/ann.jspa?annID=6068) for additional details. If developing using SDAccel environment please refer to this [Runtime Compatibility Table](SDAccel/docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table) @@ -140,7 +140,11 @@ The software-defined development environment allows customers to compile their C In addition, this development environment (also called SDAccel) allows the mix of C/C++ and RTL accelerator designs into a C/C++ software based development environment. This method enables faster prototyping using C/C++ while supporting manual optimization of critical blocks within RTL. This approach is similar to optimizing time critical functions using software compiler optimization methods. -This developer kit has 80+ examples to help you get started on FPGA acceleration. To get started, review the [Software-defined development environment readme](SDAccel/README.md). +This developer kit has 80+ examples to help you get started on FPGA acceleration. + +To get started with Xilinx SDAccel, review the [Software-defined development environment readme](SDAccel/README.md). +To get started with Xilinx Vitis, review the [Vitis unified development environment readme](Vitis/README.md). + # Runtime Tools (SDK) @@ -186,12 +190,3 @@ The documentation is located throughout this developer kit, therefore, to help d | AFI Administration | [copy\_fpga\_image](hdk/docs/copy_fpga_image.md), [delete\_fpga\_image](hdk/docs/delete_fpga_image.md), [describe\_fpga\_images](hdk/docs/describe_fpga_images.md), [fpga\_image\_attributes](hdk/docs/fpga_image_attributes.md) | CLI documentation for administering AFIs | | AFI Creation Error Codes | [create\_fpga\_image\_error\_codes](hdk/docs/create_fpga_image_error_codes.md) | CLI documentation for managing AFIs | | Developing on-premises | [HDK: on\_premise\_licensing\_help](hdk/docs/on_premise_licensing_help.md), [SDAccel: On\_Premises\_Development\_Steps](SDAccel/docs/On_Premises_Development_Steps.md) | Guidance for developer wanting to develop AFIs from on-premises instead of using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) running on AWS EC2 | - - - -# Github tips and tricks - * [Cloning the repository](https://help.github.com/articles/cloning-a-repository/) - * [Forking the repository](https://help.github.com/articles/fork-a-repo/) - * [Searching code](https://help.github.com/articles/searching-code/) and [advanced search syntax](https://help.github.com/articles/understanding-the-search-syntax/) - * [Finding files](https://help.github.com/articles/finding-files-on-github/) - * Simply replace github.com with gitprint.com to generate a printable PDF diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 11d7af45..7c1ceb01 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -24,9 +24,15 @@ * 1 DDR controller implemented in the SH (always available) * 3 DDR controllers implemented in the CL (configurable number of implemented controllers allowed) +## Release 1.4.13 (See [ERRATA](./ERRATA.md) for unsupported features) +* FPGA developer kit now supports Xilinx Vivado/Vitis 2019.2 +* To upgrade, use [Developer AMI v1.8.0](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) on the AWS Marketplace. + ## Release 1.4.12 (See [ERRATA](./ERRATA.md) for unsupported features) -* Added support for Xilinx tool versions released in the AWS China Marketplace. -* Updated NICE DCV setup instructions. +* Added supported versions for BJS AMI's +* Added link to the re:Invent 19 F1 workshop +* Fixed missing extern C declaration by PR #473 +* Documentation Path fixes from PR #466, #468 and #470 ## Release 1.4.11 (See [ERRATA](./ERRATA.md) for unsupported features) * FPGA developer kit now supports Xilinx SDx/Vivado 2019.1 diff --git a/SDAccel/FAQ.md b/SDAccel/FAQ.md index 6e3ff871..3f41a2d6 100644 --- a/SDAccel/FAQ.md +++ b/SDAccel/FAQ.md @@ -75,6 +75,10 @@ A: You may have run the previous [HDK IPI examples](../hdk/docs/IPI_GUI_Vivado_S A: This error occured because the XRT RPM was built without linking in a library needed for the uuid symbols. To fix it, use the latest XRT RPM's documented in the [XRT installation document](docs/XRT_installation_instructions.md) +## Q: What is the lowest frequency SDAccel design supported on the AWS F1 Platform? +A: We support creating AFI's from CL's that have been built to work at Frequencies no lower than 80MHz. + Re-clocking/Loading a dynamic clock frequency lower than 80MHz will also result in an error. + # Additional Resources * The [AWS SDAccel README](README.md). diff --git a/SDAccel/docs/XRT_installation_instructions.md b/SDAccel/docs/XRT_installation_instructions.md index 16bec5d5..78142ea2 100644 --- a/SDAccel/docs/XRT_installation_instructions.md +++ b/SDAccel/docs/XRT_installation_instructions.md @@ -6,7 +6,7 @@ | Xilinx SDx Tool Version | XRT Release Tag | SHA | `xrt` and `xrt-aws` pre-built RPM's (Centos/RHEL) | |---|---|---|---| -|2019.1| [2019.1_RC2](https://github.com/Xilinx/XRT/releases/tag/2019.1_RC2) | dd210161e204e882027d22132725d8ffdf285149 | [xrt_201910.2.2.0_7.6.1810-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.7.0/Patches/XRT_2019_1_RC2/xrt_201910.2.2.0_7.6.1810-xrt.rpm) [xrt_201910.2.2.0_7.6.1810-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.7.0/Patches/XRT_2019_1_RC2/xrt_201910.2.2.0_7.6.1810-aws.rpm) | +|2019.1| [2019.1.0.3](https://github.com/Xilinx/XRT/tree/2019.1.0.3) | 89e25d51313daac5c322dfb4e84707829306d3fe | [xrt_201910.2.2.0_7.7.1908-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.7.0/Patches/XRT_2019_1_0_3/xrt_201910.2.2.0_7.7.1908-xrt.rpm) [xrt_201910.2.2.0_7.7.1908-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.7.0/Patches/XRT_2019_1_0_3/xrt_201910.2.2.0_7.7.1908-aws.rpm) | |2018.3| [2018.3_RC5](https://github.com/Xilinx/XRT/releases/tag/2018.3_RC5) | 8654da1f0d2bd196c9887bdcfe1479103a93e90a | [xrt_201830.2.1.0_7.6.1810-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.6.0/Patches/XRT_2018_3_RC5/xrt_201830.2.1.0_7.6.1810-xrt.rpm) [xrt_201830.2.1.0_7.6.1810-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.6.0/Patches/XRT_2018_3_RC5/xrt_201830.2.1.0_7.6.1810-aws.rpm) | |2018.2| [2018.2_XDF.RC5](https://github.com/Xilinx/XRT/releases/tag/2018.2_XDF.RC5) | 65ffad62f427c0bd1bc65b6ea555a810295468b7 | [xrt_201802.2.1.0_7.5.1804-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.5.0/Patches/XRT_2018_2_XDF_RC5/xrt_201802.2.1.0_7.5.1804-xrt.rpm) [xrt_201802.2.1.0_7.5.1804-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.5.0/Patches/XRT_2018_2_XDF_RC5/xrt_201802.2.1.0_7.5.1804-aws.rpm) | |2017.4| N/A** | N/A** | N/A** | diff --git a/SDAccel/kernel_version.txt b/SDAccel/kernel_version.txt index 79db7d8b..20429c73 100644 --- a/SDAccel/kernel_version.txt +++ b/SDAccel/kernel_version.txt @@ -2,4 +2,6 @@ 3.10.0-693.21.1.el7.x86_64 3.10.0-957.1.3.el7.x86_64 3.10.0-957.5.1.el7.x86_64 -3.10.0-957.27.2.el7.x86_64 \ No newline at end of file +3.10.0-957.27.2.el7.x86_64 +3.10.0-1062.4.1.el7.x86_64 +3.10.0-1062.9.1.el7.x86_64 \ No newline at end of file diff --git a/SDAccel/sdaccel_xrt_version.txt b/SDAccel/sdaccel_xrt_version.txt index 89feedc2..7322b406 100644 --- a/SDAccel/sdaccel_xrt_version.txt +++ b/SDAccel/sdaccel_xrt_version.txt @@ -2,4 +2,5 @@ 2018.2:65ffad62f427c0bd1bc65b6ea555a810295468b7 2018.3:8654da1f0d2bd196c9887bdcfe1479103a93e90a 2019.1:e21b8a5b208618834760593bbb15063f7e399642 -2019.1:dd210161e204e882027d22132725d8ffdf285149 \ No newline at end of file +2019.1:dd210161e204e882027d22132725d8ffdf285149 +2019.1:89e25d51313daac5c322dfb4e84707829306d3fe \ No newline at end of file diff --git a/Vitis/README.md b/Vitis/README.md new file mode 100644 index 00000000..8ad09e5a --- /dev/null +++ b/Vitis/README.md @@ -0,0 +1,222 @@ +# Quick Start Guide to Accelerating your C/C++ application on an AWS F1 FPGA Instance with Vitis + +There are three steps for accelerating your application on an Amazon EC2 FPGA instance using the software-defined development flow: +1. Build the host application, and the Xilinx FPGA binary +2. Create an AFI +3. Run the FPGA accelerated application on AWS FPGA instances + +This quick start guide will utilize a simple "Hello World" Vitis example to get you started. + +It is highly recommended you read the documentation and utilize software and hardware emulation prior to running on F1. +The F1 HW Target compile time is ~50 minutes, therefore, software and hardware emulation should be used during development. + + +# Table of Content + +1. [Overview](#overview) +2. [Prerequisites](#prerequisites) + * [AWS Account, F1/EC2 Instances, On-Premises, AWS IAM Permissions, AWS CLI and S3 Setup](#iss) + * [Github and Environment Setup](#gitsetenv) +3. [Build the host application, Xilinx FPGA binary and verify you are ready for FPGA acceleration](#createapp) + * [Emulate the code](#emu) + * [Software Emulation](#swemu) + * [Hardware Emulation](#hwemu) + * [Build the host application and Xilinx FPGA Binary](#hw) +4. [Create an Amazon FPGA Image (AFI)](#createafi) +5. [Run the FPGA accelerated application on F1](#runonf1) +6. [Additional Vitis Information](#read) + + + +# Overview +* Vitis is a complete development environment for applications accelerated using Xilinx FPGAs +* It leverages the OpenCL heterogeneous computing framework to offload compute intensive workloads to the FPGA +* The accelerated application is written in C/C++, OpenCL or RTL with OpenCL APIs + + +# Prerequisites + +## AWS Account, F1/EC2 Instances, On-Premises, AWS IAM Permissions, AWS CLI and S3 Setup (One-time Setup) +* [Setup an AWS Account](https://aws.amazon.com/free/) +* Launch an instance using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) which comes pre-installed with SDAccel and required licenses. + * You may use this F1 instance to [build your host application and Xilinx FPGA binary](#createapp), however, it is more cost efficient to either: + * Launch the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) on a compute EC2 instance, with a minimum of 30GiB RAM), **OR** + * Follow the [On-Premises Instructions](../hdk/docs/on_premise_licensing_help.md) to purchase and install a license from Xilinx. +* Setup AWS IAM permissions for creating FPGA Images (CreateFpgaImage and DescribeFpgaImages). [EC2 API Permissions are described in more detail](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ec2-api-permissions.html). It is highly recommended that you validate your AWS IAM permissions prior to proceeding with this quick start. By calling the [DescribeFpgaImages API](../hdk/docs/describe_fpga_images.md) you can check that your IAM permissions are correct. +* [Setup AWS CLI and S3 Bucket](docs/Setup_AWS_CLI_and_S3_Bucket.md) to enable AFI creation. +* Install optional [packages](packages.txt) required to run all examples. If you do not install these packages, some examples may not work properly. The setup scripts will warn you of any missing packages. +* Additional dependencies may get flagged during the AWS Vitis scripts as warnings or errors. + + +## Github and Environment Setup +* Clone this github repository and source the *vitis_setup.sh* script. This will take care of: + * Downloading the required files: + * [AWS Platform](./aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1) that allows Xilinx FPGA Binary files to target AWS F1 instances + * [AFI Creation script](./tools/create_vitis_afi.sh) that generates an AFI and AWS FPGA Binary from a Xilinx FPGA Binary + * Installing the required XRT, libraries and drivers + + ``` + $ git clone https://github.com/aws/aws-fpga.git $AWS_FPGA_REPO_DIR + $ cd $AWS_FPGA_REPO_DIR + $ source vitis_setup.sh + ``` + * Valid platforms for shell_v04261818: `AWS_PLATFORM_201920_1` (Default) AWS F1 Vitis platform. + + +# 1. Build the host application, Xilinx FPGA binary and verify you are ready for FPGA acceleration + +This section will walk you through creating, emulating and compiling your host application and FPGA Binary + + +# Emulate your Code + + +The main goal of emulation is to ensure functional correctness and to determine how to partition the application between the host CPU and the FPGA. + + +## Software (SW) Emulation + +For CPU-based (SW) emulation, both the host code and the FPGA binary code are compiled to run on an x86 processor. The SW Emulation enables developers to iterate and refine the algorithms through fast compilation. The iteration time is similar to software compile and run cycles on a CPU. + +The instructions below describe how to run the Vitis SW Emulation flow using the Makefile provided with a simple "hello world" example + +``` + $ cd $VITIS_DIR/examples/xilinx/hello_world + $ make clean + $ make check TARGET=sw_emu DEVICE=$AWS_PLATFORM all +``` + +For more information on how to debug your application in a SW Emulation environment. + + +## Hardware (HW) Emulation + +The Vitis hardware emulation flow enables the developer to check the correctness of the logic generated for the FPGA binary. This emulation flow invokes the hardware simulator in the Vitis environment to test the functionality of the code that will be executed on the FPGA Custom Logic. + +The instructions below describe how to run the HW Emulation flow using the Makefile provided with a simple "hello world" example: + +``` + $ cd $VITIS_DIR/examples/xilinx/hello_world + $ make clean + $ make check TARGET=hw_emu DEVICE=$AWS_PLATFORM all +``` +For more information on how to debug your application in a HW Emulation environment. + + +# Build the Host Application and Xilinx FPGA Binary + +The Vitis system build flow enables the developer to build their host application as well as their Xilinx FPGA Binary. + +The instructions below describe how to build the Xilinx FPGA Binary and host application using the Makefile provided with a simple "hello world" example: + +``` + $ cd $VITIS_DIR/examples/xilinx/hello_world + $ make clean + $ make TARGET=hw DEVICE=$AWS_PLATFORM all +``` + +NOTE: If you encounter an error with `No current synthesis run set`, you may have previously run the [HDK IPI examples](../hdk/docs/IPI_GUI_Vivado_Setup.md) and created a `Vivado_init.tcl` file in `~/.Xilinx/Vivado`. This will cause [problems](https://forums.aws.amazon.com/thread.jspa?threadID=268202&tstart=25) with the build process, thus it is recommended to remove it before starting a hardware system build. + + +# 2. Create an Amazon FPGA Image (AFI) + +*The Vitis Flow only supports AFI's created with Device ID 0xF010 and Vendor ID 0x1D0F.* + +The runtime drivers are designed to only bind to 0xF010 and 0x1042(Cleared AFI) and loading AFI's from your application that provide other Device/Vendor ID's will require restarting the Xilinx MPD. + +This assumes you have: +* [Compiled your host application and Xilinx FPGA Binary](#hw) +* Validated your code using [SW/HW Emulation](#emu) and you are ready to create an AFI and test on F1. +* [Setup AWS CLI and S3 bucket](docs/Setup_AWS_CLI_and_S3_Bucket.md) for AFI creation + +The [create_vitis_afi.sh](./tools/create_vitis_afi.sh) script is provided to facilitate AFI creation from a Xilinx FPGA Binary, it: +* Takes in your Xilinx FPGA Binary \*.xclbin file +* Calls *aws ec2 create_fpga_image* to generate an AFI under the hood +* Generates a \_afi_id.txt which contains the identifiers for your AFI +* Creates an AWS FPGA Binary file with an \*.awsxclbin extension that is composed of: Metadata and AGFI-ID. + * **This \*.awsxclbin is the AWS FPGA Binary file that will need to be loaded by your host application to the FPGA** + +``` + $ $VITIS_DIR/tools/create_vitis_afi.sh -xclbin= + -o= \ + -s3_bucket= -s3_dcp_key= -s3_logs_key= +``` + +**Save the \*.awsxclbin, you will need to copy it to your F1 instance along with your executable host application.** + +**NOTE**: *Attempting to load your AFI immediately on an F1 instance will result in an 'Invalid AFI ID' error. +Please wait until you confirm the AFI has been created successfully.* + +## Tracking the status of your registered AFI + +The \*_afi_id.txt file generated by the create_vitis_afi.sh also includes the two identifiers for your AFI: +- **FPGA Image Identifier** or **AFI ID**: this is the main ID used to manage your AFI through the AWS EC2 CLI commands and AWS SDK APIs. + This ID is regional, i.e., if an AFI is copied across multiple regions, it will have a different unique AFI ID in each region. + An example AFI ID is **`afi-06d0ffc989feeea2a`**. +- **Global FPGA Image Identifier** or **AGFI ID**: this is a global ID that is used to refer to an AFI from within an F1 instance. + For example, to load or clear an AFI from an FPGA slot, you use the AGFI ID. + **This is embedded into the AWS FPGA Binary \*.awsxclbin file generated by create_vitis_afi.sh.** + Since the AGFI IDs is global (by design), it allows you to copy a combination of AFI/AMI to multiple regions, and they will work without requiring any extra setup. + An example AGFI ID is **`agfi-0f0e045f919413242`**. + + +Use the [describe-fpga-images](../hdk/docs/describe_fpga_images.md) API to check the AFI state during the background AFI generation process. + +``` + $ aws ec2 describe-fpga-images --fpga-image-ids +``` + +When AFI creation completes successfully, the output should contain: +``` + ... + "State": { + "Code": "available" + }, + ... +``` + +If the “State” code indicates the AFI generation has "failed", the AFI creation logs can be found in the bucket location (```s3:///```) provided to create_sdaccel_afi.sh above. These will detail the errors encountered during the AFI creation process. + +For help with AFI creation issues, see [create-fpga-image error codes](../hdk/docs/create_fpga_image_error_codes.md) + + + +# 3. Run the FPGA accelerated application on Amazon FPGA instances + +* Start an FPGA instance using [FPGA Developer AMI on AWS Marketplace](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) and check the AMI [compatibility table](../README.md#devAmi) and [runtime compatibility table](./docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table). Alternatively, you can [create your own Runtime AMI](docs/Create_Runtime_AMI.md) for running your SDAccel applications on Amazon FPGA instances. + * *Assuming the developer flow (compilation) was done on a separate instance you will need to:* + * Copy the compiled host executable (exe) to the new instance + * Copy the \*.awsxclbin AWS FPGA binary file to the new instance + * Depending on the host code, the \*.awsxclbin may need to named \.hw.\.awsxclbin .For Example: ```vector_addition.hw.xilinx_aws-vu9p-f1_shell-v04261818_201920_1.awsxclbin``` + * Copy any data files required for execution to the new instance + * [Clone the github repository to the new F1 instance and install runtime drivers](#gitsetenv) + +* To setup tools, runtime environment & execute your Host Application: + ``` + $ git clone https://github.com/aws/aws-fpga.git $AWS_FPGA_REPO_DIR + $ cd $AWS_FPGA_REPO_DIR + $ source vitis_setup.sh + $ ./helloworld ./vector_addition.awsxclbin + ``` + +* Alternatively, to only setup the runtime environment & execute your host application: + ``` + $ cd $AWS_FPGA_REPO_DIR + $ source vitis_runtime_setup.sh # Other runtime env settings needed by the host app should be setup after this step + # Wait till the MPD service has initialized. Check systemctl status mpd + $ ./helloworld ./vector_addition.awsxclbin + ``` +* The runtime setup script also starts the Xilinx XRT Message Proxy Daemon(MPD) service. To learn more about the XRT implementation, check the [XRT Instructions](./docs/XRT_installation_instructions.md#mpd) + + +# Additional Vitis Information + +* [Vitis Environment tutorial](https://www.github.com/Xilinx/Vitis-Tutorials) + +* [Vitis User Guide](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_2/ug1393-vitis-application-acceleration.pdf) + +* [Vitis Product Info](https://www.xilinx.com/products/design-tools/vitis.html) + +* [XRT Documentation](https://xilinx.github.io/XRT/master/html/) + +* [XRT MPD Documentation](https://xilinx.github.io/XRT/master/html/cloud_vendor_support.html) \ No newline at end of file diff --git a/Vitis/Runtime/xrt_common_functions.sh b/Vitis/Runtime/xrt_common_functions.sh new file mode 100644 index 00000000..b6b7c02b --- /dev/null +++ b/Vitis/Runtime/xrt_common_functions.sh @@ -0,0 +1,117 @@ +# +# Copyright (C) 2018 Xilinx, Inc +# Xilinx XRT setup functions +# +# Author: ryan.radjabi@xilinx.com +# +# Licensed under the Apache License, Version 2.0 (the "License"). You may +# not use this file except in compliance with the License. A copy of the +# License is located at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +XRT_PATH="${VITIS_DIR}/Runtime/XRT_${RELEASE_VER}" + +function get_install_cmd { + xrt_inst_cmd="install" + aws_inst_cmd="install" + if [[ $(lsb_release -si) == "Ubuntu" ]]; then + dpkg -s xrt + ret=$? + if [[ $ret == "0" ]]; then + xrt_inst_cmd="install --reinstall" + fi + dpkg -s xrt-aws + ret=$? + if [[ $ret == "0" ]]; then + aws_inst_cmd="install --reinstall" + fi + elif [[ $(lsb_release -si) == "CentOS" ]]; then + rpm -q xrt + ret=$? + if [[ $ret == "0" ]]; then + xrt_inst_cmd="reinstall" + fi + rpm -q xrt-aws + ret=$? + if [[ $ret == "0" ]]; then + aws_inst_cmd="reinstall" + fi + fi +} + +function build_xrt { + info_msg "xrt-path: $XRT_PATH" + if [ -z "$(ls -A $XRT_PATH)" ]; then + # XRT_PATH is empty, this is the first run, so call submodule update + git submodule update --init -- $XRT_PATH + else + # XRT_PATH is not empty, only call init, this allows local changes to exist in XRT + git submodule init -- $XRT_PATH + fi + info_msg "XRT Developer Flow: Building Xilinx runtime XRT..." + sudo sh -c "cd $XRT_PATH;./src/runtime_src/tools/scripts/xrtdeps.sh;" + ret=$? + if [[ $ret != 0 ]]; then + err_msg "XRT Developer Flow: Failed to install dependencies: xrtdeps.sh: {$?}" + return $? + fi + if [[ $(lsb_release -si) == "CentOS" ]]; then + scl enable devtoolset-6 "cd ${XRT_PATH}/build/; ./build.sh;" + elif [[ $(lsb_release -si) == "Ubuntu" ]]; then + sudo sh -c "cd ${XRT_PATH}/build/; ./build.sh;" + fi + ret=$? + if [[ $ret != 0 ]]; then + err_msg "XRT Developer Flow: Failed to build XRT: {$?}" + fi + + return $? +} + +# takes the path to RPM/DEB package as argument +function install_xrt_package { + get_install_cmd + if [[ $(lsb_release -si) == "CentOS" ]]; then + sudo sh -c "cd $1; yum ${xrt_inst_cmd} -y xrt_*-xrt.rpm; yum ${aws_inst_cmd} -y xrt_*-aws.rpm;" + elif [[ $(lsb_release -si) == "Ubuntu" ]]; then + sudo sh -c "cd $1; apt ${xrt_inst_cmd} ./xrt_*-xrt.deb; apt ${aws_inst_cmd} ./xrt_*-aws.deb;" + fi + ret=$? + if [[ $ret != 0 ]]; then + err_msg "XRT Developer Flow: Failed to install XRT: {$?}" + else + info_msg "Xilinx runtime installed" + fi + return $? +} + +function setup_runtime { + if [ -e /opt/xilinx/xrt ]; then # Check if XRT is installed + info_msg "XRT Install, non-dev" + export XILINX_XRT=/opt/xilinx/xrt + export PATH=$PATH:/opt/xilinx/xrt/bin + + export LD_LIBRARY_PATH=$XILINX_XRT/lib:$LD_LIBRARY_PATH + # copy libstdc++ from $XILINX_VITIS/lib + if [[ $(lsb_release -si) == "Ubuntu" ]]; then + sudo cp $XILINX_VITIS/lib/lnx64.o/Ubuntu/libstdc++.so* /opt/xilinx/xrt/lib/ + elif [[ $(lsb_release -si) == "CentOS" ]]; then + sudo cp $XILINX_VITIS/lib/lnx64.o/Default/libstdc++.so* /opt/xilinx/xrt/lib/ + else + info_msg "Unsupported OS." + return 1 + fi + else # No XRT available + err_msg "Xilinx XRT runtime not installed - This is required if you are running on an F1 instance." + # Placeholder for code to download pre-compiled RPM/DEB package and remove above message + # install_xrt_package + fi +} diff --git a/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/sw/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.spfm b/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/sw/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.spfm new file mode 100644 index 00000000..a2726185 --- /dev/null +++ b/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/sw/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.spfm @@ -0,0 +1,26 @@ + + + + {No description given} + + + + + config0_0 Linux OS on x86_0 + + + + + + diff --git a/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.xpfm b/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.xpfm new file mode 100644 index 00000000..6dded946 --- /dev/null +++ b/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.xpfm @@ -0,0 +1,20 @@ + + + + {No description given} + + + + + + + + + + + diff --git a/Vitis/docs/Create_Runtime_AMI.md b/Vitis/docs/Create_Runtime_AMI.md new file mode 100644 index 00000000..6d2fb49f --- /dev/null +++ b/Vitis/docs/Create_Runtime_AMI.md @@ -0,0 +1,34 @@ +# Create a Runtime AMI Starting with Amazon Linux 2, Centos or Ubuntu + +## Runtime AMI Compatibility Table + +| Vitis Version used for AFI Development | Compatible Xilinx Runtime | +|--------------------------------------|-----------------------------| +| 2019.2 | AWS FPGA Developer AMI 1.8.0 (XRT is pre-installed) or [XRT](https://xilinx.github.io/XRT/2019.2/html/build.html) | + +## 1. Launch a Runtime Instance & Install Required Packages + +* Launch an F1 instance using [Centos 7](https://aws.amazon.com/marketplace/pp/B00O7WM7QW), Ubuntu or Amazon Linux 2 AMI's. + +## 2. Install Runtime Drivers +* Build XRT on either your runtime or a similar instance using the [XRT build steps](https://xilinx.github.io/XRT/2019.2/html/build.html). +* Install the XRT package on your runtime instance + +## 3. Run your FPGA accelerated application on your Runtime Instance. +* Source the runtime setup script: +``` +$ source /opt/xilinx/xrt/setup.sh +``` +* Run application to verify that it works: +```bash +$ ./helloworld ./vector_addition.awsxclbin +``` +* You might want to add a link to the setup command: `/opt/xilinx/xrt/setup.sh` in the `/etc/profile.d` path to be able to setup on start. + +## 4. Create your Runtime AMI based on your Instance. + +* Once you have your application running you should be able to create a Runtime AMI based your Runtime Instance as specified [here](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/creating-an-ami-ebs.html). + +## 5. Make Runtime AMI available on the AWS Marketplace + +* Please see [Section 5 of the AWS Marketplace Seller's Guide](https://awsmp-loadforms.s3.amazonaws.com/AWS_Marketplace_-_Seller_Guide.pdf#page=19) for more details. \ No newline at end of file diff --git a/Vitis/docs/FAQ.md b/Vitis/docs/FAQ.md new file mode 100644 index 00000000..2da973b4 --- /dev/null +++ b/Vitis/docs/FAQ.md @@ -0,0 +1,5 @@ +# Frequently Asked Questions (FAQ) + +## Q: What is the lowest frequency Vitis design supported on the AWS F1 Platform? +A: We support creating AFI's from CL's that have been built to work at Frequencies no lower than 80MHz. + Re-clocking/Loading a dynamic clock frequency lower than 80MHz will also result in an error. diff --git a/Vitis/docs/Setup_AWS_CLI_and_S3_Bucket.md b/Vitis/docs/Setup_AWS_CLI_and_S3_Bucket.md new file mode 100644 index 00000000..da09483a --- /dev/null +++ b/Vitis/docs/Setup_AWS_CLI_and_S3_Bucket.md @@ -0,0 +1,26 @@ +## Setup CLI and Create S3 Bucket +The developer is required to create an S3 bucket for the AFI generation. The bucket will contain a tar file and logs which are generated from the AFI creation service. + +To install the AWS CLI, please follow the [instructions here](http://docs.aws.amazon.com/cli/latest/userguide/installing.html). + +The AWS SDAccel scripts require JSON output format and the scripts will not work properly if you use any other output format types (ex: text, table). JSON is the default output format of the AWS CLI. + +``` + $ aws configure # to set your credentials (found in your console.aws.amazon.com page), region (us-east-1) and output (json) +``` +This S3 bucket will be used by the AWS SDAccel scripts to upload your DCP to AWS for AFI generation which will be packaged into a tar file. +Start by creating a bucket and a folder within your new bucket: +``` + $ aws s3 mb s3:// --region us-east-1 # Create an S3 bucket (choose a unique bucket name) + $ aws s3 mb s3:/// # Create folder for your tarball files + $ touch FILES_GO_HERE.txt # Create a temp file + $ aws s3 cp FILES_GO_HERE.txt s3://// # Which creates the folder on S3 +``` +The AFI creation process will generate logs and will be placed in your S3 bucket. These logs can be used for debug if the AFI generation fails. +Next, create a folder for your log files: +``` + $ aws s3 mb s3:/// # Create a folder to keep your logs + $ touch LOGS_FILES_GO_HERE.txt # Create a temp file + $ aws s3 cp LOGS_FILES_GO_HERE.txt s3://// # Which creates the folder on S3 +``` +Once your AFI has been created successfully, you are free to delete the tar file and logs as needed. Deleting these files will not delete or modify your AFI. diff --git a/Vitis/docs/XRT_installation_instructions.md b/Vitis/docs/XRT_installation_instructions.md new file mode 100644 index 00000000..2b4c85c9 --- /dev/null +++ b/Vitis/docs/XRT_installation_instructions.md @@ -0,0 +1,149 @@ +# Xilinx Runtime (XRT) and Vitis Tool versions + +* Xilinx Runtime versions match with the tool that you created your Vitis AFI with. +* We provide pre-built RPM's for Centos/RHEL and instructions for building XRT +* Use the below table as reference to install and use the correct XRT version for your applications. + +| Xilinx Vitis Tool Version | XRT Release Tag | SHA | `xrt` and `xrt-aws` pre-built RPM's (Centos/RHEL) | +|---|---|---|---| +|2019.2| [2019.2.0.3](https://github.com/Xilinx/XRT/releases/tag/2019.2.0.3) | 9e13d57c4563e2c19bf5f518993f6e5a8dadc18a | [xrt_201920.2.3.0_7.7.1908-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/XRT_2019_2/xrt_201920.2.3.0_7.7.1908-xrt.rpm) [xrt_201920.2.3.0_7.7.1908-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/XRT_2019_2/xrt_201920.2.3.0_7.7.1908-aws.rpm) | + + +# MPD +From 2019.2 toolset onwards, [Xilinx XRT architecture has been made more modular](https://xilinx.github.io/XRT/master/html/cloud_vendor_support.html). +To be able to do so, the new architecture implements a Message Proxy Daemon in user space that interacts with the management library. +This also allows us to make calls to the management library without requiring privileged access to the user on the host. + +## FPGA Developer AMI usecase +Since this Daemon is only required for the Vitis flow, it is disabled by default on the FPGA Developer AMI as we support both the Vitis and The Vivado flows. +The `vitis_runtime_setup.sh` script when called automatically checks for and starts the MPD daemon. +Once MPD Daemon starts up, it loads a 'Default AFI' on all the slots that lets the XOCL driver bind to the device. +Since we only support Device ID 0xF010 for the Vitis workflow, any subsequent loads of AFI's would work seamlessly. + +However, after MPD has started if you clear the slot, the cleared slot will show a Device ID 0x1042 and XOCL will not bind. +Therefore, to be able to run your host application again after clearing a slot manually, you will need to restart the MPD service: + ```sudo systemctl restart mpd``` + +**Note that MPD service starts asynchronously, so you might have to wait till all the slots are loaded with the Default AFI before your application can run.** + +## Custom Runtime AMI usecase +On your custom Runtime AMI, MPD will be enabled by default once you install Xilinx XRT. +On startup, MPD will check if the instance has FPGA's and will load the Default AFI's. +After MPD has started if you clear the slot, the cleared slot will show a Device ID 0x1042 and XOCL will not bind. +Therefore, to be able to run your host application again after clearing a slot manually, you will need to restart the MPD service: + ```sudo systemctl restart mpd``` +**Note that MPD service starts asynchronously, so you might have to wait till all the slots are loaded with the Default AFI before your application can run.** + +## Default AFI details +The Default AFI loaded is a regular `Hello World` AFI that provides the Device ID 0xF010. + +# Centos/RHEL build and install steps + +```bash +XRT_RELEASE_TAG=2019.2.0.3 # Substitute XRT_RELEASE_TAG= + +git clone https://github.com/aws/aws-fpga.git + +cd aws-fpga +source vitis_setup.sh +cd $VITIS_DIR/Runtime +export XRT_PATH="${VITIS_DIR}/Runtime/${XRT_RELEASE_TAG}" +git clone http://www.github.com/Xilinx/XRT.git -b ${XRT_RELEASE_TAG} ${XRT_PATH} + +cd ${XRT_PATH} +sudo ./src/runtime_src/tools/scripts/xrtdeps.sh + +cd build +scl enable devtoolset-6 bash +./build.sh + +cd Release +sudo yum reinstall xrt_*.rpm -y +``` + +# Centos/RHEL pre-built RPM install steps + +### 2019.2 + +```bash +curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/XRT_2019_2/xrt_201920.2.3.0_7.7.1908-xrt.rpm -o xrt.rpm +curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/XRT_2019_2/xrt_201920.2.3.0_7.7.1908-aws.rpm -o xrt-aws.rpm +sudo yum reinstall xrt*.rpm -y +``` + +# FAQ + +*Q:* What should I do if I see this message when I run the host application: ```xclProbe found 1 FPGA slots with xocl driver running +WARNING: AwsXcl - Cannot open userPF: /dev/dri/renderD0 +WARNING: AwsXcl isGood: invalid user handle. +WARNING: xclOpen Handle check failed +device[0].user_instance : 0 +WARNING: AwsXcl - Cannot open userPF: /dev/dri/renderD0 +WARNING: AwsXcl isGood: invalid user handle. +ERROR: xclOpen Handle check failed``` + +This means that the XOCL driver hasn't been able to bind to the User PF. Please try to restart MPD: `sudo systemctl restart mpd` + +*Q:* How do I verify that my device is usable?: +Use the Xilinx `xbutil` utility. If you sourced the `vitis_runtime_setup.sh` script, it should be available in your path. + +``` +xbutil scan +INFO: Found total 1 card(s), 1 are usable +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +System Configuration +OS name: Linux +Release: 3.10.0-1062.4.1.el7.x86_64 +Version: #1 SMP Fri Oct 18 17:15:30 UTC 2019 +Machine: x86_64 +Model: HVM domU +CPU cores: 8 +Memory: 122724 MB +Glibc: 2.17 +Distribution: CentOS Linux 7 (Core) +Now: Thu Jan 30 03:29:45 2020 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +XRT Information +Version: 2.3.0 +Git Hash: 42da4cceb02e0386e0daeaea230bdc86ea40d19a +Git Branch: 2019.2 +Build Date: 2020-01-30 02:56:41 +XOCL: 2.3.0,42da4cceb02e0386e0daeaea230bdc86ea40d19a +XCLMGMT: unknown +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + [0] 0000:00:1d.0 xilinx_aws-vu9p-f1_dynamic_5_0(ts=0xabcd) user(inst=128) +``` + +An unusable device will show up like this: +``` +xbutil scan +INFO: Found total 1 card(s), 1 are usable +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +System Configuration +OS name: Linux +Release: 3.10.0-1062.4.1.el7.x86_64 +Version: #1 SMP Fri Oct 18 17:15:30 UTC 2019 +Machine: x86_64 +Model: HVM domU +CPU cores: 8 +Memory: 122724 MB +Glibc: 2.17 +Distribution: CentOS Linux 7 (Core) +Now: Thu Jan 30 03:29:45 2020 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +XRT Information +Version: 2.3.0 +Git Hash: 42da4cceb02e0386e0daeaea230bdc86ea40d19a +Git Branch: 2019.2 +Build Date: 2020-01-30 02:56:41 +XOCL: 2.3.0,42da4cceb02e0386e0daeaea230bdc86ea40d19a +XCLMGMT: unknown +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +*[0] 0000:00:1d.0 xilinx_aws-vu9p-f1_dynamic_5_0(ts=0xabcd) user(inst=128) +WARNING: card(s) marked by '*' are not ready, is MPD runing? run 'systemctl status mpd' to check MPD details.``` +``` + +# Additional Documentation +* [XRT Documentation](https://xilinx.github.io/XRT/master/html/) + +* [XRT MPD Documentation](https://xilinx.github.io/XRT/master/html/cloud_vendor_support.html) \ No newline at end of file diff --git a/Vitis/examples/xilinx_2019.2 b/Vitis/examples/xilinx_2019.2 new file mode 160000 index 00000000..bb80c8ec --- /dev/null +++ b/Vitis/examples/xilinx_2019.2 @@ -0,0 +1 @@ +Subproject commit bb80c8ec699c3131e8874735bd99475ac6fe2ec7 diff --git a/Vitis/kernel_version.txt b/Vitis/kernel_version.txt new file mode 100644 index 00000000..20429c73 --- /dev/null +++ b/Vitis/kernel_version.txt @@ -0,0 +1,7 @@ +3.10.0-862.11.6.el7.x86_64 +3.10.0-693.21.1.el7.x86_64 +3.10.0-957.1.3.el7.x86_64 +3.10.0-957.5.1.el7.x86_64 +3.10.0-957.27.2.el7.x86_64 +3.10.0-1062.4.1.el7.x86_64 +3.10.0-1062.9.1.el7.x86_64 \ No newline at end of file diff --git a/Vitis/packages.txt b/Vitis/packages.txt new file mode 100644 index 00000000..c682af2f --- /dev/null +++ b/Vitis/packages.txt @@ -0,0 +1,18 @@ +ocl-icd +ocl-icd-devel +opencl-headers +libstdc++-static +kernel-headers +kernel-devel +gcc-c++ +gcc +gdb +libstdc++-static +make +opencv +python +git +libjpeg-turbo-devel +libpng12-devel +libtiff-devel +compat-libtiff3 diff --git a/Vitis/tests/test_build_vitis_example.py b/Vitis/tests/test_build_vitis_example.py new file mode 100644 index 00000000..8ea0a989 --- /dev/null +++ b/Vitis/tests/test_build_vitis_example.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python2.7 + +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. +''' +Pytest module: + +Call using ```pytest test_build_vitis_example.py``` + +See TESTING.md for details. +''' + +from __future__ import print_function +import os +from os.path import dirname, realpath, basename +import json +try: + import aws_fpga_utils + import aws_fpga_test_utils + from aws_fpga_test_utils.AwsFpgaTestBase import AwsFpgaTestBase +except ImportError as e: + traceback.print_tb(sys.exc_info()[2]) + print("error: {}\nMake sure to source shared/bin/setup_test_env.sh".format(sys.exc_info()[1])) + sys.exit(1) + +logger = aws_fpga_utils.get_logger(__name__) + +class TestBuildVitisExample(AwsFpgaTestBase): + ''' + Pytest test class. + + NOTE: Cannot have an __init__ method. + + ''' + ADD_EXAMPLEPATH = True + ADD_RTENAME = True + ADD_XILINX_VERSION = True + + @classmethod + def setup_class(cls): + ''' + Do any setup required for tests. + ''' + + AwsFpgaTestBase.setup_class(cls, __file__) + + AwsFpgaTestBase.assert_sdk_setup() + AwsFpgaTestBase.assert_vitis_setup() + + return + + def test_sw_emu(self, examplePath, rteName, xilinxVersion): + target = "sw_emu" + self.base_test(examplePath=examplePath, target=target, rteName=rteName, xilinxVersion=xilinxVersion, check=True) + + def test_hw_emu(self, examplePath, rteName, xilinxVersion): + target = "hw_emu" + self.base_test(examplePath=examplePath, target=target, rteName=rteName, xilinxVersion=xilinxVersion, check=True) + + def test_hw_build(self, examplePath, rteName, xilinxVersion): + target = "hw" + self.base_test(examplePath=examplePath, target=target, rteName=rteName, xilinxVersion=xilinxVersion, check=False) + + def check_build(self, examplePath, target): + + xclbin_path = self.get_vitis_xclbin_dir(examplePath, target) + + logger.info("Checking if Vitis Example xclbin path={} exists".format(xclbin_path)) + assert os.path.exists(xclbin_path), "Vitis Example xclbinpath={} does not exist".format(xclbin_path) + + logger.info("Checking that a non zero size xclbin file exists in {}".format(xclbin_path)) + xclbin = self.assert_non_zero_file(os.path.join(xclbin_path, "*.xclbin")) + logger.info("xclbin: {}".format(xclbin)) + + return xclbin + + def base_test(self, examplePath, target, rteName, xilinxVersion, clean=True, check=True): + + full_example_path = self.get_vitis_example_fullpath(examplePath=examplePath) + logger.info("Vitis Example path={}".format(full_example_path)) + + assert os.path.exists(full_example_path), "Vitis Example path={} does not exist".format(full_example_path) + + os.chdir(full_example_path) + + if clean: + (rc, stdout_lines, stderr_lines) = self.run_cmd("make clean") + assert rc == 0, "Vitis build failed while cleaning with rc={}".format(rc) + + check_string = "" + if check: + check_string = "check" + + (rc, stdout_lines, stderr_lines) = self.run_cmd("make {0} TARGET={1} DEVICE={2} all".format(check_string, target, os.environ['AWS_PLATFORM'])) + assert rc == 0, "Vitis build failed with rc={}".format(rc) + + # Check for non zero xclbin + xclbin = self.check_build(examplePath=examplePath, target=target) + + xclbin_key = os.path.join(self.get_vitis_example_s3_xclbin_tag(examplePath=examplePath, target=target, rteName=rteName, xilinxVersion=xilinxVersion), basename(xclbin)) + + logger.info("Uploading xclbin to {}".format(os.path.join(self.s3_bucket, xclbin_key))) + self.s3_client().upload_file(xclbin, self.s3_bucket, xclbin_key) + + return diff --git a/Vitis/tests/test_create_vitis_afi.py b/Vitis/tests/test_create_vitis_afi.py new file mode 100644 index 00000000..05f51b23 --- /dev/null +++ b/Vitis/tests/test_create_vitis_afi.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python2.7 + +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + +''' +Pytest module: + +Call using ```pytest test_create_vitis_afi.py``` + +See TESTING.md for details. +''' + +from __future__ import print_function +from __builtin__ import str +import boto3 +import os +from os.path import basename, dirname, realpath +import pytest +import re +import sys +import traceback +import json + +try: + import aws_fpga_test_utils + from aws_fpga_test_utils.AwsFpgaTestBase import AwsFpgaTestBase + import aws_fpga_utils +except ImportError as e: + traceback.print_tb(sys.exc_info()[2]) + print("error: {}\nMake sure to source shared/bin/setup_test_env.sh".format(sys.exc_info()[1])) + sys.exit(1) + +logger = aws_fpga_utils.get_logger(__name__) + +class TestCreateVitisAfi(AwsFpgaTestBase): + ''' + Pytest test class. + + NOTE: Cannot have an __init__ method. + + Create AFI from xclbin. + ''' + + ADD_EXAMPLEPATH = True + ADD_RTENAME = True + ADD_XILINX_VERSION = True + + @classmethod + def setup_class(cls): + ''' + Do any setup required for tests. + ''' + AwsFpgaTestBase.setup_class(cls, __file__) + + AwsFpgaTestBase.assert_sdk_setup() + AwsFpgaTestBase.assert_vitis_setup() + + return + + def call_create_afi_script(self, examplePath, xclbin, target, rteName, xilinxVersion): + + full_example_path = self.get_vitis_example_fullpath(examplePath=examplePath) + logger.info("Vitis Example path={}".format(full_example_path)) + + assert os.path.exists(full_example_path), "Vitis Example path={} does not exist".format(full_example_path) + + os.chdir(full_example_path) + + xclbin_basename = os.path.basename(xclbin) + xclbin_filename = os.path.splitext(xclbin_basename)[0] + aws_xclbin_filename_rte = xclbin_filename + + aws_xclbin_path = AwsFpgaTestBase.get_vitis_xclbin_dir(examplePath) + aws_xclbin_basename = os.path.join(aws_xclbin_path, aws_xclbin_filename_rte) + + cmd = "{}/Vitis/tools/create_vitis_afi.sh -s3_bucket={} -s3_dcp_key={} -xclbin={} -o={}".format( + self.WORKSPACE, + self.s3_bucket, + self.get_vitis_example_s3_dcp_tag(examplePath=examplePath, target=target, rteName=rteName, xilinxVersion=xilinxVersion), + xclbin, + aws_xclbin_basename + ) + + logger.info(cmd) + rc = os.system(cmd) + assert rc == 0, "Error encountered while running the create_vitis_afi.sh script" + + logger.info("Checking that a non zero size aws_xclbin file exists in {}".format(aws_xclbin_path)) + aws_xclbin = self.assert_non_zero_file(os.path.join(aws_xclbin_path, "*.awsxclbin")) + logger.info("Uploading aws_xclbin file: {}".format(aws_xclbin)) + + aws_xclbin_key = os.path.join(self.get_vitis_example_s3_xclbin_tag(examplePath=examplePath, target=target, rteName=rteName, xilinxVersion=xilinxVersion), basename(aws_xclbin)) + self.s3_client().upload_file(aws_xclbin, self.s3_bucket, aws_xclbin_key) + + create_afi_response_file = self.assert_non_zero_file(os.path.join(full_example_path, "*afi_id.txt")) + + create_afi_response_file_key = self.get_vitis_example_s3_afi_tag(examplePath=examplePath, target=target, rteName=rteName, xilinxVersion=xilinxVersion) + + logger.info("Uploading create_afi output file: {}".format(create_afi_response_file)) + self.s3_client().upload_file(create_afi_response_file, self.s3_bucket, create_afi_response_file_key) + + create_afi_response = json.load(open(create_afi_response_file)) + + return create_afi_response + + + def test_create_vitis_afi(self, examplePath, rteName, xilinxVersion, target="hw"): + + xclbin = self.get_vitis_xclbin_file(examplePath, rteName, xilinxVersion) + create_afi_response = self.call_create_afi_script(examplePath, xclbin, target, rteName, xilinxVersion) + + afi = create_afi_response.get("FpgaImageId", None) + + assert afi is not None, "AFI ID not available in create_afi response:{}".format(str(create_afi_response)) + + # Wait for the AFI to complete + rc = os.system(self.WORKSPACE + "/shared/bin/scripts/wait_for_afi.py --afi {}".format(afi)) + assert rc == 0, "Error while waiting for afi={}".format(afi) + + self.assert_afi_available(afi) diff --git a/Vitis/tests/test_find_vitis_examples.py b/Vitis/tests/test_find_vitis_examples.py new file mode 100644 index 00000000..9d54393c --- /dev/null +++ b/Vitis/tests/test_find_vitis_examples.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python2.7 + +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. +''' +Pytest module: + +Call using ```pytest test_find_vitis_examples.py``` + +See TESTING.md for details. +''' + +from __future__ import print_function +import os +from os.path import dirname, realpath +import json +try: + import aws_fpga_utils + import aws_fpga_test_utils + from aws_fpga_test_utils.AwsFpgaTestBase import AwsFpgaTestBase +except ImportError as e: + traceback.print_tb(sys.exc_info()[2]) + print("error: {}\nMake sure to source shared/bin/setup_test_env.sh".format(sys.exc_info()[1])) + sys.exit(1) + +logger = aws_fpga_utils.get_logger(__name__) + +class TestFindVitisExamples(AwsFpgaTestBase): + ''' + Pytest test class. + + NOTE: Cannot have an __init__ method. + + ''' + ADD_XILINX_VERSION = True + + @classmethod + def setup_class(cls): + ''' + Do any setup required for tests. + ''' + AwsFpgaTestBase.setup_class(cls, __file__) + return + + def test_find_example_makefiles(self, xilinxVersion): + + assert os.path.exists(self.xilinx_vitis_examples_dir), "The Xilinx Vitis example dir does not exist: {}".format(self.xilinx_vitis_examples_dir) + assert os.listdir(self.xilinx_vitis_examples_dir) != [], "Xilinx Vitis example submodule not cloned or does not exist" + + xilinx_examples_makefiles = [] + xilinx_vitis_example_map = {} + + for root, dirs, files in os.walk(self.xilinx_vitis_examples_dir): + ignore = False + + if os.path.exists(root + "/description.json") and os.path.exists(root + "/Makefile"): + with open(root + "/description.json", "r") as description_file: + description = json.load(description_file) + + if "containers" in description: + if len(description["containers"]) > 1: + ignore = True + logger.info("Ignoring {} as >1 containers found in description.json.".format(root)) + else: + ignore = True + logger.info("Ignoring {} as no containers found in description.json.".format(root)) + continue + + if "ndevice" in description: + if "aws" in description["ndevice"]: + ignore = True + logger.info("Ignoring {} as F1 device found in ndevice.".format(root)) + continue + else: + ignore = True + logger.warn("Ignoring: {} as no Makefile/description.json exist".format(root)) + + if not ignore: + xilinx_examples_makefiles.append(root) + logger.info("Adding: " + root) + + assert len(xilinx_examples_makefiles) != 0, "Could not find any Xilinx Vitis example in %s" % self.xilinx_vitis_examples_dir + + # Remove the workspace path so that the next node can reference this path directly + # So we don't face cases like /workspace@3 .. + xilinx_examples_makefiles = [os.path.relpath(full_path, self.WORKSPACE) for full_path in xilinx_examples_makefiles] + + for example_path in xilinx_examples_makefiles: + + example_test_class = example_path.replace('/', '__').capitalize() + + xilinx_vitis_example_map[example_test_class] = example_path + + with open(self.xilinx_vitis_examples_list_file, 'w') as outfile: + json.dump(xilinx_vitis_example_map, outfile) + + # Also write the archive file + with open(self.xilinx_vitis_examples_list_file + "." + xilinxVersion, 'w') as archive_file: + json.dump(xilinx_vitis_example_map, archive_file) + + assert os.path.getsize(self.xilinx_vitis_examples_list_file) > 0, "%s is a non zero file. We need to have some data in the file" % self.xilinx_vitis_examples_list_file diff --git a/Vitis/tests/test_run_vitis_example.py b/Vitis/tests/test_run_vitis_example.py new file mode 100644 index 00000000..ec24b6dc --- /dev/null +++ b/Vitis/tests/test_run_vitis_example.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python2.7 + +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + +''' +Pytest module: + +Call using ```pytest test_create_afi.py``` + +See TESTING.md for details. +''' + +from __future__ import print_function +import boto3 +import os +from os.path import basename, dirname, realpath +import pytest +import re +import sys +import traceback +import json +try: + import aws_fpga_test_utils + from aws_fpga_test_utils.AwsFpgaTestBase import AwsFpgaTestBase + import aws_fpga_utils +except ImportError as e: + traceback.print_tb(sys.exc_info()[2]) + print("error: {}\nMake sure to source shared/bin/setup_test_env.sh".format(sys.exc_info()[1])) + sys.exit(1) + +logger = aws_fpga_utils.get_logger(__name__) + +class TestRunVitisExample(AwsFpgaTestBase): + ''' + Pytest test class. + + NOTE: Cannot have an __init__ method. + + Run the Vitis example + ''' + + ADD_EXAMPLEPATH = True + ADD_RTENAME = True + ADD_XILINX_VERSION = True + + @classmethod + def setup_class(cls): + ''' + Do any setup required for tests. + ''' + AwsFpgaTestBase.setup_class(cls, __file__) + + AwsFpgaTestBase.assert_sdk_setup() + AwsFpgaTestBase.assert_vitis_setup() + + return + + @pytest.mark.flaky(reruns=2, reruns_delay=2) + def test_run_vitis_example(self, examplePath, rteName, xilinxVersion): + os.chdir(self.get_vitis_example_fullpath(examplePath)) + + (rc, stdout_lines, stderr_lines) = self.run_cmd("make exe") + assert rc == 0 + + em_run_cmd = self.get_vitis_example_run_cmd(examplePath, xilinxVersion) + check_runtime_script = os.path.join(AwsFpgaTestBase.WORKSPACE,'vitis_runtime_setup.sh') + + self.get_vitis_aws_xclbin_file(examplePath, rteName, xilinxVersion) + + # run_cmd = "sudo -E /bin/bash -l -c \"source {} && {} \"".format(check_runtime_script, em_run_cmd) + run_cmd = "source {} && sleep 1m && {}".format(check_runtime_script, em_run_cmd) + logger.info("Running cmd={}".format(run_cmd)) + (rc, stdout_lines, stderr_lines) = self.run_cmd(run_cmd) + assert rc == 0 + + diff --git a/Vitis/tests/test_vitis_scripts.py b/Vitis/tests/test_vitis_scripts.py new file mode 100644 index 00000000..e106c1b6 --- /dev/null +++ b/Vitis/tests/test_vitis_scripts.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python2.7 + +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function +import logging +import os +from os.path import dirname, realpath +import pytest +import subprocess +import sys +import traceback +try: + import aws_fpga_utils + import aws_fpga_test_utils + from aws_fpga_test_utils.AwsFpgaTestBase import AwsFpgaTestBase +except ImportError as e: + traceback.print_tb(sys.exc_info()[2]) + print("error: {}\nMake sure to source hdk_setup.sh".format(sys.exc_info()[1])) + sys.exit(1) + +logger = aws_fpga_utils.get_logger(__name__) + +class TestVitisScripts(AwsFpgaTestBase): + ''' + Pytest test class. + + NOTE: Cannot have an __init__ method. + ''' + + @classmethod + def setup_class(cls): + ''' + Do any setup required for tests. + ''' + AwsFpgaTestBase.setup_class(cls, __file__) + + AwsFpgaTestBase.assert_sdaccel_setup() + return + + @pytest.mark.skip(reason="Not implemented") + def test_vitis_setup(self): + assert False diff --git a/Vitis/tools/create_vitis_afi.sh b/Vitis/tools/create_vitis_afi.sh new file mode 100755 index 00000000..d6717019 --- /dev/null +++ b/Vitis/tools/create_vitis_afi.sh @@ -0,0 +1,286 @@ +#!/bin/bash + +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +script=${BASH_SOURCE[0]} +full_script=$(readlink -f $script) +script_name=$(basename $full_script) + +source $AWS_FPGA_REPO_DIR/shared/bin/set_common_functions.sh +source $AWS_FPGA_REPO_DIR/shared/bin/set_common_env_vars.sh + +debug=0 + +function usage { + info_msg "USAGE: $script_name [-h|-help] [-s3_bucket=] [-s3_dcp_key=] [-s3_logs_key=] [-xclbin=] [-o=] [-awsprofile=]" +} + +function help { + info_msg "$script_name" + info_msg " " + info_msg "Vitis AFI Creation" + info_msg " " + info_msg "create_vitis_afi.sh assumes you have:" + info_msg " (*) Read the README on Github and understand the Vitis workflow (Vitis/README.md)" + info_msg " (*) Generated an XCLBIN using the Vitis Build flow" + info_msg " (*) Ready to create an AFI and test on F1. Your kernel has been validated using SW/HW Emulation." + info_msg "create_vitis_afi.sh will:" + info_msg " (1) Extract three parts from your XCLBIN: DCP (.dcp) , clocks data(.json) and build metadata (.json)" + info_msg " (2) Generates a Manifest file for AFI creation that sets the clocks based on your achieved target freq from your build" + info_msg " (3) Prepares tar file for AFI creation process" + info_msg " (4) Calls aws ec2 create-fpga-image" + info_msg " (5) Creates new XCLBIN (called AWSXCLBIN) that is composed of: Metadata and AGFI-ID" + echo " " + usage +} + +if [ "$1" == "" ] +then + err_msg "Invalid usage" + usage + exit 1 +fi + +while [ "$1" != "" ]; do + PARAM=`echo $1 | awk -F= '{print $1}'` + VALUE=`echo $1 | awk -F= '{print $2}'` + case $PARAM in + -h | --help) + help + exit + ;; + -xclbin) + xclbin=$VALUE + ;; + -o) + awsxclbin=$VALUE + ;; + -aws_profile_name) + aws_profile_name=$VALUE + ;; + -s3_bucket) + s3_bucket=$VALUE + ;; + -s3_logs_key) + s3_logs=$VALUE + ;; + -s3_dcp_key) + s3_dcps=$VALUE + ;; + *) + err_msg "Unknown parameter \"$PARAM\"" + usage + exit 1 + ;; + esac + shift +done + +if [ "$HDK_DIR" == "" ] +then + err_msg "Env HDK_DIR not set" + exit 1 +fi +echo $HDK_DIR +if [ "$RELEASE_VER" == "" ] +then + err_msg "Env variable RELEASE_VER not set, did you source sdaccel_setup.sh?" + exit 1 +fi + +if [[ -e "$xclbin" ]] +then + info_msg "Found xclbin '$xclbin'" +else + err_msg "File '$xclbin' not found" + exit 1 +fi + +stripped_xclbin=$(basename $xclbin) +ext_xclbin=${stripped_xclbin##*.} +stripped_xclbin=${stripped_xclbin%.*} + +info_msg "$stripped_xclbin" + +if [ "$awsxclbin" == "" ] +then + awsxclbin=$stripped_xclbin +fi + + +if [ "$awsxclbin" != "$stripped_xclbin" ] +then + warn_msg "$awsxclbin does not match $stripped_xclbin" + warn_msg "For github examples, -o must be equal to $stripped_xclbin" +fi + +if [[ -e "$awsxclbin" ]] +then + err_msg "File '$awsxclbin' already exists" + exit 1 +fi + +if [ ":$s3_bucket" == ":" ] +then + err_msg "Invalid s3_bucket" + usage + exit 1 +fi + +# s3 logs is not required +# s3 dcp key is required +if [ "$s3_dcps" == "" ] +then + err_msg "Invalid s3_dcps key" + usage + exit 1 +fi + +timestamp=$(date +"%y_%m_%d-%H%M%S") + +#Steps +#1. Strip XCLBIN to get DCP for ingestion +#2. Create Manifest file +#3. Prepare ingestion tar file +#4. Call create-fpga-image +#5. Manipulate the AFI ID +#6. Create awsxclbin + +#STEP 1 +#Strip XCLBIN to get DCP for ingestion +#/opt/xilinx/xrt/bin/xclbinsplit -o ${timestamp} $xclbin +/opt/xilinx/xrt/bin/xclbinutil --dump-section BUILD_METADATA:JSON:${timestamp}_build.json --dump-section CLOCK_FREQ_TOPOLOGY:JSON:${timestamp}_clocks.json --dump-section BITSTREAM:RAW:${timestamp}_SH_CL_routed.dcp -i $xclbin +if [[ -e "${timestamp}_SH_CL_routed.dcp" ]] +then + info_msg "Split DCP from xclbin: ${timestamp}_SH_CL_routed.dcp" +else + err_msg "File ${timestamp}_SH_CL_routed.dcp not found" + exit 1 +fi +if [[ -e "${timestamp}_build.json" ]] +then + info_msg "The build Metadata from xclbin: ${timestamp}_build.json" +else + err_msg "File ${timestamp}_build.json not found" + exit 1 +fi +if [[ -e "${timestamp}_clocks.json" ]] +then + info_msg "The clocks Metadata from xclbin: ${timestamp}_clocks.json" +else + err_msg "File ${timestamp}_clocks.json not found" + exit 1 +fi + +if [[ -d "to_aws" ]] +then + err_msg "Directory to_aws already exists" + exit 1 +fi + +mkdir to_aws +cp ${timestamp}_SH_CL_routed.dcp ./to_aws/ + +#STEP 2 +#Create Manifest file +strategy=DEFAULT +hdk_version=$(grep 'HDK_VERSION' $HDK_DIR/hdk_version.txt | sed 's/=/ /g' | awk '{print $2}') +shell_version=0x04261818 +tool_version=v$RELEASE_VER +device_id=0xF010 +vendor_id=0x1D0F +subsystem_id=0x1D51 +subsystem_vendor_id=0xFEDD +# Get XSA info from build metadata +vendor=$(echo `grep -A 6 dsa ./${timestamp}_build.json | grep vendor | sed 's/.*: "//g' | sed 's/",//'`) +board_id=$(echo `grep -A 6 dsa ./${timestamp}_build.json | grep board_id | sed 's/.*: "//g' | sed 's/",//'`) +plat_name=$(echo `grep -A 6 dsa ./${timestamp}_build.json | grep name | sed 's/.*: "//g' | sed 's/",//'`) +major=$(echo `grep -A 6 dsa ./${timestamp}_build.json | grep major | sed 's/.*: "//g' | sed 's/",//'`) +minor=$(echo `grep -A 6 dsa ./${timestamp}_build.json | grep minor | sed 's/.*: "//g' | sed 's/",//'`) +# Get clock info from clock metadata +clock_main_a0=$(echo `grep -B 1 SYSTEM ${timestamp}_clocks.json | grep -o -e '[0-9]*'`) +clock_extra_b0=$(echo `grep -B 2 DATA_CLK ${timestamp}_clocks.json | grep freq | grep -o -e '[0-9]*'`) +clock_extra_c0=$(echo `grep -B 2 KERNEL_CLK ${timestamp}_clocks.json | grep -o -e '[0-9]*'`) + +if [[ "$vendor" != "xilinx" && "$board_id" != "aws-vu9p-f1" && "$plat_name" != "shell-v04261818" && "$major" != "201920" && "$minor" != "1" ]] +then + err_msg "Platform ${vendor}_${board_id}_${plat_name}_${major}_${minor} used to create xclbin is not correct, you should be using xilinx_aws-vu9p-f1_shell-v04261818_201920_1" + exit +fi + +#Write Manifest File here +hash=$( sha256sum to_aws/${timestamp}_SH_CL_routed.dcp | awk '{ print $1 }' ) +manifest_file="${timestamp}_manifest.txt" +exec 3<>$manifest_file +echo "manifest_format_version=2" >&3 +echo "pci_vendor_id=$vendor_id" >&3 +echo "pci_device_id=$device_id" >&3 +echo "pci_subsystem_id=$subsystem_id" >&3 +echo "pci_subsystem_vendor_id=$subsystem_vendor_id" >&3 +echo "dcp_hash=$hash" >&3 +echo "shell_version=$shell_version" >&3 +echo "dcp_file_name=${timestamp}_SH_CL_routed.dcp" >&3 +echo "hdk_version=$hdk_version" >&3 +echo "tool_version=$tool_version" >&3 +echo "date=$timestamp" >&3 +echo "clock_main_a0=$clock_main_a0" >&3 +echo "clock_extra_b0=$clock_extra_b0" >&3 +echo "clock_extra_c0=$clock_extra_c0" >&3 +exec 3>&- +exec 3>&- + +if [[ -e "$manifest_file" ]] +then + info_msg "Generated manifest file '$manifest_file'" +else + err_msg "File '$manifest_file' not found" + exit 1 +fi +cp $manifest_file to_aws/$manifest_file + + +#STEP 3 +#Prepare ingestion +tar -cf ${timestamp}_Developer_Vitis_Kernel.tar to_aws/${timestamp}_SH_CL_routed.dcp to_aws/${timestamp}_manifest.txt +#STEP 4 +#Call create-fpga-image +profile_text="" +if [ "$aws_profile_name" != "" ] +then + profile_text="--profile ${aws_profile_name}" +fi + +log_storage_text="" +if [ "${s3_logs}" != "" ] +then + log_storage_text="--logs-storage-location Bucket=${s3_bucket},Key=${s3_logs}" +fi + +aws s3 ${profile_text} cp ${timestamp}_Developer_Vitis_Kernel.tar s3://${s3_bucket}/${s3_dcps}/ +aws ec2 ${profile_text} create-fpga-image --name ${stripped_xclbin} --description ${stripped_xclbin} --input-storage-location Bucket=${s3_bucket},Key=${s3_dcps}/${timestamp}_Developer_Vitis_Kernel.tar ${log_storage_text} > ${timestamp}_afi_id.txt + + +#STEP 5 +#Manipulate the AFI ID +test=`grep agfi ${timestamp}_afi_id.txt | awk -F: '{print $2}' | sed 's/ \"//g' | sed 's/\".*//g' | sed ':a;N;$!ba;s/\n/ /g'` +echo -n $test > ${timestamp}_agfi_id.txt +echo ${timestamp}_agfi_id.txt + +#STEP 6 +#Create .awsxclbin +/opt/xilinx/xrt/bin/xclbinutil -i $xclbin --remove-section PARTITION_METADATA --remove-section SYSTEM_METADATA --replace-section BITSTREAM:RAW:${timestamp}_agfi_id.txt -o ${awsxclbin}.awsxclbin diff --git a/Vitis/vitis_xrt_version.txt b/Vitis/vitis_xrt_version.txt new file mode 100644 index 00000000..e37a320d --- /dev/null +++ b/Vitis/vitis_xrt_version.txt @@ -0,0 +1 @@ +2019.2:9e13d57c4563e2c19bf5f518993f6e5a8dadc18a \ No newline at end of file diff --git a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile index 496e44ea..8671cd45 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile +++ b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile @@ -22,7 +22,8 @@ endif export TEST ?= test_null export C_TEST ?= test_null -export CL_ROOT = $(PWD)/../.. +export SCRIPTS_DIR = $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +export CL_ROOT = $(realpath $(SCRIPTS_DIR)/../..) export SDK_DIR = $(AWS_FPGA_REPO_DIR)/sdk export C_COMMON_DIR = $(HDK_COMMON_DIR)/software @@ -45,29 +46,29 @@ ifeq ($(C_TEST),test_null) ifeq ($(AXI_MEMORY_MODEL), 1) ifeq ($(ECC_DIRECT), 1) export SIM_DIR = $(SIM_ROOT)/$(TEST)_sv_fast_ecc_direct - else + else ifeq ($(ECC_RAND), 1) export SIM_DIR = $(SIM_ROOT)/$(TEST)_sv_fast_ecc_rnd else ifeq ($(DDR_BKDR), 1) export SIM_DIR = $(SIM_ROOT)/$(TEST)_sv_fast_bkdr - else + else export SIM_DIR = $(SIM_ROOT)/$(TEST)_sv_fast - endif + endif endif endif else ifeq ($(ECC_DIRECT), 1) export SIM_DIR = $(SIM_ROOT)/$(TEST)_sv_ecc_direct - else + else ifeq ($(ECC_RAND), 1) export SIM_DIR = $(SIM_ROOT)/$(TEST)_sv_ecc_rnd else ifeq ($(DDR_BKDR), 1) export SIM_DIR = $(SIM_ROOT)/$(TEST)_sv_bkdr - else + else export SIM_DIR = $(SIM_ROOT)/$(TEST)_sv - endif + endif endif endif endif @@ -75,7 +76,6 @@ else export SIM_DIR = $(SIM_ROOT)/$(C_TEST)_c endif -export SCRIPTS_DIR = $(PWD) export XILINX_IP = $(HDK_SHELL_DESIGN_DIR)/ip export SH_LIB_DIR = $(HDK_SHELL_DESIGN_DIR)/lib export SH_INF_DIR = $(HDK_SHELL_DESIGN_DIR)/interfaces diff --git a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa index 808b23c2..f0fbe206 100644 --- a/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa +++ b/hdk/cl/examples/cl_dram_dma/verif/scripts/Makefile.questa @@ -22,37 +22,21 @@ ## 2. make all QUESTA=1 -> Runs the test ################################################################## +LIBLISTS = $(COMMON_LIBLISTS) +LIBLISTS_ARGS = $(shell echo " $(strip $(LIBLISTS))" | sed 's|\ | -L |g') + compile: $(COMPLIB_DIR) mkdir -p $(SIM_DIR) cd ${SIM_DIR} && ln -s -f ../questa_complib/modelsim.ini cd $(SIM_DIR) && vlog $(C_FILES) -ccflags "-I$(C_SDK_USR_INC_DIR)" -ccflags "-I$(C_SDK_USR_UTILS_DIR)" -ccflags "-I$(C_COMMON_DIR)/include" -ccflags "-I$(C_COMMON_DIR)/src" -ccflags "-DSV_TEST" -ccflags "-DSCOPE" -ccflags "-DQUESTA_SIM" -ccflags "-DINT_MAIN" -ccflags "-I$(C_INC_DIR)" cd $(SIM_DIR) && vlog +define+DMA_TEST $(DEFAULT_DEFINES) -mfcu -sv -64 -timescale 1ps/1ps -93 -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/secureip -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f + run: -ifeq ($(VIVADO_TOOL_VERSION), v2017.4) ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_15 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_16 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_14 -L $(COMPLIB_DIR)/fifo_generator_v13_2_1 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_14 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 $(PLUSARGS) -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random $(LIBLISTS_ARGS) $(PLUSARGS) -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_15 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_16 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_14 -L $(COMPLIB_DIR)/fifo_generator_v13_2_1 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_14 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 $(PLUSARGS) -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif -else ifeq ($(VIVADO_TOOL_VERSION), v2018.3) -ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_2_3 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 $(PLUSARGS) -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) -else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_2_3 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 $(PLUSARGS) -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif -else ifeq ($(VIVADO_TOOL_VERSION), v2019.1) -ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 $(PLUSARGS) -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) -else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 $(PLUSARGS) -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif -else -ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_2_2 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 $(PLUSARGS) -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) -else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_2_2 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 $(PLUSARGS) -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random $(LIBLISTS_ARGS) $(PLUSARGS) -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) endif $(COMPLIB_DIR): diff --git a/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile b/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile index 0531c878..6347104a 100644 --- a/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile +++ b/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile @@ -22,7 +22,8 @@ endif export TEST ?= test_null export C_TEST ?= test_null -export CL_ROOT = $(PWD)/../.. +export SCRIPTS_DIR = $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +export CL_ROOT = $(realpath $(SCRIPTS_DIR)/../..) export SDK_DIR = $(AWS_FPGA_REPO_DIR)/sdk export C_COMMON_DIR = $(HDK_COMMON_DIR)/software @@ -47,15 +48,13 @@ else export SIM_DIR = $(SIM_ROOT)/$(C_TEST)_c endif - -export SCRIPTS_DIR = $(PWD) export XILINX_IP = $(HDK_SHELL_DESIGN_DIR)/ip export SH_LIB_DIR = $(HDK_SHELL_DESIGN_DIR)/lib export SH_INF_DIR = $(HDK_SHELL_DESIGN_DIR)/interfaces export SH_SH_DIR = $(HDK_SHELL_DESIGN_DIR)/sh_ddr/sim SV_TEST_LIST = test_hello_world -C_FILES = $(C_TEST_NAME) $(C_SDK_USR_UTILS_DIR)/sh_dpi_tasks.c $(C_COMMON_DIR)/src/fpga_pci_sv.c +C_FILES = $(C_TEST_NAME) $(C_SDK_USR_UTILS_DIR)/sh_dpi_tasks.c $(C_COMMON_DIR)/src/fpga_pci_sv.c ifeq ($(XCHK), 1) all: make_sim_dir compile_chk run diff --git a/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.questa index 3b5b17d1..188155df 100644 --- a/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.questa +++ b/hdk/cl/examples/cl_hello_world/verif/scripts/Makefile.questa @@ -17,47 +17,30 @@ ################################################################## ## Makefile For Questa compiles and simulations ## Step to run : -## 1. make create_libs QUESTA=1 -> To generate xilinx compile +## 1. make create_libs QUESTA=1 -> To generate xilinx compile ## libraries. This is a one time step ## 2. make all QUESTA=1 -> Runs the test ################################################################## +LIBLISTS = $(COMMON_LIBLISTS) +LIBLISTS_ARGS = $(shell echo " $(strip $(LIBLISTS))" | sed 's|\ | -L |g') + compile: $(COMPLIB_DIR) mkdir -p $(SIM_DIR) - cd ${SIM_DIR} && ln -s -f ../questa_complib/modelsim.ini - cd $(SIM_DIR) && vlog $(C_FILES) -ccflags "-I$(C_SDK_USR_INC_DIR)" -ccflags "-I$(C_SDK_USR_UTILS_DIR)" -ccflags "-I$(C_COMMON_DIR)/include" -ccflags "-I$(C_COMMON_DIR)/src" -ccflags "-DSV_TEST" -ccflags "-DSCOPE" -ccflags "-DQUESTA_SIM" -ccflags "-DINT_MAIN" -ccflags "-I$(C_INC_DIR)" + cd ${SIM_DIR} && ln -s -f ../questa_complib/modelsim.ini + cd $(SIM_DIR) && vlog $(C_FILES) -ccflags "-I$(C_SDK_USR_INC_DIR)" -ccflags "-I$(C_SDK_USR_UTILS_DIR)" -ccflags "-I$(C_COMMON_DIR)/include" -ccflags "-I$(C_COMMON_DIR)/src" -ccflags "-DSV_TEST" -ccflags "-DSCOPE" -ccflags "-DQUESTA_SIM" -ccflags "-DINT_MAIN" -ccflags "-I$(C_INC_DIR)" cd $(SIM_DIR) && vlog -mfcu -sv -64 -timescale 1ps/1ps -93 -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/secureip -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f run: -ifeq ($(VIVADO_TOOL_VERSION), v2017.4) -ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_15 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_16 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_14 -L $(COMPLIB_DIR)/fifo_generator_v13_2_1 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_14 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) -else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_15 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_16 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_14 -L $(COMPLIB_DIR)/fifo_generator_v13_2_1 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_14 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif -else ifeq ($(VIVADO_TOOL_VERSION), v2018.3) -ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_2_3 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) -else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_2_3 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif -else ifeq ($(VIVADO_TOOL_VERSION), v2019.1) -ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) -else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif -else ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_2_2 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random $(LIBLISTS_ARGS) -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_2_2 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random $(LIBLISTS_ARGS) -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) endif $(COMPLIB_DIR): cd $(SIM_ROOT) && echo "compile_simlib -language all -dir $(COMPLIB_DIR) -simulator $(SIMULATOR) -library all -family all" > create_libs.tcl cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl - cd $(SIM_ROOT) && rm -rf create_libs.tcl + cd $(SIM_ROOT) && rm -rf create_libs.tcl diff --git a/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile b/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile index 76a16792..adb03a8e 100644 --- a/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile +++ b/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile @@ -22,7 +22,8 @@ endif export TEST ?= test_null export C_TEST ?= test_null -export CL_ROOT = $(PWD)/../.. +export SCRIPTS_DIR = $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +export CL_ROOT = $(realpath $(SCRIPTS_DIR)/../..) export C_INC_DIR = $(CL_ROOT)/software/verif_rtl/include export C_SRC_DIR = $(CL_ROOT)/software/verif_rtl/src @@ -40,7 +41,6 @@ else endif -export SCRIPTS_DIR = $(PWD) export XILINX_IP = $(HDK_SHELL_DESIGN_DIR)/ip export SH_LIB_DIR = $(HDK_SHELL_DESIGN_DIR)/lib export SH_INF_DIR = $(HDK_SHELL_DESIGN_DIR)/interfaces diff --git a/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.questa index 7e4285e2..19c18b94 100644 --- a/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.questa +++ b/hdk/cl/examples/cl_hello_world_vhdl/verif/scripts/Makefile.questa @@ -22,24 +22,18 @@ ## 2. make all QUESTA=1 -> Runs the test ################################################################## +LIBLISTS = $(COMMON_LIBLISTS) +LIBLISTS_ARGS = $(shell echo " $(strip $(LIBLISTS))" | sed 's|\ | -L |g') + compile: $(COMPLIB_DIR) mkdir -p $(SIM_DIR) cd ${SIM_DIR} && ln -s -f ../questa_complib/modelsim.ini cd $(SIM_DIR) && vlog $(C_TEST_NAME) -ccflags "-I$(C_INC_DIR)" - cd $(SIM_DIR) && vcom -work work -64 -93 -f $(SCRIPTS_DIR)/top_vhdl.$(SIMULATOR).f + cd $(SIM_DIR) && vcom -work work -64 -93 -f $(SCRIPTS_DIR)/top_vhdl.$(SIMULATOR).f cd $(SIM_DIR) && vlog -mfcu -sv -64 -timescale 1ps/1ps -93 -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/secureip -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f run: -ifeq ($(VIVADO_TOOL_VERSION), v2017.4) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_15 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_16 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_14 -L $(COMPLIB_DIR)/fifo_generator_v13_2_1 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_14 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -do "run -all; quit -f" tb glbl $(TEST) -else ifeq ($(VIVADO_TOOL_VERSION), v2018.3) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_2_3 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -do "run -all; quit -f" tb glbl $(TEST) -else ifeq ($(VIVADO_TOOL_VERSION), v2019.1) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -do "run -all; quit -f" tb glbl $(TEST) -else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_2_2 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -do "run -all; quit -f" tb glbl $(TEST) -endif - + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random $(LIBLISTS_ARGS) -do "run -all; quit -f" tb glbl $(TEST) $(COMPLIB_DIR): cd $(SIM_ROOT) && echo "compile_simlib -language all -dir $(COMPLIB_DIR) -simulator $(SIMULATOR) -library all -family all" > create_libs.tcl diff --git a/hdk/cl/examples/cl_sde/verif/scripts/Makefile b/hdk/cl/examples/cl_sde/verif/scripts/Makefile index 793c0d20..746af12b 100644 --- a/hdk/cl/examples/cl_sde/verif/scripts/Makefile +++ b/hdk/cl/examples/cl_sde/verif/scripts/Makefile @@ -21,8 +21,9 @@ endif export TEST ?= test_null export C_TEST ?= test_null - -export CL_ROOT = $(PWD)/../.. + +export SCRIPTS_DIR = $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +export CL_ROOT = $(realpath $(SCRIPTS_DIR)/../..) export SDK_DIR = $(AWS_FPGA_REPO_DIR)/sdk export C_COMMON_DIR = $(HDK_COMMON_DIR)/software @@ -30,7 +31,7 @@ export C_SDK_USR_INC_DIR = $(SDK_DIR)/userspace/include export C_SDK_USR_UTILS_DIR = $(SDK_DIR)/userspace/utils export C_INC_DIR = $(CL_ROOT)/software/runtime export C_SRC_DIR = $(CL_ROOT)/software/src - + export TEST_NAME = $(CL_ROOT)/verif/tests/$(TEST).sv ifeq ($(C_TEST),test_null) @@ -47,13 +48,11 @@ else export SIM_DIR = $(SIM_ROOT)/$(C_TEST) endif - -export SCRIPTS_DIR = $(PWD) export XILINX_IP = $(HDK_SHELL_DESIGN_DIR)/ip export SH_LIB_DIR = $(HDK_SHELL_DESIGN_DIR)/lib export SH_INF_DIR = $(HDK_SHELL_DESIGN_DIR)/interfaces export SH_SH_DIR = $(HDK_SHELL_DESIGN_DIR)/sh_ddr/sim - + SV_TEST_LIST = test_null.sv C_FILES = $(C_TEST_NAME) $(C_SDK_USR_UTILS_DIR)/sh_dpi_tasks.c $(C_COMMON_DIR)/src/fpga_pci_sv.c @@ -62,6 +61,6 @@ ifeq ($(XCHK), 1) else all: make_sim_dir compile run endif - + include $(HDK_COMMON_DIR)/verif/tb/scripts/Makefile.common.inc diff --git a/hdk/cl/examples/cl_sde/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_sde/verif/scripts/Makefile.questa index decab5be..16058390 100644 --- a/hdk/cl/examples/cl_sde/verif/scripts/Makefile.questa +++ b/hdk/cl/examples/cl_sde/verif/scripts/Makefile.questa @@ -22,6 +22,9 @@ ## 2. make all QUESTA=1 -> Runs the test ################################################################## +LIBLISTS = $(COMMON_LIBLISTS) +LIBLISTS_ARGS = $(shell echo " $(strip $(LIBLISTS))" | sed 's|\ | -L |g') + compile: $(COMPLIB_DIR) mkdir -p $(SIM_DIR) cd ${SIM_DIR} && ln -s -f ../questa_complib/modelsim.ini @@ -29,30 +32,10 @@ compile: $(COMPLIB_DIR) cd $(SIM_DIR) && vlog -mfcu -sv -64 -timescale 1ps/1ps -93 -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/secureip -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f run: -ifeq ($(VIVADO_TOOL_VERSION), v2017.4) -ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_15 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_16 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_14 -L $(COMPLIB_DIR)/fifo_generator_v13_2_1 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_14 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) -else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_15 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_16 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_14 -L $(COMPLIB_DIR)/fifo_generator_v13_2_1 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_14 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif -else ifeq ($(VIVADO_TOOL_VERSION), v2018.3) -ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_2_3 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) -else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_2_3 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif -else ifeq ($(VIVADO_TOOL_VERSION), v2019.1) -ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) -else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_2_4 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif -else ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_2_2 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random $(LIBLISTS_ARGS) -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_2_2 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random $(LIBLISTS_ARGS) -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) endif $(COMPLIB_DIR): diff --git a/hdk/cl/examples/cl_sde/verif/scripts/Makefile.vcs b/hdk/cl/examples/cl_sde/verif/scripts/Makefile.vcs index dc2f5f3e..67b92dd4 100644 --- a/hdk/cl/examples/cl_sde/verif/scripts/Makefile.vcs +++ b/hdk/cl/examples/cl_sde/verif/scripts/Makefile.vcs @@ -29,7 +29,7 @@ compile: $(COMPLIB_DIR) cd $(SIM_DIR) && vcs tb $(TEST) $(C_FILES) -CFLAGS "-I$(C_SDK_USR_INC_DIR)" -CFLAGS "-I$(C_SDK_USR_UTILS_DIR)" -CFLAGS "-I$(C_COMMON_DIR)/include" -CFLAGS "-I$(C_COMMON_DIR)/src" -CFLAGS "-DSV_TEST" -CFLAGS "-DSCOPE" -CFLAGS "-I$(C_INC_DIR)" -debug_all -M +lint=TFIPC-L -debug_pp glbl -ntb_opts tb_timescale=1ps/1ps -timescale=1ps/1ps -sverilog -full64 +memcbk -licqueue -lca -v2005 -l compile.vcs.log run: - cd $(SIM_DIR) && ./simv -l -l $(TEST).log $(PLUSARGS) +ntb_random_seed_automatic +vpdfile+$(TEST).vpd + cd $(SIM_DIR) && ./simv -l $(TEST).log $(PLUSARGS) +ntb_random_seed_automatic +vpdfile+$(TEST).vpd $(COMPLIB_DIR): cd $(SIM_ROOT) && echo "compile_simlib -language all -dir $(COMPLIB_DIR) -simulator $(SIMULATOR) -library all -family all" > create_libs.tcl diff --git a/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile b/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile index 0531c878..6347104a 100644 --- a/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile +++ b/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile @@ -22,7 +22,8 @@ endif export TEST ?= test_null export C_TEST ?= test_null -export CL_ROOT = $(PWD)/../.. +export SCRIPTS_DIR = $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +export CL_ROOT = $(realpath $(SCRIPTS_DIR)/../..) export SDK_DIR = $(AWS_FPGA_REPO_DIR)/sdk export C_COMMON_DIR = $(HDK_COMMON_DIR)/software @@ -47,15 +48,13 @@ else export SIM_DIR = $(SIM_ROOT)/$(C_TEST)_c endif - -export SCRIPTS_DIR = $(PWD) export XILINX_IP = $(HDK_SHELL_DESIGN_DIR)/ip export SH_LIB_DIR = $(HDK_SHELL_DESIGN_DIR)/lib export SH_INF_DIR = $(HDK_SHELL_DESIGN_DIR)/interfaces export SH_SH_DIR = $(HDK_SHELL_DESIGN_DIR)/sh_ddr/sim SV_TEST_LIST = test_hello_world -C_FILES = $(C_TEST_NAME) $(C_SDK_USR_UTILS_DIR)/sh_dpi_tasks.c $(C_COMMON_DIR)/src/fpga_pci_sv.c +C_FILES = $(C_TEST_NAME) $(C_SDK_USR_UTILS_DIR)/sh_dpi_tasks.c $(C_COMMON_DIR)/src/fpga_pci_sv.c ifeq ($(XCHK), 1) all: make_sim_dir compile_chk run diff --git a/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.questa b/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.questa index 3d31459e..f82c7de3 100644 --- a/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.questa +++ b/hdk/cl/examples/cl_uram_example/verif/scripts/Makefile.questa @@ -22,6 +22,9 @@ ## 2. make all QUESTA=1 -> Runs the test ################################################################## +LIBLISTS = $(COMMON_LIBLISTS) +LIBLISTS_ARGS = $(shell echo " $(strip $(LIBLISTS))" | sed 's|\ | -L |g') + compile: $(COMPLIB_DIR) mkdir -p $(SIM_DIR) cd ${SIM_DIR} && ln -s -f ../questa_complib/modelsim.ini @@ -30,34 +33,14 @@ compile: $(COMPLIB_DIR) cd $(SIM_DIR) && vlog -mfcu -sv -64 -timescale 1ps/1ps -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/secureip -f $(SCRIPTS_DIR)/top.$(SIMULATOR).f run: -ifeq ($(VIVADO_TOOL_VERSION),v2017.4) -ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_15 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_16 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_14 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_14 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) -else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_15 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_16 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_14 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_14 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif -else ifeq ($(VIVADO_TOOL_VERSION),v2018.3) -ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) -else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_18 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_19 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_17 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_17 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif -else ifeq ($(VIVADO_TOOL_VERSION), v2019.1) ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random $(LIBLISTS_ARGS) -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_19 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_20 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_18 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_18 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif -else -ifeq ($(TEST),test_null) - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(C_TEST).log -do "run -all; quit -f" tb glbl $(TEST) -else - cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random -L $(COMPLIB_DIR)/unisims_ver -L $(COMPLIB_DIR)/unisim -L $(COMPLIB_DIR)/unifast_ver -L $(COMPLIB_DIR)/unifast -L $(COMPLIB_DIR)/unimacro_ver -L $(COMPLIB_DIR)/unimacro -L $(COMPLIB_DIR)/secureip -L $(COMPLIB_DIR)/axi_register_slice_v2_1_17 -L $(COMPLIB_DIR)/axi_infrastructure_v1_1_0 -L $(COMPLIB_DIR)/axi_crossbar_v2_1_18 -L $(COMPLIB_DIR)/xpm -L $(COMPLIB_DIR)/axi_clock_converter_v2_1_16 -L $(COMPLIB_DIR)/fifo_generator_v13_1_4 -L $(COMPLIB_DIR)/axi_data_fifo_v2_1_16 -L $(COMPLIB_DIR)/generic_baseblocks_v2_1_0 -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) -endif + cd $(SIM_DIR) && vsim -c -voptargs="+acc" -64 -t ps -sv_seed random $(LIBLISTS_ARGS) -l $(TEST).log -do "run -all; quit -f" tb glbl $(TEST) endif + $(COMPLIB_DIR): cd $(SIM_ROOT) && echo "compile_simlib -language all -dir $(COMPLIB_DIR) -simulator $(SIMULATOR) -library all -family all" > create_libs.tcl cd $(SIM_ROOT) && vivado -mode batch -source create_libs.tcl cd $(SIM_ROOT) && rm -rf create_libs.tcl - diff --git a/hdk/common/verif/tb/scripts/Makefile.common.inc b/hdk/common/verif/tb/scripts/Makefile.common.inc index b47e19cc..9802eb89 100644 --- a/hdk/common/verif/tb/scripts/Makefile.common.inc +++ b/hdk/common/verif/tb/scripts/Makefile.common.inc @@ -98,6 +98,68 @@ endif endif endif +COMMON_LIBLISTS =\ + unisims_ver\ + unisim\ + unifast_ver\ + unifast\ + unimacro_ver\ + unimacro\ + secureip\ + xpm + +ifeq ($(VIVADO_TOOL_VERSION), v2017.4) + COMMON_LIBLISTS +=\ + axi_register_slice_v2_1_15\ + axi_infrastructure_v1_1_0\ + axi_crossbar_v2_1_16\ + axi_clock_converter_v2_1_14\ + fifo_generator_v13_2_1\ + fifo_generator_v13_1_4\ + axi_data_fifo_v2_1_14\ + generic_baseblocks_v2_1_0 +else ifeq ($(VIVADO_TOOL_VERSION), v2018.3) + COMMON_LIBLISTS +=\ + axi_register_slice_v2_1_18\ + axi_infrastructure_v1_1_0\ + axi_crossbar_v2_1_19\ + axi_clock_converter_v2_1_17\ + fifo_generator_v13_2_3\ + fifo_generator_v13_1_4\ + axi_data_fifo_v2_1_17\ + generic_baseblocks_v2_1_0 +else ifeq ($(VIVADO_TOOL_VERSION), v2019.1) + COMMON_LIBLISTS +=\ + axi_register_slice_v2_1_19\ + axi_infrastructure_v1_1_0\ + axi_crossbar_v2_1_20\ + axi_clock_converter_v2_1_18\ + fifo_generator_v13_2_4\ + fifo_generator_v13_1_4\ + axi_data_fifo_v2_1_18\ + generic_baseblocks_v2_1_0 +else ifeq ($(VIVADO_TOOL_VERSION), v2019.2) + COMMON_LIBLISTS +=\ + axi_register_slice_v2_1_20\ + axi_infrastructure_v1_1_0\ + axi_crossbar_v2_1_21\ + axi_clock_converter_v2_1_19\ + fifo_generator_v13_2_5\ + fifo_generator_v13_1_4\ + axi_data_fifo_v2_1_19\ + generic_baseblocks_v2_1_0 +else + COMMON_LIBLISTS +=\ + axi_register_slice_v2_1_17\ + axi_infrastructure_v1_1_0\ + axi_crossbar_v2_1_18\ + axi_clock_converter_v2_1_16\ + fifo_generator_v13_2_2\ + fifo_generator_v13_1_4\ + axi_data_fifo_v2_1_16\ + generic_baseblocks_v2_1_0 +endif + include $(HDK_COMMON_DIR)/verif/tb/scripts/Makefile.$(SIMULATOR).inc regression: $(SV_TEST_LIST) $(C_TEST_LIST) diff --git a/hdk/hdk_version.txt b/hdk/hdk_version.txt index e05658b5..b2fb0ae7 100644 --- a/hdk/hdk_version.txt +++ b/hdk/hdk_version.txt @@ -1 +1 @@ -HDK_VERSION=1.4.11 +HDK_VERSION=1.4.13 diff --git a/sdaccel_setup.sh b/sdaccel_setup.sh index 2d17953e..8db58a02 100644 --- a/sdaccel_setup.sh +++ b/sdaccel_setup.sh @@ -194,7 +194,7 @@ export LD_LIBRARY_PATH=`$XILINX_SDX/bin/ldlibpath.sh $XILINX_SDX/lib/lnx64.o`:$X export LD_LIBRARY_PATH=$XILINX_SDX/lnx64/tools/opencv/:$LD_LIBRARY_PATH # add variable to allow compilation using 2017.4 and 2018.2 on newer OSes -export XOCC_ADD_OPTIONS="--xp param:compiler.useHlsGpp=1" +export XOCC_ADD_OPTIONS="--xp param:compiler.useHlsGpp=1 --xp param:compiler.minFrequencyLimit=80" # Check if internet connection is available if ! check_internet; then diff --git a/shared/bin/set_common_env_vars.sh b/shared/bin/set_common_env_vars.sh index 27a8f4f6..c249a253 100644 --- a/shared/bin/set_common_env_vars.sh +++ b/shared/bin/set_common_env_vars.sh @@ -61,6 +61,9 @@ export SDK_DIR=$AWS_FPGA_REPO_DIR/sdk # SDACCEL # Setup Location of SDACCEL_DIR export SDACCEL_DIR=$AWS_FPGA_REPO_DIR/SDAccel +# Vitis +# Setup Location of VITIS_DIR +export VITIS_DIR=$AWS_FPGA_REPO_DIR/Vitis # PYTHONPATH # Update PYTHONPATH with libraries used for unit testing diff --git a/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py b/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py index be82b060..56a9f371 100644 --- a/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py +++ b/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py @@ -90,6 +90,12 @@ def setup_class(cls, derived_cls, filename_of_test_class): AwsFpgaTestBase.xilinx_sdaccel_examples_dir = AwsFpgaTestBase.git_repo_dir + "/" + AwsFpgaTestBase.xilinx_sdaccel_examples_prefix_path AwsFpgaTestBase.xilinx_sdaccel_examples_list_file = AwsFpgaTestBase.WORKSPACE + "/sdaccel_examples_list.json" + # Vitis locations + # Need to move to either a config file somewhere or a subclass + AwsFpgaTestBase.xilinx_vitis_examples_prefix_path = "Vitis/examples/xilinx" + AwsFpgaTestBase.xilinx_vitis_examples_dir = AwsFpgaTestBase.git_repo_dir + "/" + AwsFpgaTestBase.xilinx_vitis_examples_prefix_path + AwsFpgaTestBase.xilinx_vitis_examples_list_file = AwsFpgaTestBase.WORKSPACE + "/vitis_examples_list.json" + if 'WORKSPACE' in os.environ: assert os.environ['WORKSPACE'] == AwsFpgaTestBase.git_repo_dir, "WORKSPACE incorrect" else: @@ -136,6 +142,17 @@ def assert_sdaccel_setup(): assert os.environ.get('AWS_PLATFORM') != 'None', "Environment Var AWS_PLATFORM not set. source {}/sdaccel_setup.sh".format(AwsFpgaTestBase.git_repo_dir) assert os.environ.get('XILINX_SDX') != 'None', "Environment Var XILINX_SDX not set. Please check the AMI." + @staticmethod + def assert_vitis_setup(): + assert 'AWS_FPGA_REPO_DIR' in os.environ, "AWS_FPGA_REPO_DIR not set. source {}/vitis_setup.sh".format(AwsFpgaTestBase.git_repo_dir) + assert os.environ['AWS_FPGA_REPO_DIR'] == AwsFpgaTestBase.git_repo_dir, "AWS_FPGA_REPO_DIR not set to the repo dir. source {}/vitis_setup.sh".format(AwsFpgaTestBase.git_repo_dir) + assert 'SDK_DIR' in os.environ, "SDK_DIR not set. source {}/vitis_setup.sh".format(AwsFpgaTestBase.git_repo_dir) + assert os.environ['SDK_DIR'] == os.path.join(AwsFpgaTestBase.git_repo_dir, 'sdk'), "SDK_DIR incorrect. source {}/vitis_setup.sh".format(AwsFpgaTestBase.git_repo_dir) + assert 'VITIS_DIR' in os.environ, "VITIS_DIR not set. source {}/vitis_setup.sh".format(AwsFpgaTestBase.git_repo_dir) + assert os.environ['VITIS_DIR'] == os.path.join(AwsFpgaTestBase.git_repo_dir, 'Vitis'), "VITIS_DIR incorrect. source {}/vitis_setup.sh".format(AwsFpgaTestBase.git_repo_dir) + assert os.environ.get('AWS_PLATFORM') != 'None', "Environment Var AWS_PLATFORM not set. source {}/vitis_setup.sh".format(AwsFpgaTestBase.git_repo_dir) + assert os.environ.get('XILINX_VITIS') != 'None', "Environment Var XILINX_VITIS not set. Please check the AMI." + @staticmethod def running_on_f1_instance(): ''' @@ -191,6 +208,12 @@ def run_sdaccel_cmd(cmd, echo=False, check=True): cmd = source_sdaccel_cmd + " && " + cmd return AwsFpgaTestBase.run_cmd(cmd, echo, check) + @staticmethod + def run_vitis_cmd(cmd, echo=False, check=True): + source_vitis_cmd = "source {}/vitis_setup.sh &> /dev/null".format(AwsFpgaTestBase.git_repo_dir) + cmd = source_vitis_cmd + " && " + cmd + return AwsFpgaTestBase.run_cmd(cmd, echo, check) + @staticmethod def get_shell_version(): shell_link = os.path.join(AwsFpgaTestBase.WORKSPACE, 'hdk/common/shell_stable') @@ -238,6 +261,10 @@ def get_cl_s3_afi_tag(cl, option_tag, xilinxVersion): def get_sdaccel_xclbin_dir(examplePath): return os.path.join(AwsFpgaTestBase.get_sdaccel_example_fullpath(examplePath=examplePath), 'xclbin') + @staticmethod + def get_vitis_xclbin_dir(examplePath, target='hw'): + return os.path.join(AwsFpgaTestBase.get_sdaccel_example_fullpath(examplePath=examplePath), "build_dir.{}.xilinx_aws-vu9p-f1_shell-v04261818_201920_1".format(target)) + @staticmethod def get_sdaccel_example_s3_root_tag(examplePath, target, rteName, xilinxVersion): ''' @@ -253,6 +280,21 @@ def get_sdaccel_example_s3_root_tag(examplePath, target, rteName, xilinxVersion) example_relative_path = os.path.relpath(examplePath, AwsFpgaTestBase.xilinx_sdaccel_examples_prefix_path) return "jenkins/{}/SDAccel/{}/{}/{}/{}".format(os.environ['BUILD_TAG'], xilinxVersion, rteName, example_relative_path, target) + @staticmethod + def get_vitis_example_s3_root_tag(examplePath, target, rteName, xilinxVersion): + ''' + @param examplePath: Path of the Xilinx Vitis example + @param target: The target to build. For eg: hw, hw_emu, sw_emu + @param rteName: The runtime environment + @param xilinxVersion: The Xilinx tool version + ''' + assert target != '' + assert examplePath != '' + assert rteName != '' + assert xilinxVersion != '' + example_relative_path = os.path.relpath(examplePath, AwsFpgaTestBase.xilinx_vitis_examples_prefix_path) + return "jenkins/{}/Vitis/{}/{}/{}/{}".format(os.environ['BUILD_TAG'], xilinxVersion, rteName, example_relative_path, target) + @staticmethod def get_sdaccel_example_s3_xclbin_tag(examplePath, target, rteName, xilinxVersion): ''' @@ -269,6 +311,22 @@ def get_sdaccel_example_s3_xclbin_tag(examplePath, target, rteName, xilinxVersio return "{}/xclbin".format(root_tag) + @staticmethod + def get_vitis_example_s3_xclbin_tag(examplePath, target, rteName, xilinxVersion): + ''' + @param examplePath: Path of the Xilinx Vitis example + @param target: The target to build. For eg: hw, hw_emu, sw_emu + @param rteName: The runtime environment + @param xilinxVersion: The Xilinx tool version + ''' + assert target != '' + assert examplePath != '' + assert rteName != '' + assert xilinxVersion != '' + root_tag = AwsFpgaTestBase.get_vitis_example_s3_root_tag(examplePath, target, rteName, xilinxVersion) + + return "{}/xclbin".format(root_tag) + @staticmethod def get_sdaccel_example_s3_dcp_tag(examplePath, target, rteName, xilinxVersion): ''' @@ -285,6 +343,22 @@ def get_sdaccel_example_s3_dcp_tag(examplePath, target, rteName, xilinxVersion): return "{}/dcp".format(root_tag) + @staticmethod + def get_vitis_example_s3_dcp_tag(examplePath, target, rteName, xilinxVersion): + ''' + @param examplePath: Path of the Xilinx Vitis example + @param target: The target to build. For eg: hw, hw_emu, sw_emu + @param rteName: The runtime environment + @param xilinxVersion: The Xilinx tool version + ''' + assert target != '' + assert examplePath != '' + assert rteName != '' + assert xilinxVersion != '' + root_tag = AwsFpgaTestBase.get_vitis_example_s3_root_tag(examplePath, target, rteName, xilinxVersion) + + return "{}/dcp".format(root_tag) + @staticmethod def get_sdaccel_example_s3_afi_tag(examplePath, target, rteName, xilinxVersion): ''' @@ -300,6 +374,21 @@ def get_sdaccel_example_s3_afi_tag(examplePath, target, rteName, xilinxVersion): return "{}/create-afi/afi-ids.txt".format(root_tag) + @staticmethod + def get_vitis_example_s3_afi_tag(examplePath, target, rteName, xilinxVersion): + ''' + @param examplePath: Path of the Xilinx Vitis example + @param target: The target to build. For eg: hw, hw_emu, sw_emu + @param rteName: The runtime environment + ''' + assert target != '' + assert examplePath != '' + assert rteName != '' + assert xilinxVersion != '' + root_tag = AwsFpgaTestBase.get_vitis_example_s3_root_tag(examplePath, target, rteName, xilinxVersion) + + return "{}/create-afi/afi-ids.txt".format(root_tag) + @staticmethod def get_sdaccel_example_run_cmd(examplePath, xilinxVersion): ''' @@ -328,6 +417,35 @@ def get_sdaccel_example_run_cmd(examplePath, xilinxVersion): return run_cmd + @staticmethod + def get_vitis_example_run_cmd(examplePath, xilinxVersion): + ''' + @param examplePath: Path of the Xilinx Vitis example + @param xilinxVersion: The Xilinx tool version + ''' + description = AwsFpgaTestBase.get_vitis_example_description(examplePath) + + host_description = description.get("host", None) + assert host_description is not None, "Could not find host key in the description.json here {}".format( + examplePath) + + launch_description = description.get("launch", None) + assert launch_description is not None, "Could not find launch/cmd_args key in the description.json here {}".format( + examplePath) + + if host_description.get("host_exe", None): + run_cmd = "./{}".format(host_description.get("host_exe", None)) + + if launch_description[0].get("cmd_args", None): + run_cmd += " {}".format(((launch_description[0].get("cmd_args", None).replace(".xclbin", + ".awsxclbin")).replace( + "PROJECT", ".")).replace("BUILD", "./build_dir.hw.xilinx_aws-vu9p-f1_shell-v04261818_201920_1")) + + assert run_cmd is not None, "Could not find run_cmd(em_cmd) or (host_exe) in the example description here {}".format( + examplePath) + + return run_cmd + @staticmethod def get_sdaccel_example_description(examplePath): ''' @@ -340,10 +458,26 @@ def get_sdaccel_example_description(examplePath): description = json.load(json_data) return description + @staticmethod + def get_vitis_example_description(examplePath): + ''' + @param examplePath: Path of the Xilinx Vitis example + ''' + + example_description = AwsFpgaTestBase.assert_non_zero_file(os.path.join(AwsFpgaTestBase.get_vitis_example_fullpath(examplePath), "description.json")) + + with open(example_description) as json_data: + description = json.load(json_data) + return description + @staticmethod def get_sdaccel_example_fullpath(examplePath): return "{}/{}/".format(AwsFpgaTestBase.WORKSPACE, examplePath) + @staticmethod + def get_vitis_example_fullpath(examplePath): + return "{}/{}/".format(AwsFpgaTestBase.WORKSPACE, examplePath) + @staticmethod def fetch_sdaccel_xclbin_folder_from_s3(examplePath, rteName, xilinxVersion): cwd = os.getcwd() @@ -362,6 +496,24 @@ def fetch_sdaccel_xclbin_folder_from_s3(examplePath, rteName, xilinxVersion): os.chdir(cwd) return xclbin_path + @staticmethod + def fetch_vitis_xclbin_folder_from_s3(examplePath, rteName, xilinxVersion): + cwd = os.getcwd() + assert examplePath != '' + assert rteName != '' + assert xilinxVersion != '' + + os.chdir(AwsFpgaTestBase.get_vitis_example_fullpath(examplePath)) + rc = os.system("aws s3 cp s3://{}/{} {} --recursive".format(AwsFpgaTestBase.s3_bucket, AwsFpgaTestBase.get_vitis_example_s3_xclbin_tag(examplePath=examplePath, target="hw", rteName=rteName, xilinxVersion=xilinxVersion), AwsFpgaTestBase.get_vitis_xclbin_dir(examplePath=examplePath))) + assert rc == 0, "Error while copying from s3://{}/{} to {}".format(AwsFpgaTestBase.s3_bucket, AwsFpgaTestBase.get_vitis_example_s3_xclbin_tag(examplePath=examplePath, target="hw", rteName=rteName, xilinxVersion=xilinxVersion), AwsFpgaTestBase.get_vitis_xclbin_dir(examplePath=examplePath)) + xclbin_path = AwsFpgaTestBase.get_vitis_xclbin_dir(examplePath=examplePath) + + logger.debug(xclbin_path) + assert os.path.exists(xclbin_path), "Vitis Example xclbin path={} does not exist".format(xclbin_path) + + os.chdir(cwd) + return xclbin_path + @staticmethod def get_sdaccel_xclbin_file(examplePath, rteName, xilinxVersion): assert examplePath != '' @@ -373,6 +525,17 @@ def get_sdaccel_xclbin_file(examplePath, rteName, xilinxVersion): xclbin = AwsFpgaTestBase.assert_non_zero_file(os.path.join(xclbin_path, "*.{}.*.xclbin".format("hw"))) return xclbin + @staticmethod + def get_vitis_xclbin_file(examplePath, rteName, xilinxVersion): + assert examplePath != '' + assert rteName != '' + assert xilinxVersion != '' + xclbin_path = AwsFpgaTestBase.fetch_vitis_xclbin_folder_from_s3(examplePath, rteName, xilinxVersion) + logger.info("Checking that a non zero size xclbin file exists in {}".format(xclbin_path)) + + xclbin = AwsFpgaTestBase.assert_non_zero_file(os.path.join(xclbin_path, "*.xclbin")) + return xclbin + @staticmethod def get_sdaccel_aws_xclbin_file(examplePath, rteName, xilinxVersion): assert examplePath != '' @@ -384,6 +547,17 @@ def get_sdaccel_aws_xclbin_file(examplePath, rteName, xilinxVersion): aws_xclbin = AwsFpgaTestBase.assert_non_zero_file(os.path.join(xclbin_path, "*.{}.*.awsxclbin".format("hw"))) return aws_xclbin + @staticmethod + def get_vitis_aws_xclbin_file(examplePath, rteName, xilinxVersion): + assert examplePath != '' + assert rteName != '' + assert xilinxVersion != '' + + xclbin_path = AwsFpgaTestBase.fetch_vitis_xclbin_folder_from_s3(examplePath, rteName, xilinxVersion) + logger.info("Checking that a non zero size awsxclbin file exists in {}".format(xclbin_path)) + aws_xclbin = AwsFpgaTestBase.assert_non_zero_file(os.path.join(xclbin_path, "*.awsxclbin")) + return aws_xclbin + @staticmethod def assert_afi_available(afi): # Check the status of the afi diff --git a/shared/lib/aws_fpga_test_utils/__init__.py b/shared/lib/aws_fpga_test_utils/__init__.py index c806d7d7..d28616b6 100644 --- a/shared/lib/aws_fpga_test_utils/__init__.py +++ b/shared/lib/aws_fpga_test_utils/__init__.py @@ -247,6 +247,8 @@ def get_instance_type(): def get_num_fpga_slots(instance_type): if re.match('f1\.2xlarge', instance_type): return 1 + if re.match('f1\.4xlarge', instance_type): + return 2 elif re.match('f1\.16xlarge', instance_type): return 8 return 0 diff --git a/shared/lib/check_src_headers.py b/shared/lib/check_src_headers.py index 7249bb36..8d390a3c 100755 --- a/shared/lib/check_src_headers.py +++ b/shared/lib/check_src_headers.py @@ -574,6 +574,8 @@ def check_headers(dir): "SDAccel/aws_platform", "SDAccel/examples/3rd_party", "SDAccel/examples/xilinx", + "Vitis/aws_platform", + "Vitis/examples/xilinx", ]) file_path_list = sorted(file_provider.get_files(dir)) diff --git a/shared/tests/bin/setup_test_build_vitis_env.sh b/shared/tests/bin/setup_test_build_vitis_env.sh new file mode 100644 index 00000000..ed76bf76 --- /dev/null +++ b/shared/tests/bin/setup_test_build_vitis_env.sh @@ -0,0 +1,36 @@ +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + +# Script must be sourced from a bash shell or it will not work +# When being sourced $0 will be the interactive shell and $BASH_SOURCE_ will contain the script being sourced +# When being run $0 and $_ will be the same. + +script=${BASH_SOURCE[0]} +if [ $script == $0 ]; then + echo "ERROR: You must source this script" + exit 2 +fi + +full_script=$(readlink -f $script) +script_name=$(basename $full_script) +script_dir=$(dirname $full_script) + +if ! source $script_dir/setup_test_env.sh; then + return 1 +fi + +if ! source $WORKSPACE/vitis_setup.sh; then + return 1 +fi diff --git a/shared/tests/bin/setup_test_runtime_vitis_env.sh b/shared/tests/bin/setup_test_runtime_vitis_env.sh new file mode 100644 index 00000000..3e7cc1a5 --- /dev/null +++ b/shared/tests/bin/setup_test_runtime_vitis_env.sh @@ -0,0 +1,42 @@ +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + +# Script must be sourced from a bash shell or it will not work +# When being sourced $0 will be the interactive shell and $BASH_SOURCE_ will contain the script being sourced +# When being run $0 and $_ will be the same. + +script=${BASH_SOURCE[0]} +if [ $script == $0 ]; then + echo "ERROR: You must source this script" + exit 2 +fi + +full_script=$(readlink -f $script) +script_name=$(basename $full_script) +script_dir=$(dirname $full_script) + +export LD_LIBRARY_PATH=$XILINX_VITIS/lnx64/tools/opencv/:$LD_LIBRARY_PATH + +if ! source $script_dir/setup_test_env.sh; then + return 1 +fi + +if ! source $script_dir/setup_test_xrtpatch.sh; then + return 1 +fi + +if ! source $WORKSPACE/vitis_setup.sh; then + return 1 +fi diff --git a/shared/tests/bin/setup_test_xrtpatch.sh b/shared/tests/bin/setup_test_xrtpatch.sh index 63eb1380..ccfbfa47 100644 --- a/shared/tests/bin/setup_test_xrtpatch.sh +++ b/shared/tests/bin/setup_test_xrtpatch.sh @@ -82,6 +82,43 @@ elif [[ "$VIVADO_TOOL_VERSION" =~ .*2018\.3.* ]]; then xrt_rpm_path=$s3_ami_bucket/$s3_ami_version/Patches/$xrt_release_version/$xrt_rpm_name aws_xrt_rpm_path=$s3_ami_bucket/$s3_ami_version/Patches/$xrt_release_version/$aws_xrt_rpm_name + if [ -f "/opt/xilinx/xrt/include/version.h" ]; then + echo "XRT installed. proceeding to check version compatibility" + xrt_build_ver=$(grep 'xrt_build_version_hash\[\]' /opt/xilinx/xrt/include/version.h | sed 's/";//' | sed 's/^.*"//') + echo "Installed XRT version hash : $xrt_build_ver" + if grep -Fxq "$xrt_build_ver" $AWS_FPGA_REPO_DIR/SDAccel/sdaccel_xrt_version.txt + then + echo "XRT version $xrt_build_ver is up-to-date." + else + echo "$xrt_build_ver is stale. upgrading XRT to" + cat $AWS_FPGA_REPO_DIR/SDAccel/sdaccel_xrt_version.txt + curl -s https://s3.amazonaws.com/$xrt_rpm_path -o $xrt_rpm_name || { echo " Error: Failed to download xrt rpm from $xrt_rpm_path"; return 2; } + curl -s https://s3.amazonaws.com/$aws_xrt_rpm_path -o $aws_xrt_rpm_name || { echo " Error: Failed to download aws xrt rpm from $aws_xrt_rpm_path"; return 2; } + sudo yum reinstall -y $xrt_rpm_name + echo " XRT patch rpm installed successfully" + sudo yum reinstall -y $aws_xrt_rpm_name + echo " XRT patch aws rpm installed successfully" + fi + else + echo "XRT not installed. Please install XRT" + curl -s https://s3.amazonaws.com/$xrt_rpm_path -o $xrt_rpm_name || { echo " Error: Failed to download xrt rpm from $xrt_rpm_path"; return 2; } + curl -s https://s3.amazonaws.com/$aws_xrt_rpm_path -o $aws_xrt_rpm_name || { echo " Error: Failed to download aws xrt rpm from $aws_xrt_rpm_path"; return 2; } + sudo yum reinstall -y $xrt_rpm_name + echo " XRT patch rpm installed successfully" + sudo yum install -y $aws_xrt_rpm_name + echo " XRT patch aws rpm installed successfully" + fi +elif [[ "$VIVADO_TOOL_VERSION" =~ .*2019\.1.* ]]; then + echo "Xilinx Vivado version is 2019.1" + + s3_ami_version=1.7.0 + xrt_release_version=XRT_2019_1_0_3 + xrt_rpm_name=xrt_201910.2.2.0_7.7.1908-xrt.rpm + aws_xrt_rpm_name=xrt_201910.2.2.0_7.7.1908-aws.rpm + + xrt_rpm_path=$s3_ami_bucket/$s3_ami_version/Patches/$xrt_release_version/$xrt_rpm_name + aws_xrt_rpm_path=$s3_ami_bucket/$s3_ami_version/Patches/$xrt_release_version/$aws_xrt_rpm_name + if [ -f "/opt/xilinx/xrt/include/version.h" ]; then echo "XRT installed. proceeding to check version compatibility" xrt_build_ver=$(grep 'xrt_build_version_hash\[\]' /opt/xilinx/xrt/include/version.h | sed 's/";//' | sed 's/^.*"//') diff --git a/supported_vivado_versions.txt b/supported_vivado_versions.txt index b8bb41c6..f04c4093 100644 --- a/supported_vivado_versions.txt +++ b/supported_vivado_versions.txt @@ -9,4 +9,5 @@ Vivado v2018.3 (64-bit) Vivado v2018.3_AR72667 (64-bit) Vivado v2019.1.op (64-bit) Vivado v2019.1 (64-bit) -Vivado v2019.1_AR72668 (64-bit) \ No newline at end of file +Vivado v2019.1_AR72668 (64-bit) +Vivado v2019.2 (64-bit) diff --git a/vitis_runtime_setup.sh b/vitis_runtime_setup.sh new file mode 100644 index 00000000..57a0b7a0 --- /dev/null +++ b/vitis_runtime_setup.sh @@ -0,0 +1,206 @@ +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + +# Script must be sourced from a bash shell or it will not work +# When being sourced $0 will be the interactive shell and $BASH_SOURCE_ will contain the script being sourced +# When being run $0 and $_ will be the same. +script=${BASH_SOURCE[0]} +if [ $script == $0 ]; then + echo "ERROR: You must source this script" + exit 2 +fi + +full_script=$(readlink -f $script) +script_name=$(basename $full_script) +script_dir=$(dirname $full_script) +current_dir=$(pwd) + +source $script_dir/shared/bin/set_common_functions.sh +source $script_dir/shared/bin/set_common_env_vars.sh +source $VITIS_DIR/Runtime/xrt_common_functions.sh + +# Source sdk_setup.sh +info_msg "Sourcing sdk_setup.sh" +if ! source $AWS_FPGA_REPO_DIR/sdk_setup.sh; then + return 1 +fi + +if [ -z "$SDK_DIR" ]; then + err_msg "SDK_DIR environment variable is not set. Please use 'source sdk_setup.sh' from the aws-fpga directory." + return 1 +fi + +debug=0 +override=0 +function usage { + echo -e "USAGE: source [\$AWS_FPGA_REPO_DIR/]$script_name [-d|-debug] [-h|-help] [-o|-override]" +} + +function help { + info_msg "$script_name" + info_msg " " + info_msg "Checks & Sets up the runtime environment for AWS FPGA Vitis Application usage." + info_msg " " + info_msg "vitis_runtime_check.sh script will:" + info_msg " (1) install FPGA Management Tools," + info_msg " (2) check if Xilinx Runtime (XRT) is installed" + info_msg " (3) check if correct version of Xilinx Runtime (XRT) is installed," + info_msg " (4) check if the required XOCL driver is running " + info_msg " (5) source runtime setup script " + echo " " + usage +} + +function check_xdma_driver { + + if lsmod | grep -q 'xdma' ; then + err_msg "Found XDMA Driver running. Please remove xdma driver using below command" + err_msg " rmmod xdma" + return 1 + fi +} + +function check_edma_driver { + + if lsmod | grep -q 'edma' ; then + err_msg "Found EDMA Driver running. Please remove edma driver using below command" + err_msg " rmmod edma" + return 1 + fi +} + +function check_xocl_driver { + if lsmod | grep -q 'xocl' ; then + info_msg "Found 'xocl Driver is installed and running. ' " + else + err_msg " XOCL Driver not installed. Please install xocl driver using below instructions" + err_msg " If using 2019.2 Vitis toolset please source $AWS_FPGA_REPO_DIR/vitis_setup.sh " + return 1 + fi +} + +function check_kernel_ver { + + ins_ker_ver=$(uname -r) + info_msg "Installed kernel version : $ins_ker_ver" + if grep -Fxq "$ins_ker_ver" $AWS_FPGA_REPO_DIR/Vitis/kernel_version.txt + then + info_msg "kernel version $ins_ker_ver has been validated for this devkit." + else + warn_msg "$ins_ker_ver does not match one of recommended kernel versions" + cat $AWS_FPGA_REPO_DIR/Vitis/kernel_version.txt + warn_msg "Xilinx Runtime not validated against your installed kernel version." + fi +} + +# Process command line args +args=( "$@" ) +for (( i = 0; i < ${#args[@]}; i++ )); do + arg=${args[$i]} + case $arg in + -d|-debug) + debug=1 + ;; + -h|-help) + help + return 0 + ;; + -o|-override) + override=1 + ;; + *) + err_msg "Invalid option: $arg\n" + usage + return 1 + esac +done + + +if ! exists vivado; then + if [[ -z "${VIVADO_TOOL_VERSION}" ]]; then + err_msg " VIVADO_TOOL_VERSION ENV variable is not set." + err_msg " ENV Variable VIVADO_TOOL_VERSION needs to be set for runtime usage. " + err_msg " If AFI was generated using V2019.2 tools use the command : export VIVADO_TOOL_VERSION=2019.2 " + err_msg " Please set VIVADO_TOOL_VERSION to the correct value and re-run script." + return 1 + else + info_msg " VIVADO tools not found. Reading VIVADO_TOOL_VERSION ENV variable to determine runtime version... " + VIVADO_TOOL_VERSION="${VIVADO_TOOL_VERSION}" + export VIVADO_TOOL_VERSION=${VIVADO_TOOL_VERSION:0:6} + fi +else + info_msg "You are using instance with installed vivado tools. determining VIVADO version for runtime setup..." + VIVADO_TOOL_VERSION=`vivado -version | grep Vivado | head -1 | sed 's:Vivado *::' | sed 's: .*$::' | sed 's:v::'` + export VIVADO_TOOL_VERSION=${VIVADO_TOOL_VERSION:0:6} +fi +info_msg "VIVADO_TOOL_VERSION is $VIVADO_TOOL_VERSION" + + +check_kernel_ver +check_xdma_driver +check_edma_driver + +if [[ "$VIVADO_TOOL_VERSION" =~ .*2019\.2.* ]]; then + info_msg "Xilinx Vivado version is $VIVADO_TOOL_VERSION" + + if [ $override == 1 ]; then + info_msg "XRT check overide selected." + source /opt/xilinx/xrt/setup.sh + return 0 + fi + + if [ -f "/opt/xilinx/xrt/include/version.h" ]; then + info_msg "XRT installed. proceeding to check version compatibility" + xrt_build_ver=$VIVADO_TOOL_VERSION + xrt_build_ver+=: + xrt_build_ver+=$(grep 'xrt_build_version_hash\[\]' /opt/xilinx/xrt/include/version.h | sed 's/";//' | sed 's/^.*"//') + info_msg "Installed XRT version : $xrt_build_ver" + if grep -Fxq "$xrt_build_ver" $AWS_FPGA_REPO_DIR/Vitis/vitis_xrt_version.txt + then + info_msg "XRT version $xrt_build_ver is supported." + info_msg " Now checking XOCL driver..." + check_xocl_driver + if [ -f "/opt/xilinx/xrt/setup.sh" ]; then + source /opt/xilinx/xrt/setup.sh + else + err_msg " Cannot find /opt/xilinx/xrt/setup.sh" + err_msg " Please check XRT is installed correctly" + err_msg " Please Refer to $AWS_FPGA_REPO/Vitis/doc/XRT_installation_instructions.md for XRT installation instructions" + return 1 + fi + info_msg " XRT Runtime setup Done" + else + err_msg "$xrt_build_ver does not match recommended versions" + cat $AWS_FPGA_REPO_DIR/Vitis/vitis_xrt_version.txt + err_msg "Please Refer $AWS_FPGA_REPO/Vitis/doc/XRT_installation_instructions.md for XRT installation instructions" + return 1 + fi + else + err_msg "XRT not installed. Please install XRT" + err_msg "Please Refer $AWS_FPGA_REPO/Vitis/doc/XRT_installation_instructions.md for XRT installation instructions" + return 1 + fi +else + err_msg "Xilinx Vivado version is $VIVADO_TOOL_VERSION , only 2019.2 is supported for Vitis " + return 1 +fi + +# Setup XRT as we need it for building +setup_runtime + +info_msg "Starting MPD" +systemctl is-active --quiet mpd || sudo systemctl start mpd + +info_msg "Vitis runtime check PASSED" \ No newline at end of file diff --git a/vitis_setup.sh b/vitis_setup.sh new file mode 100644 index 00000000..2f1e6a93 --- /dev/null +++ b/vitis_setup.sh @@ -0,0 +1,292 @@ +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + +# Script must be sourced from a bash shell or it will not work +# When being sourced $0 will be the interactive shell and $BASH_SOURCE_ will contain the script being sourced +# When being run $0 and $_ will be the same. +script=${BASH_SOURCE[0]} +if [ $script == $0 ]; then + echo "ERROR: You must source this script" + exit 2 +fi + +full_script=$(readlink -f $script) +script_name=$(basename $full_script) +script_dir=$(dirname $full_script) +current_dir=$(pwd) + +source $script_dir/shared/bin/set_common_functions.sh +source $script_dir/shared/bin/set_common_env_vars.sh +source $VITIS_DIR/Runtime/xrt_common_functions.sh + +# Source sdk_setup.sh +info_msg "Sourcing sdk_setup.sh" +if ! source $AWS_FPGA_REPO_DIR/sdk_setup.sh; then + return 1 +fi + +if [ -z "$SDK_DIR" ]; then + err_msg "SDK_DIR environment variable is not set. Please use 'source sdk_setup.sh' from the aws-fpga directory." + return 1 +fi + +debug=0 + +function usage { + echo -e "USAGE: source [\$AWS_FPGA_REPO_DIR/]$script_name [-d|-debug] [-h|-help]" +} + +function help { + info_msg "$script_name" + info_msg " " + info_msg "Sets up the environment for AWS FPGA Vitis tools." + info_msg " " + info_msg "vitis_setup.sh script will:" + info_msg " (1) install FPGA Management Tools," + info_msg " (2) check if Xilinx tools are available," + info_msg " (3) check if required packages are installed," + info_msg " (4) Download lastest AWS Platform," + info_msg " (5) Install Runtime drivers " + echo " " + usage +} + +function check_set_xilinx_vitis { + if [[ ":$XILINX_VITIS" == ':' ]]; then + debug_msg "XILINX_VITIS is not set" + which vitis + RET=$? + if [ $RET != 0 ]; then + debug_msg "vitis not found in path." + err_msg "XILINX_VITIS variable not set and vitis not in the path" + err_msg "Please set XILINX_VITIS variable to point to your location of your Xilinx installation or add location of vitis exectuable to your PATH variable" + return $RET + else + export XILINX_VITIS=`which vitis | sed 's:/bin/vitis::'` + info_msg "Setting XILINX_VITIS to $XILINX_VITIS" + fi + else + info_msg "XILINX_VITIS is already set to $XILINX_VITIS" + fi + # get Vitis release version, i.e. "2019.2" + RELEASE_VER=$(basename $XILINX_VITIS) + RELEASE_VER=${RELEASE_VER:0:6} + export RELEASE_VER=$RELEASE_VER + echo "RELEASE_VER equals $RELEASE_VER" +} + +function check_install_packages_centos { +#TODO: Check required packages are installed or install them +#TODO: Check version of gcc is above 4.8.5 (4.6.3 does not work) + for pkg in `cat $VITIS_DIR/packages.txt`; do + if yum list installed "$pkg" >/dev/null 2>&1; then + true + else + warn_msg " $pkg not installed - please run: sudo yum install $pkg " + fi + done +} + +function check_install_packages_ubuntu { + for pkg in `cat $VITIS_DIR/packages.txt`; do + if apt -qq list "$pkg" >/dev/null 2>&1; then + true + else + warn_msg " $pkg not installed - please run: sudo apt-get install $pkg " + fi + done +} + +function check_internet { + curl --silent --head -m 30 http://www.amazon.com + RET=$? + if [ $RET != 0 ]; then + err_msg "curl cannot connect to the internet using please check your internet connection or proxy settings" + err_msg "To check your connection run: curl --silent --head -m 30 http://www.amazon.com " + return $RET + else + info_msg "Internet Access OK" + fi +} + +function check_icd { + info_msg "Checking ICD is installed" + if grep -q 'libxilinxopencl.so' /etc/OpenCL/vendors/xilinx.icd; then + info_msg "Found 'libxilinxopencl.so" + else + info_msg "/etc/OpenCL/vendors/xilinx.icd does not exist or does not contain lbixilinxopencl.so creating and adding libxilinxopencl.so to it" + sudo sh -c "echo libxilinxopencl.so > /etc/OpenCL/vendors/xilinx.icd" + RET=$? + if [ $RET != 0 ]; then + err_msg "/etc/OpenCL/vendors/xilinx.icd does not exist and cannot be created, sudo permissions needed to update it." + err_msg "Run the following with sudo permissions: sudo sh -c \"echo libxilinxopencl.so > /etc/OpenCL/vendors/xilinx.icd\" " + return $RET + else + echo "Done with ICD installation" + fi + fi +} + +# Process command line args +args=( "$@" ) +for (( i = 0; i < ${#args[@]}; i++ )); do + arg=${args[$i]} + case $arg in + -d|-debug) + debug=1 + ;; + -h|-help) + help + return 0 + ;; + *) + err_msg "Invalid option: $arg\n" + usage + return 1 + esac +done + +# Check XILINX_VITIS is set +if ! check_set_xilinx_vitis; then + return 1 +fi + +info_msg " XILINX_VITIS is set to $XILINX_VITIS" +# Install patches as required. +info_msg " Checking & installing required patches" +setup_patches + + +# Update Xilinx Vitis Examples from GitHub +info_msg "Using Vitis $RELEASE_VER" +if [[ $RELEASE_VER =~ .*2019\.2.* ]]; then + info_msg "Updating Xilinx Vitis Examples $RELEASE_VER" + git submodule update --init -- Vitis/examples/xilinx_$RELEASE_VER + export VIVADO_TOOL_VER=$RELEASE_VER + if [ -e $VITIS_DIR/examples/xilinx ]; then + if [ ! -L $VITIS_DIR/examples/xilinx ]; then + err_msg "ERROR: Vitis/examples/xilinx is not a symbolic link. Backup any data and remove Vitis/examples/xilinx directory. The setup needs to create a symbolic link from Vitis/examples/xilinx to Vitis/examples/xilinx_$RELEASE_VER" + return 1 + fi + fi + ln -sf $VITIS_DIR/examples/xilinx_$RELEASE_VER $VITIS_DIR/examples/xilinx +else + echo " $RELEASE_VER is not supported (2019.2 is supported).\n" + return 2 +fi + +# settings64 removal - once we put this in the AMI, we will add a check +#export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$XILINX_VITIS/lib/lnx64.o + +export LD_LIBRARY_PATH=`$XILINX_VITIS/bin/ldlibpath.sh $XILINX_VITIS/lib/lnx64.o` + +# Check if internet connection is available +if ! check_internet; then + return 1 +fi + +# Check ICD is installed +if ! check_icd; then + return 1 +fi + +# Check correct packages are installed +if [ -f "/etc/redhat-release" ]; then + if ! check_install_packages_centos; then + return 1 + fi +else + if ! check_install_packages_ubuntu; then + return 1 + fi +fi + +function setup_xsa { + + if [ "$#" -ne 3 ]; then + err_msg "Illegal number of parameters sent to the setup_xsa function!" + return 1 + fi + + XSA=$1 + XSA_S3_BASE_DIR=$2 + PLATFORM_ENV_VAR_NAME=$3 + + xsa_dir=$VITIS_DIR/aws_platform/$XSA/hw/ + vitis_xsa=$xsa_dir/$XSA.xsa + vitis_xsa_s3_bucket=aws-fpga-hdk-resources + s3_vitis_xsa=$vitis_xsa_s3_bucket/Vitis/$XSA_S3_BASE_DIR/$XSA/$XSA.xsa + + # set a variable to point to the platform for build and emulation runs + export "$PLATFORM_ENV_VAR_NAME"=$VITIS_DIR/aws_platform/$XSA/$XSA.xpfm + + # Download the sha256 + if [ ! -e $xsa_dir ]; then + mkdir -p $xsa_dir || { err_msg "Failed to create $xsa_dir"; return 2; } + fi + + # Use curl instead of AWS CLI so that credentials aren't required. + curl -s https://s3.amazonaws.com/$s3_vitis_xsa.sha256 -o $vitis_xsa.sha256 || { err_msg "Failed to download XSA version from $s3_vitis_xsa.sha256 -o $vitis_xsa.sha256"; return 2; } + if grep -q ' Date: Mon, 2 Mar 2020 14:45:33 -0600 Subject: [PATCH 12/31] Update Errata and documentation (#481) * Added link to Xilinx AR# 73360 * Updated README to point to Vitis as the initial start point for new development --- ERRATA.md | 3 +-- README.md | 10 ++++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ERRATA.md b/ERRATA.md index 64257416..408dfa16 100644 --- a/ERRATA.md +++ b/ERRATA.md @@ -8,8 +8,7 @@ * Multiple SDE instances per CL is not supported in this release. Support is planned for a future release. * DRAM Data retention is not supported for CL designs with less than 4 DDRs enabled * Combinatorial loops in CL designs are not supported. -* Connecting one of the clocks provided from the shell (clk_main_a0, clk_extra_a1, etc...) directly to a BUFG in the CL is not supported by the Xilinx tools and may result in a non-functional clock. To workaround this limitation, it is recommended to use an MMCM to feed the BUFG (clk_from_shell -> MMCM -> BUFG). - +* Connecting one of the clocks provided from the shell (clk_main_a0, clk_extra_a1, etc...) directly to a BUFG in the CL is not supported by the Xilinx tools and may result in a non-functional clock. To workaround this limitation, it is recommended to use an MMCM to feed the BUFG (clk_from_shell -> MMCM -> BUFG). Please refer to [Xilinx AR# 73360](https://www.xilinx.com/support/answers/73360.html) for further details. ### 2019.1 * Vivado `compile_simlib` command fails to generate the following verilog IP libraries for the following simulators. diff --git a/README.md b/README.md index 3ae8f2d3..89419c1e 100644 --- a/README.md +++ b/README.md @@ -91,8 +91,8 @@ You have the choice to develop on AWS EC2 using the [FPGA Developer AMI](https:/ To setup your instance for development, checkout our [Developer Resources](./developer_resources/README.md) where we provide Step-By-Step guides to setting up a GUI Desktop or a compute cluster. Before you start your first AWS FPGA design, we recommend that you go through one of the step-by-step guides. The guides will walk through development steps for hello world examples. Based on the tables above, pick the development environment that best fits your needs and use the guide to get started: - * For fastest way to get started on FPGA accelerator development, start with the software defined development environment. The guide starts with the [SW Hello World example](SDAccel/README.md). - * Next use the same guide to develop using the C/C++/openCL/RTL based [80+ examples on github](./SDAccel/examples/xilinx_2017.4). + * For fastest way to get started on FPGA accelerator development, start with the software-defined development environment. The guide starts with the [Hello World example](Vitis/README.md). + * Next use the same guide to develop using the C/C++/openCL/RTL based [60+ examples on github](./Vitis/examples/xilinx_2019.2). * For custom hardware development (HDK) environment, start with the [HDK Hello World example](hdk/README.md). * Next use the same guide to develop using the [cl\_dram\_dma](hdk/cl/examples/cl_dram_dma). @@ -124,9 +124,11 @@ Currently, AWS marketplace includes multiple versions of the FPGA Developer AMI, | 1.4.8+ | 2018.3 | v1.6.0-v1.6.X (Xilinx Vivado/SDx 2018.3) | | 1.4.11+ | 2019.1 | v1.7.0-v1.7.X (Xilinx Vivado/SDx 2019.1) | | 1.4.13+ | 2019.2 | v1.8.0-v1.8.X (Xilinx Vivado/Vitis 2019.2) | -Developer kit versions prior to v1.3.7 and Developer AMI prior to v1.4 (2017.1) reached end-of-life. See [AWS forum announcement](https://forums.aws.amazon.com/ann.jspa?annID=6068) for additional details. -If developing using SDAccel environment please refer to this [Runtime Compatibility Table](SDAccel/docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table) +Developer kit versions prior to v1.3.7 and Developer AMI prior to v1.4 (2017.1) reached end-of-life. See [AWS forum announcement](https://forums.aws.amazon.com/ann.jspa?annID=6068) for additional details. + +For software-defined development please look at the runtime compatibility table based on the Xilinx toolset in use: +[SDAccel](SDAccel/docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table) or [Vitis](Vitis/docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table) # Hardware Development Kit (HDK) From 4f7d97d4fd09f36be9fc1828e853187c48edadfe Mon Sep 17 00:00:00 2001 From: Deep Patel Date: Thu, 9 Apr 2020 09:45:18 -0500 Subject: [PATCH 13/31] Fixes to scripts based on customer feedback (#484) * Fixes for prepare_new_cl.sh * Update to FAQ * Early exit if running sdaccel_setup on a vitis instance * Changes per feedback from CSA --- FAQs.md | 2 +- Vitis/README.md | 15 +++++++-------- hdk/cl/developer_designs/prepare_new_cl.sh | 2 +- sdaccel_setup.sh | 8 ++++++++ 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/FAQs.md b/FAQs.md index c8b25573..a4e2a3cd 100644 --- a/FAQs.md +++ b/FAQs.md @@ -502,6 +502,6 @@ You would need a valid [on premise license](./hdk/docs/on_premise_licensing_help We have seen this issue when running RDP in 32 bit color mode where Vivado shows up as a blank window. Please modify RDP options to choose any color depth less than 32 bit and try re-connecting. -**Q: Why did my AFI creation fail with `***ERROR***: DCP has DNA_PORT instantiation, ingestion failed, exiting`? +**Q: Why did my AFI creation fail with `***ERROR***: DCP has DNA_PORT instantiation, ingestion failed, exiting`?** AWS does not support creating AFI's with the Device DNA instantiated within your design. Please create your design without instantiating the DNA_PORT primitive to be able to create your AFI. \ No newline at end of file diff --git a/Vitis/README.md b/Vitis/README.md index 8ad09e5a..004eb79d 100644 --- a/Vitis/README.md +++ b/Vitis/README.md @@ -38,7 +38,7 @@ The F1 HW Target compile time is ~50 minutes, therefore, software and hardware e ## AWS Account, F1/EC2 Instances, On-Premises, AWS IAM Permissions, AWS CLI and S3 Setup (One-time Setup) * [Setup an AWS Account](https://aws.amazon.com/free/) -* Launch an instance using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) which comes pre-installed with SDAccel and required licenses. +* Launch an instance using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) which comes pre-installed with Vitis and required licenses. * You may use this F1 instance to [build your host application and Xilinx FPGA binary](#createapp), however, it is more cost efficient to either: * Launch the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) on a compute EC2 instance, with a minimum of 30GiB RAM), **OR** * Follow the [On-Premises Instructions](../hdk/docs/on_premise_licensing_help.md) to purchase and install a license from Xilinx. @@ -175,7 +175,7 @@ When AFI creation completes successfully, the output should contain: ... ``` -If the “State” code indicates the AFI generation has "failed", the AFI creation logs can be found in the bucket location (```s3:///```) provided to create_sdaccel_afi.sh above. These will detail the errors encountered during the AFI creation process. +If the “State” code indicates the AFI generation has "failed", the AFI creation logs can be found in the bucket location (```s3:///```) provided to create_vitis_afi.sh above. These will detail the errors encountered during the AFI creation process. For help with AFI creation issues, see [create-fpga-image error codes](../hdk/docs/create_fpga_image_error_codes.md) @@ -183,11 +183,10 @@ For help with AFI creation issues, see [create-fpga-image error codes](../hdk/do # 3. Run the FPGA accelerated application on Amazon FPGA instances -* Start an FPGA instance using [FPGA Developer AMI on AWS Marketplace](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) and check the AMI [compatibility table](../README.md#devAmi) and [runtime compatibility table](./docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table). Alternatively, you can [create your own Runtime AMI](docs/Create_Runtime_AMI.md) for running your SDAccel applications on Amazon FPGA instances. - * *Assuming the developer flow (compilation) was done on a separate instance you will need to:* - * Copy the compiled host executable (exe) to the new instance +* Start an FPGA instance using [FPGA Developer AMI on AWS Marketplace](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) and check the AMI [compatibility table](../README.md#devAmi) and [runtime compatibility table](./docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table). Alternatively, you can [create your own Runtime AMI](docs/Create_Runtime_AMI.md) for running your Vitis applications on Amazon FPGA instances. + * *Assuming the developer flow (compilation) was done on a separate build instance you will need to:* + * Copy the compiled host executable (exe) to the new F1 instance * Copy the \*.awsxclbin AWS FPGA binary file to the new instance - * Depending on the host code, the \*.awsxclbin may need to named \.hw.\.awsxclbin .For Example: ```vector_addition.hw.xilinx_aws-vu9p-f1_shell-v04261818_201920_1.awsxclbin``` * Copy any data files required for execution to the new instance * [Clone the github repository to the new F1 instance and install runtime drivers](#gitsetenv) @@ -196,7 +195,7 @@ For help with AFI creation issues, see [create-fpga-image error codes](../hdk/do $ git clone https://github.com/aws/aws-fpga.git $AWS_FPGA_REPO_DIR $ cd $AWS_FPGA_REPO_DIR $ source vitis_setup.sh - $ ./helloworld ./vector_addition.awsxclbin + $ ./host ./vadd.awsxclbin ``` * Alternatively, to only setup the runtime environment & execute your host application: @@ -204,7 +203,7 @@ For help with AFI creation issues, see [create-fpga-image error codes](../hdk/do $ cd $AWS_FPGA_REPO_DIR $ source vitis_runtime_setup.sh # Other runtime env settings needed by the host app should be setup after this step # Wait till the MPD service has initialized. Check systemctl status mpd - $ ./helloworld ./vector_addition.awsxclbin + $ ./host ./vadd.awsxclbin ``` * The runtime setup script also starts the Xilinx XRT Message Proxy Daemon(MPD) service. To learn more about the XRT implementation, check the [XRT Instructions](./docs/XRT_installation_instructions.md#mpd) diff --git a/hdk/cl/developer_designs/prepare_new_cl.sh b/hdk/cl/developer_designs/prepare_new_cl.sh index 80d3e3f6..b84ebd6f 100755 --- a/hdk/cl/developer_designs/prepare_new_cl.sh +++ b/hdk/cl/developer_designs/prepare_new_cl.sh @@ -19,5 +19,5 @@ # Check if /build and /design directories exist, abort # Check if $HDK_COMMON_DIR exist -cp -r $HDK_SHELL_DIR/new_cl_template/build . +cp -rl $HDK_SHELL_DIR/new_cl_template/build . cp -r $HDK_SHELL_DIR/new_cl_template/design . diff --git a/sdaccel_setup.sh b/sdaccel_setup.sh index 8db58a02..bbce138b 100644 --- a/sdaccel_setup.sh +++ b/sdaccel_setup.sh @@ -158,11 +158,19 @@ for (( i = 0; i < ${#args[@]}; i++ )); do esac done + +if [[ ! -z "$XILINX_VITIS" ]]; then + debug_msg "XILINX_VITIS is set" + err_msg "XILINX_VITIS variable is set, but you are calling sdaccel_setup.sh. This likely means that you are calling source sdaccel_setup.sh with Xilinx Vitis installed. Xilinx has replaced SDAccel with Vitis from 2019.2 release onwards. Please checkout the Vitis README and flow instead." + return 1 +fi + # Check XILINX_SDX is set if ! check_set_xilinx_sdx; then return 1 fi + info_msg " XILINX_SDX is set to $XILINX_SDX" # Install patches as required. info_msg " Checking & installing required patches" From 61f6e2e162769276d3c14b7cd708ca07161c0c88 Mon Sep 17 00:00:00 2001 From: LiuHanCheng <2463765697@qq.com> Date: Wed, 29 Apr 2020 03:30:08 +0800 Subject: [PATCH 14/31] fix typo in README of CL_SDE example (#488) If my understand is correct, SDE IP use three interfaces of shell, including PCIS, PCIM and OCL, instead of two. --- hdk/cl/examples/cl_sde/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hdk/cl/examples/cl_sde/README.md b/hdk/cl/examples/cl_sde/README.md index cb82f592..bb9682ab 100644 --- a/hdk/cl/examples/cl_sde/README.md +++ b/hdk/cl/examples/cl_sde/README.md @@ -35,7 +35,7 @@ See [SDE HW Guide](../../../../sdk/apps/virtual-ethernet/doc/SDE_HW_Guide.md) fo ## Interfaces and Address Range ### Interfaces -CL_SDE uses two interfaces from the Shell. +CL_SDE uses three interfaces from the Shell. The PCIS interface is used to provide connectivity between the [Virtual Ethernet Application](../../../../sdk/apps/virtual-ethernet/doc/Virtual_Ethernet_Application_Guide.md) and the SDE. The OCL interface is used to provide connectivity between the host and all the test/control/utility blocks (except the SDE). The PCIM interfaces is used by the SDE to read and write to host memory. From b22012466d2f7740fc19caeda3ad7b648c900de5 Mon Sep 17 00:00:00 2001 From: Deep Patel Date: Tue, 12 May 2020 09:35:57 -0500 Subject: [PATCH 15/31] Fixes to create_vitis_sfi script (#598) (#487) * Fixes to create_vitis_sfi script * Fixed based on feedback --- Vitis/README.md | 7 ------- Vitis/tools/create_vitis_afi.sh | 10 +++------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/Vitis/README.md b/Vitis/README.md index 004eb79d..18e2f29c 100644 --- a/Vitis/README.md +++ b/Vitis/README.md @@ -193,13 +193,6 @@ For help with AFI creation issues, see [create-fpga-image error codes](../hdk/do * To setup tools, runtime environment & execute your Host Application: ``` $ git clone https://github.com/aws/aws-fpga.git $AWS_FPGA_REPO_DIR - $ cd $AWS_FPGA_REPO_DIR - $ source vitis_setup.sh - $ ./host ./vadd.awsxclbin - ``` - -* Alternatively, to only setup the runtime environment & execute your host application: - ``` $ cd $AWS_FPGA_REPO_DIR $ source vitis_runtime_setup.sh # Other runtime env settings needed by the host app should be setup after this step # Wait till the MPD service has initialized. Check systemctl status mpd diff --git a/Vitis/tools/create_vitis_afi.sh b/Vitis/tools/create_vitis_afi.sh index d6717019..a83ec6fd 100755 --- a/Vitis/tools/create_vitis_afi.sh +++ b/Vitis/tools/create_vitis_afi.sh @@ -23,6 +23,8 @@ script_name=$(basename $full_script) source $AWS_FPGA_REPO_DIR/shared/bin/set_common_functions.sh source $AWS_FPGA_REPO_DIR/shared/bin/set_common_env_vars.sh +script_dir=$(dirname $full_script) + debug=0 @@ -91,12 +93,6 @@ while [ "$1" != "" ]; do shift done -if [ "$HDK_DIR" == "" ] -then - err_msg "Env HDK_DIR not set" - exit 1 -fi -echo $HDK_DIR if [ "$RELEASE_VER" == "" ] then err_msg "Env variable RELEASE_VER not set, did you source sdaccel_setup.sh?" @@ -199,7 +195,7 @@ cp ${timestamp}_SH_CL_routed.dcp ./to_aws/ #STEP 2 #Create Manifest file strategy=DEFAULT -hdk_version=$(grep 'HDK_VERSION' $HDK_DIR/hdk_version.txt | sed 's/=/ /g' | awk '{print $2}') +hdk_version=$(grep 'HDK_VERSION' $script_dir/../../hdk/hdk_version.txt | sed 's/=/ /g' | awk '{print $2}') shell_version=0x04261818 tool_version=v$RELEASE_VER device_id=0xF010 From c61dbf59b37d622dbcd9553662612cf59bd95657 Mon Sep 17 00:00:00 2001 From: Deep Patel Date: Fri, 15 May 2020 17:15:45 -0500 Subject: [PATCH 16/31] Release v1.4.14 (#489) * Added a new platform file to fix DDR bandwidth issue * Add Vitis Debug document * Updated broken link in the Testing doc --- RELEASE_NOTES.md | 4 + Vitis/README.md | 6 +- ...aws-vu9p-f1_shell-v04261818_201920_2.spfm} | 2 +- ...aws-vu9p-f1_shell-v04261818_201920_2.xpfm} | 6 +- Vitis/docs/Debug_Vitis_Kernel.md | 152 ++++++++++++++++++ Vitis/tools/create_vitis_afi.sh | 4 +- hdk/README.md | 1 + hdk/hdk_version.txt | 2 +- .../aws_fpga_test_utils/AwsFpgaTestBase.py | 4 +- shared/tests/TESTING.md | 2 +- vitis_setup.sh | 14 +- 11 files changed, 177 insertions(+), 20 deletions(-) rename Vitis/aws_platform/{xilinx_aws-vu9p-f1_shell-v04261818_201920_1/sw/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.spfm => xilinx_aws-vu9p-f1_shell-v04261818_201920_2/sw/xilinx_aws-vu9p-f1_shell-v04261818_201920_2.spfm} (96%) rename Vitis/aws_platform/{xilinx_aws-vu9p-f1_shell-v04261818_201920_1/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.xpfm => xilinx_aws-vu9p-f1_shell-v04261818_201920_2/xilinx_aws-vu9p-f1_shell-v04261818_201920_2.xpfm} (83%) create mode 100644 Vitis/docs/Debug_Vitis_Kernel.md diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 7c1ceb01..a6e97d95 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -24,6 +24,10 @@ * 1 DDR controller implemented in the SH (always available) * 3 DDR controllers implemented in the CL (configurable number of implemented controllers allowed) +## Release 1.4.14 (See [ERRATA](./ERRATA.md) for unsupported features) +* Updated Vitis Platform file to fix a DDR bandwidth issue +* Added Vitis Debug Documentation + ## Release 1.4.13 (See [ERRATA](./ERRATA.md) for unsupported features) * FPGA developer kit now supports Xilinx Vivado/Vitis 2019.2 * To upgrade, use [Developer AMI v1.8.0](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) on the AWS Marketplace. diff --git a/Vitis/README.md b/Vitis/README.md index 18e2f29c..a3248372 100644 --- a/Vitis/README.md +++ b/Vitis/README.md @@ -51,7 +51,7 @@ The F1 HW Target compile time is ~50 minutes, therefore, software and hardware e ## Github and Environment Setup * Clone this github repository and source the *vitis_setup.sh* script. This will take care of: * Downloading the required files: - * [AWS Platform](./aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1) that allows Xilinx FPGA Binary files to target AWS F1 instances + * [AWS Platform](./aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_2) that allows Xilinx FPGA Binary files to target AWS F1 instances * [AFI Creation script](./tools/create_vitis_afi.sh) that generates an AFI and AWS FPGA Binary from a Xilinx FPGA Binary * Installing the required XRT, libraries and drivers @@ -60,7 +60,7 @@ The F1 HW Target compile time is ~50 minutes, therefore, software and hardware e $ cd $AWS_FPGA_REPO_DIR $ source vitis_setup.sh ``` - * Valid platforms for shell_v04261818: `AWS_PLATFORM_201920_1` (Default) AWS F1 Vitis platform. + * Valid platforms for shell_v04261818: `AWS_PLATFORM_201920_2` (Default) AWS F1 Vitis platform. # 1. Build the host application, Xilinx FPGA binary and verify you are ready for FPGA acceleration @@ -211,4 +211,4 @@ For help with AFI creation issues, see [create-fpga-image error codes](../hdk/do * [XRT Documentation](https://xilinx.github.io/XRT/master/html/) -* [XRT MPD Documentation](https://xilinx.github.io/XRT/master/html/cloud_vendor_support.html) \ No newline at end of file +* [XRT MPD Documentation](https://xilinx.github.io/XRT/master/html/cloud_vendor_support.html) diff --git a/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/sw/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.spfm b/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_2/sw/xilinx_aws-vu9p-f1_shell-v04261818_201920_2.spfm similarity index 96% rename from Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/sw/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.spfm rename to Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_2/sw/xilinx_aws-vu9p-f1_shell-v04261818_201920_2.spfm index a2726185..8cf04dce 100644 --- a/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/sw/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.spfm +++ b/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_2/sw/xilinx_aws-vu9p-f1_shell-v04261818_201920_2.spfm @@ -2,7 +2,7 @@ diff --git a/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.xpfm b/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_2/xilinx_aws-vu9p-f1_shell-v04261818_201920_2.xpfm similarity index 83% rename from Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.xpfm rename to Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_2/xilinx_aws-vu9p-f1_shell-v04261818_201920_2.xpfm index 6dded946..b0f9bee9 100644 --- a/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_1/xilinx_aws-vu9p-f1_shell-v04261818_201920_1.xpfm +++ b/Vitis/aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_2/xilinx_aws-vu9p-f1_shell-v04261818_201920_2.xpfm @@ -2,7 +2,7 @@ @@ -10,11 +10,11 @@ - + - + diff --git a/Vitis/docs/Debug_Vitis_Kernel.md b/Vitis/docs/Debug_Vitis_Kernel.md new file mode 100644 index 00000000..839f49ff --- /dev/null +++ b/Vitis/docs/Debug_Vitis_Kernel.md @@ -0,0 +1,152 @@ +Hardware Debug of Vitis Kernel +====================== + +This file contains the following sections: + +1. Overview +2. Enabling ChipScope Debug +3. Host code changes to support debugging +4. Building the executable, creating the AFI, and executing the host code +5. Start debug servers + + +## 1. Overview +The sections below give you a brief explanation of the steps required to debug your Vitis kernel. They include enabling ChipScope debug, pausing the execution of the host code at the appropriate stage to ensure the setup of ILA triggers, building the running the host code and starting the debug servers to debug the design in hardware. + +## 2. Enabling ChipScope Debug + +Debug cores can be added to the AXI interfaces on the kernel itself to monitor AXI transaction level activity (part of the ChipScope Debug feature of Vitis). + +Adding debug cores to the AXI interfaces on the kernel can be done using the v++ --dk chipscope option with the compute unit name and optional interface name. + +This can be enabled by adding an v++ option to the CLFLAGS in the makefile. The --dk option shown below shows the general usage: + +``` +--dk chipscope:: +``` + +For example, to add ChipScope debugging to the helloworld_ocl OpenCL example , enabling chipscope debug can be accomplished by adding the following v++ option to the CLFLAGS in the makefile: + +``` +--dk chipscope:krnl_vadd_1 +``` + +For detailed usage and more examples, refer to the Debugging section of Vitis Application Acceleration (UG1393). + + +### Adding debug cores to the RTL kernel code + +To debug signals internal to an RTL Kernel you need to instantiate debug cores like the Integrated Logic Analyzer(ILA), Virtual Input/Output(VIO) etc in your application RTL kernel code. + +The ILA Debug IP can be created and added to the RTL Kernel in a couple of ways. + + +1. Open the ILA IP customization wizard in the Vivado GUI and customize the ILA and instantiate it in the RTL code – similar to any other IP in Vivado. + + +2. Create the ILA IP on the fly using TCL. A snippet of the create_ip TCL command is shown below. The example below creates the ILA IP with 7 probes and associates properties with the IP. + +``` +create_ip -name ila -vendor xilinx.com -library ip -module_name ila_0 +set_property -dict [list CONFIG.C_PROBE6_WIDTH {32} CONFIG.C_PROBE3_WIDTH {64} +CONFIG.C_NUM_OF_PROBES {7} CONFIG.C_EN_STRG_QUAL {1} CONFIG.C_INPUT_PIPE_STAGES {2} CONFIG.C_ADV_TRIGGER {true} CONFIG.ALL_PROBE_SAME_MU_CNT {4} CONFIG.C_PROBE6_MU_CNT {4} CONFIG.C_PROBE5_MU_CNT {4} CONFIG.C_PROBE4_MU_CNT {4} CONFIG.C_PROBE3_MU_CNT {4} CONFIG.C_PROBE2_MU_CNT {4} CONFIG.C_PROBE1_MU_CNT {4} CONFIG.C_PROBE0_MU_CNT {4}] [get_ips ila_0] +``` + +This TCL file should be added as an RTL Kernel source in the Makefile of your design + + +Now you are ready to instantiate the ILA Debug core in your RTL Kernel. The RTL code snippet below is an ILA that monitors the output of a combinatorial adder. + + // ILA monitoring combinatorial adder + ila_0 i_ila_0 ( + .clk(ap_clk), // input wire clk + .probe0(areset), // input wire [0:0] probe0 + .probe1(rd_fifo_tvalid_n), // input wire [0:0] probe1 + .probe2(rd_fifo_tready), // input wire [0:0] probe2 + .probe3(rd_fifo_tdata), // input wire [63:0] probe3 + .probe4(adder_tvalid), // input wire [0:0] probe4 + .probe5(adder_tready_n), // input wire [0:0] probe5 + .probe6(adder_tdata) // input wire [31:0] probe6 + ); + + +## 3. Host code changes to support debugging + +The application host code needs to be modified to ensure you can set up the ILA trigger conditions **prior** to running the kernel. + + + +The host code shown below introduces the wait for the setup of ILA Trigger conditions and the arming of the ILA. + +src/host.cpp + + void wait_for_enter(const std::string& msg) + { + std::cout << msg << std::endl; + std::cin.ignore(std::numeric_limits::max(), '\n'); + } + + ... + + cl::Program::Binaries bins = xcl::import_binary_file(binaryFile); + devices.resize(1); + cl::Program program(context, devices, bins); + cl::Kernel krnl_vadd(program,"krnl_vadd_rtl"); + + wait_for_enter("\nPress ENTER to continue after setting up ILA trigger..."); + + //Allocate Buffer in Global Memory + + ... + + //Launch the Kernel + q.enqueueTask(krnl_vadd); + + + +## 4. Building the executable, creating the AFI and executing the host code + +- **Build the executable** in your design directory (`your_design_directory`) by running the steps below: + +``` + cd your_design_directory + + make all DEVICES=$AWS_PLATFORM +``` + +- **Creating and registering the AFI** + +Please note, the angle bracket directories need to be replaced according to the user setup. + +``` + $VITIS_DIR/tools/create_vitis_afi.sh -xclbin=your_design.xclbin -o=your_design.awsxclbin -s3_bucket= +``` + +- **Setup and Execute** + +``` + $ cd $AWS_FPGA_REPO_DIR + $ source vitis_runtime_setup.sh + $ ./host +``` +This produces the following output: +``` + + platform Name: Xilinx + Vendor Name : Xilinx + Found Platform + XCLBIN File Name: vadd + INFO: Importing ./binary_container_1.awsxclbin + Loading: './binary_container_1.awsxclbin' + Successfully skipped reloading of local image. + + Press ENTER to continue after setting up ILA trigger... +``` + + +## 5. Start Debug Servers + +#### Starting Debug Servers on Amazon F1 instance +Instructions to start the debug servers on an Amazon F1 instance can be found [here](../../hdk/docs/Virtual_JTAG_XVC.md). +Once you have setup your ILA triggers and armed the ILA core, you can now Press Enter on your host to continue execution of the application and RTL Kernel. + diff --git a/Vitis/tools/create_vitis_afi.sh b/Vitis/tools/create_vitis_afi.sh index a83ec6fd..c7bd9b9a 100755 --- a/Vitis/tools/create_vitis_afi.sh +++ b/Vitis/tools/create_vitis_afi.sh @@ -213,9 +213,9 @@ clock_main_a0=$(echo `grep -B 1 SYSTEM ${timestamp}_clocks.json | grep -o -e '[0 clock_extra_b0=$(echo `grep -B 2 DATA_CLK ${timestamp}_clocks.json | grep freq | grep -o -e '[0-9]*'`) clock_extra_c0=$(echo `grep -B 2 KERNEL_CLK ${timestamp}_clocks.json | grep -o -e '[0-9]*'`) -if [[ "$vendor" != "xilinx" && "$board_id" != "aws-vu9p-f1" && "$plat_name" != "shell-v04261818" && "$major" != "201920" && "$minor" != "1" ]] +if [[ "$vendor" != "xilinx" && "$board_id" != "aws-vu9p-f1" && "$plat_name" != "shell-v04261818" && "$major" != "201920" && "$minor" != "2" ]] then - err_msg "Platform ${vendor}_${board_id}_${plat_name}_${major}_${minor} used to create xclbin is not correct, you should be using xilinx_aws-vu9p-f1_shell-v04261818_201920_1" + err_msg "Platform ${vendor}_${board_id}_${plat_name}_${major}_${minor} used to create xclbin is not correct, you should be using xilinx_aws-vu9p-f1_shell-v04261818_201920_2" exit fi diff --git a/hdk/README.md b/hdk/README.md index 48238144..032d0859 100644 --- a/hdk/README.md +++ b/hdk/README.md @@ -145,6 +145,7 @@ To be notified via e-mail when the build completes: 1. Set up notification via SNS: ``` + $ pip install --user --upgrade boto3 # boto3 package is required by the notify_via_sns script $ export EMAIL=your.email@example.com $ $AWS_FPGA_REPO_DIR/shared/bin/scripts/notify_via_sns.py diff --git a/hdk/hdk_version.txt b/hdk/hdk_version.txt index b2fb0ae7..4d6f4aed 100644 --- a/hdk/hdk_version.txt +++ b/hdk/hdk_version.txt @@ -1 +1 @@ -HDK_VERSION=1.4.13 +HDK_VERSION=1.4.14 diff --git a/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py b/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py index 56a9f371..32a5e014 100644 --- a/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py +++ b/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py @@ -263,7 +263,7 @@ def get_sdaccel_xclbin_dir(examplePath): @staticmethod def get_vitis_xclbin_dir(examplePath, target='hw'): - return os.path.join(AwsFpgaTestBase.get_sdaccel_example_fullpath(examplePath=examplePath), "build_dir.{}.xilinx_aws-vu9p-f1_shell-v04261818_201920_1".format(target)) + return os.path.join(AwsFpgaTestBase.get_sdaccel_example_fullpath(examplePath=examplePath), "build_dir.{}.xilinx_aws-vu9p-f1_shell-v04261818_201920_2".format(target)) @staticmethod def get_sdaccel_example_s3_root_tag(examplePath, target, rteName, xilinxVersion): @@ -439,7 +439,7 @@ def get_vitis_example_run_cmd(examplePath, xilinxVersion): if launch_description[0].get("cmd_args", None): run_cmd += " {}".format(((launch_description[0].get("cmd_args", None).replace(".xclbin", ".awsxclbin")).replace( - "PROJECT", ".")).replace("BUILD", "./build_dir.hw.xilinx_aws-vu9p-f1_shell-v04261818_201920_1")) + "PROJECT", ".")).replace("BUILD", "./build_dir.hw.xilinx_aws-vu9p-f1_shell-v04261818_201920_2")) assert run_cmd is not None, "Could not find run_cmd(em_cmd) or (host_exe) in the example description here {}".format( examplePath) diff --git a/shared/tests/TESTING.md b/shared/tests/TESTING.md index 1e0e5aeb..2052f299 100644 --- a/shared/tests/TESTING.md +++ b/shared/tests/TESTING.md @@ -59,7 +59,7 @@ The boto3 package is the AWS Python API. It can be used to start and terminate instances and any other API operation that you have permissions for. -Configuration of account credentials is explained in the [Quickstart](http://boto3.readthedocs.io/en/latest/guide/quickstart.html#configuration). +Configuration of account credentials is explained in the [Quickstart](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html#configuration). The following command will install the latest release. diff --git a/vitis_setup.sh b/vitis_setup.sh index 2f1e6a93..a979b17e 100644 --- a/vitis_setup.sh +++ b/vitis_setup.sh @@ -275,18 +275,18 @@ function setup_xsa { fi } - #-------------------201920_1 Vitis Platform---------------------- - setup_xsa xilinx_aws-vu9p-f1_shell-v04261818_201920_1 xsa_v121319_shell_v04261818 AWS_PLATFORM_201920_1 - info_msg "AWS Platform: 201920_1 Vitis Platform is up-to-date" - #-------------------201920_1 Vitis Platform---------------------- + #-------------------201920_2 Vitis Platform---------------------- + setup_xsa xilinx_aws-vu9p-f1_shell-v04261818_201920_2 xsa_v121319_shell_v04261818 AWS_PLATFORM_201920_2 + info_msg "AWS Platform: 201920_2 Vitis Platform is up-to-date" + #-------------------201920_2 Vitis Platform---------------------- # Setup XRT as we need it for building setup_runtime -export AWS_PLATFORM=$AWS_PLATFORM_201920_1 -info_msg "The default AWS Platform has been set to: \"AWS_PLATFORM=\$AWS_PLATFORM_201920_1\" " +export AWS_PLATFORM=$AWS_PLATFORM_201920_2 +info_msg "The default AWS Platform has been set to: \"AWS_PLATFORM=\$AWS_PLATFORM_201920_2\" " info_msg "Vitis Setup PASSED" -info_msg "To run a runtime example, start the MPD service by calling: \`systemctl is-active --quiet mpd || sudo systemctl start mpd\`" \ No newline at end of file +info_msg "To run a runtime example, start the MPD service by calling: \`systemctl is-active --quiet mpd || sudo systemctl start mpd\`" From 0a7e06b5d1c652a521017056b2088541b9369bd3 Mon Sep 17 00:00:00 2001 From: Amirali Sharifian Date: Fri, 3 Jul 2020 18:25:35 -0700 Subject: [PATCH 17/31] Update XRT_installation_instructions.md (#493) --- SDAccel/docs/XRT_installation_instructions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SDAccel/docs/XRT_installation_instructions.md b/SDAccel/docs/XRT_installation_instructions.md index 78142ea2..a6503c98 100644 --- a/SDAccel/docs/XRT_installation_instructions.md +++ b/SDAccel/docs/XRT_installation_instructions.md @@ -42,7 +42,7 @@ sudo yum reinstall xrt_*.rpm -y ```bash curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.7.0/Patches/XRT_2019_1_RC2/xrt_201910.2.2.0_7.6.1810-xrt.rpm -o xrt.rpm -curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.7.0/Patches/XRT_2019_1_RC2/xrt_201910.2.2.0_7.6.1810-aws.rpm-o xrt-aws.rpm +curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.7.0/Patches/XRT_2019_1_RC2/xrt_201910.2.2.0_7.6.1810-aws.rpm -o xrt-aws.rpm sudo yum reinstall xrt*.rpm -y ``` ### 2018.3 @@ -58,4 +58,4 @@ sudo yum reinstall xrt*.rpm -y curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.5.0/Patches/XRT_2018_2_XDF_RC5/xrt_201802.2.1.0_7.5.1804-xrt.rpm -o xrt.rpm curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.5.0/Patches/XRT_2018_2_XDF_RC5/xrt_201802.2.1.0_7.5.1804-aws.rpm -o xrt-aws.rpm sudo yum reinstall xrt*.rpm -y -``` \ No newline at end of file +``` From a22e34a9a5b8b20fd8f77c03a9a39f0155c9cee9 Mon Sep 17 00:00:00 2001 From: David Durst Date: Fri, 3 Jul 2020 21:30:04 -0400 Subject: [PATCH 18/31] Fixing Link To Vitis Examples (#494) The old link to the Vitis examples in the README.md lead to https://github.com/aws/aws-fpga/blob/master/Vitis/examples/xilinx_2019.2, which is a 404 error. The new link is the result of going to https://github.com/aws/aws-fpga/blob/master/Vitis/examples and then entering the xilinx_2019.2 folder. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 89419c1e..a771195a 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ To setup your instance for development, checkout our [Developer Resources](./dev Before you start your first AWS FPGA design, we recommend that you go through one of the step-by-step guides. The guides will walk through development steps for hello world examples. Based on the tables above, pick the development environment that best fits your needs and use the guide to get started: * For fastest way to get started on FPGA accelerator development, start with the software-defined development environment. The guide starts with the [Hello World example](Vitis/README.md). - * Next use the same guide to develop using the C/C++/openCL/RTL based [60+ examples on github](./Vitis/examples/xilinx_2019.2). + * Next use the same guide to develop using the C/C++/openCL/RTL based [60+ examples on github](https://github.com/Xilinx/Vitis_Accel_Examples/tree/bb80c8ec699c3131e8874735bd99475ac6fe2ec7). * For custom hardware development (HDK) environment, start with the [HDK Hello World example](hdk/README.md). * Next use the same guide to develop using the [cl\_dram\_dma](hdk/cl/examples/cl_dram_dma). From 8762e6f7d1e65349969f433ffa976be832d659cb Mon Sep 17 00:00:00 2001 From: ChangLiu <1061974239@qq.com> Date: Thu, 9 Jul 2020 02:48:06 +0800 Subject: [PATCH 19/31] Update README.md (#495) Fix table error in Overview of Development Tools --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a771195a..87e6dd01 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ The AWS EC2 FPGA Development Kit is provided by AWS to support development and r | Tool | Development/Runtime | Tool location | Description | | --------|---------|---------|---------| -| Vitis 2019.2 Development | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Software Defined Accelerator Development using the new Vitis toolset](Vitis/README.md) | +| Vitis 2019.2 | Development | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Software Defined Accelerator Development using the new Vitis toolset](Vitis/README.md) | | Vivado 2017.4, 2018.2, 2018.3, 2019.1 & 2019.2 | Development | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Hardware Accelerator Development](hdk/README.md) | | SDx 2017.4, 2018.2, 2018.3 & 2019.1| Development | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Software Defined Accelerator Development](SDAccel/README.md) | | FPGA AFI Management Tools | Runtime | [SDK - fpga\_mgmt\_tools](sdk/userspace/fpga_mgmt_tools) | Command-line tools used for FPGA management while running on the F1 instance | From 1023466e61a581eeb40cf1ca110babbf94868732 Mon Sep 17 00:00:00 2001 From: Deep Patel Date: Sun, 12 Jul 2020 13:19:17 -0500 Subject: [PATCH 20/31] Release v1.4.15 (#496) * Add Vitis Debug document (#601) * Create Debug_OpenCL_Kernel.md * Update and rename Debug_OpenCL_Kernel.md to Debug_Vitis_Kernel.md * Updated the shell interface spec to reflect current shell (#603) * Updated the shell interface spec to reflect current shell and pointed to the DDR Data Retention doc * Update hdk/docs/AWS_Shell_Interface_Specification.md * Enhance DDR Model Build qualifiers in hdk_setup.sh script. (#604) * Enhance DDR Model Build qualifiers in hdk_setup.sh script. * Enhance the DDR model build's lock file creation+check to not rely on external tools. * Update Virtual_JTAG_XVC.md (#606) * AR73068 patching (#608) * Added patching mechanism for Vivado AR73068 * Updated supported versions * Added dma range error to interrupt status register metrics (#591) * added dma range error to interrupt status register metrics * updated tests to match change to output * Fixing test_fpga_tools to accomodate dma range error addition. (#609) * Fixed the lines where we expect ` clock group c ` --- .gitignore | 1 + ERRATA.md | 21 ++- README.md | 11 +- RELEASE_NOTES.md | 6 + SDAccel/examples/3rd_party/README.md | 11 +- hdk/common/verif/scripts/.gitignore | 2 + hdk/common/verif/scripts/Makefile | 34 +++++ hdk/common/verif/scripts/init.sh | 16 +-- hdk/docs/AFI_Manifest.md | 1 + hdk/docs/AWS_Shell_Interface_Specification.md | 16 +-- hdk/docs/Virtual_JTAG_XVC.md | 32 ++++- hdk/hdk_version.txt | 2 +- hdk_setup.sh | 40 +++--- sdk/tests/test_fpga_tools.py | 16 +-- .../fpga_mgmt_tools/src/fpga_local_cmd.c | 4 + sdk/userspace/include/hal/fpga_common.h | 7 +- shared/bin/set_common_functions.sh | 128 +++++++++++++++++- shared/tests/bin/check_md_links.py | 2 +- shared/tests/test_md_links.py | 2 +- supported_vivado_versions.txt | 4 + vitis_setup.sh | 4 +- 21 files changed, 273 insertions(+), 87 deletions(-) create mode 100644 hdk/common/verif/scripts/.gitignore create mode 100644 hdk/common/verif/scripts/Makefile diff --git a/.gitignore b/.gitignore index b5abe33d..36dee488 100644 --- a/.gitignore +++ b/.gitignore @@ -110,3 +110,4 @@ patches/* .batch .temp +.python-version diff --git a/ERRATA.md b/ERRATA.md index 408dfa16..7f99a344 100644 --- a/ERRATA.md +++ b/ERRATA.md @@ -9,14 +9,25 @@ * DRAM Data retention is not supported for CL designs with less than 4 DDRs enabled * Combinatorial loops in CL designs are not supported. * Connecting one of the clocks provided from the shell (clk_main_a0, clk_extra_a1, etc...) directly to a BUFG in the CL is not supported by the Xilinx tools and may result in a non-functional clock. To workaround this limitation, it is recommended to use an MMCM to feed the BUFG (clk_from_shell -> MMCM -> BUFG). Please refer to [Xilinx AR# 73360](https://www.xilinx.com/support/answers/73360.html) for further details. + +### Xilinx Design Advisory for UltraScale/UltraScale+ DDR4/DDR3 IP - Memory IP Timing Exceptions (AR# 73068) +AWS EC2 F1 customers using the DDR4 IP in customer logic (HDK or SDAccel/Vitis designs) may be impacted by a recent design advisory from Xilinx. + +AWS customers may experience hardware failures including: post calibration data errors and DQS gate tracking issues. The error condition is build dependent and errors would need to be detected on the first write/read access after a successful calibration to prevent further data corruption. + +To detect if your build is impacted by this bug, AWS recommends all EC2 F1 customers utilizing the DDR4 IP in their designs should run a TCL script on the design checkpoint point (DCP) to check to determine if the design is susceptible to this issue. If the check passes, your design is safe to use as the hardware will function properly. +If the check fails, the design is susceptible to the issue and will need to be regenerated using the same tool version with the AR 73068 patch. +For designs under development, we recommend applying the patch to your on-premises tools or update to developer kit v1.4.15. +For additional details, please refer to the [Xilinx Answer Record #73068](https://www.xilinx.com/support/answers/73068.html) + ### 2019.1 * Vivado `compile_simlib` command fails to generate the following verilog IP libraries for the following simulators. +* Please refer to the Xilinx Answer record for details. -| Library(verilog) | Simulator | -|---|---| -| `sync_ip` | Cadence IES | -| `hdmi_gt_controller_v1_0_0` | Synopsys VCS | -* We are working with Xilinx to provide a fix for these. +| Library(verilog) | Simulator | Xilinx Answer Record | +|---|---|---| +| `sync_ip` | Cadence IES | [AR72795](https://www.xilinx.com/support/answers/72795.html) | +| `hdmi_gt_controller_v1_0_0` | Synopsys VCS | [AR72601](https://www.xilinx.com/support/answers/72601.html) | ## SDK diff --git a/README.md b/README.md index 87e6dd01..10d63b23 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ 1. [Overview of AWS EC2 FPGA Development Kit](#overviewdevkit) - [Development environments](#overviewdevenv) - [Runtime environments](#overviewrunenv) - - [Example applications](#overviewexapps) - [Development tools](#overviewdevtools) + - [Example applications](#overviewexapps) 2. [Getting Started](#gettingstarted) 3. [FPGA Developer AMI available on AWS Marketplace](#devAmi) 4. [FPGA Hardware Development Kit (HDK)](#fpgahdk) @@ -18,7 +18,9 @@ # Overview of AWS EC2 FPGA Development Kit -The AWS EC2 FPGA Development Kit is provided by AWS to support development and runtime on [AWS FPGA instances](https://aws.amazon.com/ec2/instance-types/f1/). Amazon EC2 FPGA instances are high-performance compute instances with field programmable gate arrays (FPGAs) that are programmed to create custom hardware accelerations in EC2. F1 instances are easy to program and AWS provides everything needed to develop, simulate, debug, compile and run hardware accelerated applications. Using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ), developers create an FPGA design. Once the FPGA design (also called CL - Custom logic) is complete, developers create the Amazon FPGA Image (AFI), and easily deploy it to the F1 instance. AFIs are reusable, shareable and can be deployed in a scalable and secure way. +AWS EC2 FPGA Development Kit is a set of free development and runtime tools that provide everything needed to develop, simulate, debug, compile and run hardware accelerated applications on [Amazon EC2 F1 instances](https://aws.amazon.com/ec2/instance-types/f1/), EC2 F1 instances are high-performance compute instances with field programmable gate arrays (FPGAs) that enable the development and deployment of custom hardware accelerators on AWS cloud. + +AWS EC2 FPGA Development Kit content is distributed between this github repository and [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) provided by AWS, developers are able to develop, simulate and debug an FPGA design on compute [EC2 instance](https://aws.amazon.com/ec2/) with no cost of development or runtime tools. Once the FPGA design (also called CL - Custom logic) is complete, developers create the Amazon FPGA Image (AFI), and easily deploy it to the F1 instance. AFIs are reusable, shareable and can be deployed in a scalable and secure way. ![Alt text](hdk/docs/images/f1-Instance-How-it-Works-flowchart.jpg) @@ -78,13 +80,12 @@ The AWS EC2 FPGA Development Kit is provided by AWS to support development and r # Getting Started -### New to AWS? +### Getting familiar with AWS If you have never used AWS before, we recommend you start with [AWS getting started training](https://aws.amazon.com/getting-started/), and focus on the basics of the [AWS EC2](https://aws.amazon.com/ec2/) and [AWS S3](https://aws.amazon.com/s3/) services. Understanding the fundamentals of these services will make it easier to work with AWS FPGAs. AWS FPGA generation and EC2 F1 instances are supported in the us-east-1 (N. Virginia), us-west-2 (Oregon), eu-west-1 (Ireland) and us-gov-west-1 ([GovCloud US](https://aws.amazon.com/govcloud-us/)) [regions](https://aws.amazon.com/about-aws/global-infrastructure/). - -### New to AWS FPGAs and setting up a development environment? +### Setting up development environment for the first time The developer kit is supported for Linux operating systems only. You have the choice to develop on AWS EC2 using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) or on-premises. Within a linux environment, you can execute `git clone https://github.com/aws/aws-fpga.git` to download the latest release to your EC2 Instance or local server. Help on cloning from github is available [here](https://help.github.com/articles/which-remote-url-should-i-use/). When using a SSH connection, execute `git clone git@github.com:aws/aws-fpga.git`. [To get help with connecting to Github via SSH](https://help.github.com/articles/connecting-to-github-with-ssh/). diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index a6e97d95..443d2bea 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -24,6 +24,12 @@ * 1 DDR controller implemented in the SH (always available) * 3 DDR controllers implemented in the CL (configurable number of implemented controllers allowed) +## Release 1.4.15 (See [ERRATA](./ERRATA.md) for unsupported features) +* Added Xilinx AR#73068 patching +* Added DMA range error to the interrupt status register metrics +* Enhanced DDR model rebuild qualifiers in hdk_setup.sh +* Updated Virtual JTAG Documentation + ## Release 1.4.14 (See [ERRATA](./ERRATA.md) for unsupported features) * Updated Vitis Platform file to fix a DDR bandwidth issue * Added Vitis Debug Documentation diff --git a/SDAccel/examples/3rd_party/README.md b/SDAccel/examples/3rd_party/README.md index 5e82242d..d50cca85 100644 --- a/SDAccel/examples/3rd_party/README.md +++ b/SDAccel/examples/3rd_party/README.md @@ -81,7 +81,6 @@ make TARGETS=hw DEVICES=$AWS_PLATFORM all * For more information on running this example on an F1 instance, see [this](../../README.md#runonf1). - ## Xilinx and third party Implementation Differences #### Host Code | third party FPGA | Xilinx | @@ -104,18 +103,12 @@ make TARGETS=hw DEVICES=$AWS_PLATFORM all | declares and initializes an struct object together | declare an struct object and then initialize it separately | ## SUPPORT -For more information check here: -[SDAccel User Guides][] +For more information check the [SDAccel User Guides](http://www.xilinx.com/support/documentation-navigation/development-tools/software-development/sdaccel.html?resultsTablePreSelect=documenttype:SeeAll#documentation) -For questions and to get help on this project or your own projects, visit the [SDAccel Forums][]. +For questions and to get help on this project or your own projects, visit the [SDAccel Forums](https://forums.xilinx.com/t5/SDAccel/bd-p/SDx) ## REVISION HISTORY Date | Readme Version | Revision Description --------|----------------|------------------------- SEP2017 | 1.0 | Initial release - - - -[SDAccel Forums]: https://forums.xilinx.com/t5/SDAccel/bd-p/SDx -[SDAccel User Guides]: http://www.xilinx.com/support/documentation-navigation/development-tools/software-development/sdaccel.html?resultsTablePreSelect=documenttype:SeeAll#documentation diff --git a/hdk/common/verif/scripts/.gitignore b/hdk/common/verif/scripts/.gitignore new file mode 100644 index 00000000..bd7e70f1 --- /dev/null +++ b/hdk/common/verif/scripts/.gitignore @@ -0,0 +1,2 @@ +.done + diff --git a/hdk/common/verif/scripts/Makefile b/hdk/common/verif/scripts/Makefile new file mode 100644 index 00000000..3098d515 --- /dev/null +++ b/hdk/common/verif/scripts/Makefile @@ -0,0 +1,34 @@ +#------------------------------------------------------------------------------- +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. +#------------------------------------------------------------------------------- + +DONE_FILE := $(HDK_COMMON_DIR)/verif/scripts/.done +DEPS_FILE := $(HDK_SHELL_DESIGN_DIR)/ip/ddr4_core/ddr4_core.xci +DEPS_FILE += $(HDK_COMMON_DIR)/verif/scripts/init.tcl +DEPS_FILE += $(HDK_COMMON_DIR)/verif/scripts/init.sh + +all: $(DONE_FILE) + +$(DONE_FILE): $(DEPS_FILE) + @ echo "INFO: Building in $(shell dirname $@)" + @ echo "INFO: This could take 5-10 minutes, please be patient!" + @ git clean -fXdq $(shell dirname $@) + @ cd $(shell dirname $@)\ + && ./init.sh $(MODEL_DIR)\ + && echo "INFO: DDR4 model build passed."\ + || (echo "ERROR: DDR4 model build failed." && exit 2) + @ touch $@ + diff --git a/hdk/common/verif/scripts/init.sh b/hdk/common/verif/scripts/init.sh index e72c3192..ce70d347 100755 --- a/hdk/common/verif/scripts/init.sh +++ b/hdk/common/verif/scripts/init.sh @@ -16,12 +16,12 @@ # limitations under the License. if [[ ":$HDK_COMMON_DIR" == ":" ]]; then - echo "error: HDK_COMMON_DIR not set. Source hdk_setup.sh first." + echo "ERROR: HDK_COMMON_DIR not set. Source hdk_setup.sh first." exit 2 fi if [[ ":$VIVADO_VER" == ":" ]]; then - echo "error: VIVADO_VER not set. Source hdk_setup.sh first." + echo "ERROR: VIVADO_VER not set. Source hdk_setup.sh first." exit 2 fi @@ -39,12 +39,12 @@ lockfile_filename=$models_dir/build.lock # Prevent multiple users from building in the same directory. # Set the number of retries to 0 so that we will just fail # and let the other process complete the build. -if [ -e /bin/lockfile ]; then - if ! lockfile -r 0 $lockfile_filename; then - echo "error: $lockfile_filename exists" - echo "error: Another process is already building the models." - exit 2 - fi +if [ -e $lockfile_filename ]; then + echo "ERROR: $lockfile_filename exists" + echo "ERROR: Another process is already building the models." + exit 2 +else + touch $lockfile_filename fi echo "$VIVADO_VER" > $models_dir/.vivado_version diff --git a/hdk/docs/AFI_Manifest.md b/hdk/docs/AFI_Manifest.md index 40588cb3..4386b68a 100644 --- a/hdk/docs/AFI_Manifest.md +++ b/hdk/docs/AFI_Manifest.md @@ -40,6 +40,7 @@ The manifest file is a text file formatted with key=value pairs. Some keys are m | vivado tool version | field value | |------------------- | -----------| +| 2019.2 | tool_version=v2019.2 | | 2019.1 | tool_version=v2019.1 | | 2018.3 | tool_version=v2018.3 | | 2018.2 | tool_version=v2018.2 | diff --git a/hdk/docs/AWS_Shell_Interface_Specification.md b/hdk/docs/AWS_Shell_Interface_Specification.md index 99be458a..8016dae2 100644 --- a/hdk/docs/AWS_Shell_Interface_Specification.md +++ b/hdk/docs/AWS_Shell_Interface_Specification.md @@ -222,9 +222,10 @@ These parameters are used to control which DDR controllers are impemented in the ... ``` -### DRAM Content Preservation between AFI Loads (Future) +### DRAM Content Preservation between AFI Loads -In future Shell versions a DRAM content preservation feature will be implemented. This feature allows the DDR state to be preserved when dynamically changing CL logic. The current Shell version will not guarantee preservation of DRAM contents if the CL logic is re-loaded. +Shell version 1.4 allows the DDR state to be preserved when dynamically changing CL logic. Any AFI generated with a v1.4 shell will enable DRAM content preservation by default. +Please refer to the [guide on how to use the DRAM data retention mode to preserve the content of DRAM across AFI loads](./data_retention.md) for more details on utilizing this feature. ## DMA @@ -649,12 +650,6 @@ It is ideal to place logic that interfaces to the shell in the same SLR as the S For the interfaces that are in both the MID/BOTTOM the recommendation is to use flops for pipelining, but don’t constrain to an SLR. Also it is recommended to not use the SDA interface because it spans two SLR's (use BAR1 or OCL instead). You can constrain logic to a particular SLR by creating PBLOCKs (one per SLR), and assigning logic to the PBLOCKs (refer to cl_dram_dma example [cl_pnr_user.xdc](../cl/examples/cl_dram_dma/build/constraints/cl_pnr_user.xdc)). Dataflow should be mapped so that SLR crossing is minimized (for example a pipeline should be organized such that successive stages are mostly in the same SLR). -Here’s an example post on the Xilinx forum which points to some documentation related to solving this: - - -There are some good timing closure tips in this methodology doc pointed to by the Xilinx forum post: - - ### Logic Levels You can report all paths that are greater than a certain number of logic levels. This can be used to iterate on timing in synthesis rather than waiting for place and route. For example at 250MHz a general rule of thumb is try to keep logic levels to around 10. The following commands report on all paths that have more than 10 logic levels: @@ -692,13 +687,10 @@ You have to be careful that pipeline registers do not infer a shift register com ### Vivado Analysis -Vivado has some nice analysis capabilities: +Vivado has the following analysis capabilities: * report_methodology (includes CDC report) * clock interaction report (see if paths between async clocks are erroneously being timed) * congestion heat map * power analysis * physical implementation analysis (placement, routing) * linked timing/schematic/physical views - - - diff --git a/hdk/docs/Virtual_JTAG_XVC.md b/hdk/docs/Virtual_JTAG_XVC.md index 3dd7315b..2551e5a8 100644 --- a/hdk/docs/Virtual_JTAG_XVC.md +++ b/hdk/docs/Virtual_JTAG_XVC.md @@ -142,6 +142,7 @@ To connect the debug Xilinx Hardware Manager to Virtual JTAG XVC server on the t `> connect_hw_server -url :3121` +If the above command fails, it is most likely because hw_server is not running on target F1 instance. Please follow see this [FAQ](#hw_serverRunOnF1Instance) on how to start hw_server @@ -153,7 +154,7 @@ To connect the debug Xilinx Hardware Manager to Virtual JTAG XVC server on the t **NOTES:** -- If the above command fails, its most likely that either the virtual jtag server is not running, the IP/Port are wrong, or a firewall/security-group rule is blocking the connection. See the [FAQ](#faq) section in the end of this document. +- If the above command fails, its most likely that either the virtual jtag server or hw_server is not running, the IP/Port are wrong, or a firewall/security-group rule is blocking the connection. See the [FAQ](#faq) section in the end of this document. Upon successful connection, Vivado's Hardware panel will be populated with a debug bridge instance. @@ -228,7 +229,6 @@ The following list describes the steps to successfully setup debug in a CL: # Frequently Asked Questions - **Q: Do I need to run Vivado or Hardware Manager on the target EC2 instance to debug?** @@ -238,6 +238,11 @@ No, you may run Vivado on a "remote" host as long as your instance/VPC has the r **Q: How do I configure Linux firewalls and EC2 network security groups to enable remote debug?** +If your OS has the `firewalld` service running, you can disable it for the time being for setting up remote debug by calling: +```sudo systemctl stop firewalld``` + +You will also have to allow incoming and outgoing traffic to TCP ports 3121 and 10201. +To open up incoming and outgoing traffic on those ports for your instance, please refer to the [EC2 Security Group documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html#sg-rules-other-instances) **Q: Can I have a secure connection (i.e. SSL/TLS) to the target FPGA-enable EC2 Instance running Virtual JTAG service?** @@ -249,20 +254,35 @@ You may use the ssh "port forwarding" option (-L) to forward connections from th No, you need the Vivado Lab Edition which does not require a license. - **Q: How do I stop the Virtual JTAG service on the target instance?** - +After starting the Virtual JTAG service, you can stop it by calling `Ctrl + C` from your keyboard. **Q: Can I debug multiple FPGAs on same target EC2 instance concurrently?** Yes, you must start the the `$ fpga-start-virtual-jtag` with a different Slot/Port for each FPGA. You can launch multiple Vivado sessions, and have each session connect to the corresponding TCP port associated with the FPGA. - + **Q: What are some of the best practices I should be aware when working with Virtual JTAG?** If you are running Vivado on a remote machine trying to connect to Virtual JTAG - we recommend running the hw_server on the F1 instance - to ensure optimal performance between Vivado and the Virtual JTAG server. - +On your target F1 Instance: +``` +[$] sudo su +[$]# hw_server & +****** Xilinx hw_server v2019.2 + **** Build date : Oct 24 2019 at 19:23:45 + ** Copyright 1986-2019 Xilinx, Inc. All Rights Reserved. + +INFO: hw_server application started +INFO: Use Ctrl-C to exit hw_server application + +INFO: To connect to this hw_server instance use url: TCP:ip-xxx-xx-xx-xxx.ec2.internal:3121 + +[$]# fpga-start-virtual-jtag -P 10201 -S 0 +Starting Virtual JTAG XVC Server for FPGA slot id 0, listening to TCP port 10201. +Press CTRL-C to stop the service. +``` **Q: Can other instances running on the same F1 server access the Virtual JTAG of my instance?** diff --git a/hdk/hdk_version.txt b/hdk/hdk_version.txt index 4d6f4aed..ed532a29 100644 --- a/hdk/hdk_version.txt +++ b/hdk/hdk_version.txt @@ -1 +1 @@ -HDK_VERSION=1.4.14 +HDK_VERSION=1.4.15 diff --git a/hdk_setup.sh b/hdk_setup.sh index 3171c42e..969bbf2c 100644 --- a/hdk_setup.sh +++ b/hdk_setup.sh @@ -139,6 +139,7 @@ do mkdir -p $hdk_shell_dir || { err_msg "Failed to create $hdk_shell_dir"; return 2; } fi # Use curl instead of AWS CLI so that credentials aren't required. + debug_msg "curl -s https://$hdk_resources_s3_bucket.s3.amazonaws.com/$s3_shell_dir/$shell_file.sha256 -o $hdk_file.sha256" curl -s https://$hdk_resources_s3_bucket.s3.amazonaws.com/$s3_shell_dir/$shell_file.sha256 -o $hdk_file.sha256 || { err_msg "Failed to download HDK shell's $shell_file version from $s3_shell_dir/$shell_file.sha256 -o $hdk_file.sha256"; return 2; } if grep -q ' /dev/null - # Run init.sh then clean-up - if ! $HDK_DIR/common/verif/scripts/init.sh $models_dir; then - err_msg "DDR4 model build failed." - err_msg " Build dir=$ddr4_build_dir" - popd &> /dev/null - return 2 - fi - info_msg "DDR4 model build passed." - popd &> /dev/null - rm -rf $ddr4_build_dir -else - debug_msg "DDR4 model files exist in "$ddr4_model_dir/". Skipping model creation step."; +if [[ $models_vivado_version != $VIVADO_VER ]] && [ ! -e $models_dir/build.lock ]; then + rm -rf $HDK_COMMON_DIR/verif/scripts/.done 2>&1 >/dev/null fi -if [[ ":$CL_DIR" == ':' ]]; then - info_msg "ATTENTION: Don't forget to set the CL_DIR variable for the directory of your Custom Logic."; +ddr4_build_dir=$HDK_COMMON_DIR/verif/scripts/tmp +if [ -d $ddr4_build_dir ] && [ ! -e $models_dir/build.lock ]; then rm -rf $ddr4_build_dir; fi +if ! make -s -C $HDK_DIR/common/verif/scripts MODEL_DIR=$models_dir; then + err_msg " build dir=$ddr4_build_dir" + return 2 +fi + +if [[ ":$cl_dir" == ':' ]]; then + info_msg "attention: don't forget to set the cl_dir variable for the directory of your custom logic."; else - info_msg "CL_DIR is $CL_DIR" - if [ ! -d $CL_DIR ]; then - err_msg "CL_DIR doesn't exist. Set CL_DIR to a valid directory." - unset CL_DIR + info_msg "cl_dir is $cl_dir" + if [ ! -d $cl_dir ]; then + err_msg "cl_dir doesn't exist. set cl_dir to a valid directory." + unset cl_dir fi fi diff --git a/sdk/tests/test_fpga_tools.py b/sdk/tests/test_fpga_tools.py index ff2629a4..668748e5 100644 --- a/sdk/tests/test_fpga_tools.py +++ b/sdk/tests/test_fpga_tools.py @@ -42,9 +42,9 @@ class TestFpgaTools(BaseSdkTools): ''' Pytest test class. - + NOTE: Cannot have an __init__ method. - + Test FPGA AFI Management tools described in ../userspace/fpga_mgmt_tools/README.md ''' @@ -110,24 +110,24 @@ def test_describe_local_image(self): # Test -M (Return FPGA image hardware metrics.) (rc, stdout, stderr) = self.run_cmd("sudo fpga-describe-local-image -M -S {}".format(slot), echo=True) - assert len(stdout) == 58 + assert len(stdout) == 59 assert len(stderr) == 1 assert stdout[0] == 'AFI {} none cleared 1 ok 0 {}'.format(slot, self.shell_version) assert stdout[1] == 'AFIDEVICE {} 0x1d0f 0x1042 {}'.format(slot, self.slot2device[slot]) assert stdout[2] == 'sdacl-slave-timeout=0' - assert stdout[50] == 'Clock Group C Frequency (Mhz)' - assert stdout[51] == '0 0 ' + assert stdout[51] == 'Clock Group C Frequency (Mhz)' + assert stdout[52] == '0 0 ' assert stdout[-2].startswith('Cached agfis:') # Test -C (Return FPGA image hardware metrics (clear on read).) (rc, stdout, stderr) = self.run_cmd("sudo fpga-describe-local-image -C -M -S {}".format(slot), echo=True) - assert len(stdout) == 58 + assert len(stdout) == 59 assert len(stderr) == 1 assert stdout[0] == 'AFI {} none cleared 1 ok 0 {}'.format(slot, self.shell_version) assert stdout[1] == 'AFIDEVICE {} 0x1d0f 0x1042 {}'.format(slot, self.slot2device[slot]) assert stdout[2] == 'sdacl-slave-timeout=0' - assert stdout[50] == 'Clock Group C Frequency (Mhz)' - assert stdout[51] == '0 0 ' + assert stdout[51] == 'Clock Group C Frequency (Mhz)' + assert stdout[52] == '0 0 ' @pytest.mark.flaky(reruns=2, reruns_delay=5) def test_load_local_image(self): diff --git a/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.c b/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.c index a68db443..720113b7 100644 --- a/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.c +++ b/sdk/userspace/fpga_mgmt_tools/src/fpga_local_cmd.c @@ -169,6 +169,10 @@ cli_show_image_info(struct fpga_mgmt_image_info *info) (fmc->int_status & FPGA_INT_STATUS_PCI_MASTER_AXI_PROTOCOL_ERROR) ? 1 : 0); + printf("dma-range-error=%u\n", + (fmc->int_status & FPGA_INT_STATUS_DMA_RANGE_ERROR) ? + 1 : 0); + printf("pcim-axi-protocol-4K-cross-error=%u\n", (fmc->pcim_axi_protocol_error_status & FPGA_PAP_4K_CROSS_ERROR) ? 1 : 0); diff --git a/sdk/userspace/include/hal/fpga_common.h b/sdk/userspace/include/hal/fpga_common.h index 7cd18971..c3d7d833 100644 --- a/sdk/userspace/include/hal/fpga_common.h +++ b/sdk/userspace/include/hal/fpga_common.h @@ -331,10 +331,12 @@ struct fpga_metrics_common { /** Common int_status */ enum { - /** SDACL slave timeout (CL did not respond to cycle from host) */ + /** SDACL slave timeout (CL did not respond to cycle from host) */ FPGA_INT_STATUS_SDACL_SLAVE_TIMEOUT = 1 << 0, /** Virtual JTAG timeout */ - FPGA_INT_STATUS_VIRTUAL_JTAG_SLAVE_TIMEOUT = 1 << 1, + FPGA_INT_STATUS_VIRTUAL_JTAG_SLAVE_TIMEOUT = 1 << 1, + /** A DMA engine made an out of range access */ + FPGA_INT_STATUS_DMA_RANGE_ERROR = 1 << 7, /** CL did not respond to DMA cycle from host */ FPGA_INT_STATUS_DMA_PCI_SLAVE_TIMEOUT = 1 << 17, /** PCIe master cycle from CL out of range */ @@ -349,6 +351,7 @@ enum { FPGA_INT_STATUS_ALL = FPGA_INT_STATUS_SDACL_SLAVE_TIMEOUT | FPGA_INT_STATUS_VIRTUAL_JTAG_SLAVE_TIMEOUT | + FPGA_INT_STATUS_DMA_RANGE_ERROR | FPGA_INT_STATUS_DMA_PCI_SLAVE_TIMEOUT | FPGA_INT_STATUS_PCI_MASTER_RANGE_ERROR | FPGA_INT_STATUS_PCI_MASTER_AXI_PROTOCOL_ERROR | diff --git a/shared/bin/set_common_functions.sh b/shared/bin/set_common_functions.sh index 5d31ee34..c7a05c91 100644 --- a/shared/bin/set_common_functions.sh +++ b/shared/bin/set_common_functions.sh @@ -41,6 +41,15 @@ function is_myvivado_set { fi } +function is_xilinx_path_set { + if env | grep -q ^XILINX_PATH + then + true + else + false + fi +} + # Function to check whether a command exists. exists() { if command -v $1 >/dev/null 2>&1 @@ -60,10 +69,16 @@ function get_base_vivado_version { local MYVIVADO_ENV_VAR_BACKUP=$MYVIVADO unset MYVIVADO - local __vivado_version=$(get_vivado_version) + local __vivado_version=$(get_vivado_v + ersion) export MYVIVADO=$MYVIVADO_ENV_VAR_BACKUP + elif is_xilinx_path_set + then + local XILINX_PATH_ENV_VAR_BACKUP=$XILINX_PATH + unset XILINX_PATH + local __vivado_version=$(get_vivado_version) + export XILINX_PATH=$XILINX_PATH_ENV_VAR_BACKUP else - local __vivado_version=$(get_vivado_version) fi @@ -102,6 +117,18 @@ function get_vivado_version { function setup_patches { patch_AR71715 + patch_AR73068 +} + +function is_patch_applied { + local patch_name="$1" + local long_vivado_version=$(get_vivado_version) + + if [[ "$long_vivado_version" =~ .*"$patch_name".* ]]; then + true + else + false + fi } function patch_AR71715 { @@ -118,7 +145,7 @@ function patch_AR71715 { local base_vivado_version=$(get_base_vivado_version) is_patch_valid=false - info_msg "Base vivado version is $base_vivado_version ; Checking if patch AR71715 needs to be installed" + info_msg "Base vivado version is $base_vivado_version. Checking if patch AR71715 needs to be installed" for vivado_version in "${valid_vivado_versions[@]}" do if [ ":$vivado_version" == ":$base_vivado_version" ]; then @@ -151,6 +178,101 @@ function patch_AR71715 { fi } +function install_patch { + local patch_name="$1" + local patch_bucket="$2" + local patch_object="$3" + local patch_dir_name="${patch_object%.*}" + + if is_patch_applied $patch_name + then + info_msg "$patch_name is already applied. Skipping." + else + info_msg "Applying $patch_name" + info_msg "in bucket $patch_bucket" + info_msg "object $patch_object" + + # Checking if the patches directory exists and making it if it doesn't + [ -d $script_dir/patches ] || mkdir -p $script_dir/patches + + info_msg "Downloading the $patch_name from $patch_bucket/$patch_object." + debug_msg "curl -s $patch_bucket/$patch_object -o $script_dir/patches/$patch_object" + + curl -s $patch_bucket/$patch_object -o $script_dir/patches/$patch_object || { err_msg "Failed to download Patch $object from $patch_bucket/$patch_object"; return 2; } + + info_msg "Extracting the $patch_name to $script_dir/patches/$patch_dir_name." + + unzip -q -o $script_dir/patches/$patch_object -d $script_dir/patches/$patch_dir_name || { err_msg "Failed to extract $script_dir/patches/$patch_object to $script_dir/patches/$patch_dir_name"; return 2; } + + # XILINX_PATH should not have AR73068 at this point. + info_msg "Appending XILINX_PATH with $script_dir/patches/$patch_dir_name/vivado" + + export XILINX_PATH=$XILINX_PATH:$script_dir/patches/$patch_dir_name/vivado + fi +} + +function patch_AR73068_2019_2 { + info_msg "Patching Vivado 2019.2 with Xilinx Patch AR73068" + + local patch_bucket="https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/AR73068" + local patch_object="AR73068_Vivado_2019_2_preliminary_rev1.zip" + + install_patch "AR73068" "$patch_bucket" "$patch_object" +} + +function patch_AR73068_2019_1 { + info_msg "Patching Vivado 2019.1 with Xilinx Patch AR73068" + + local patch_bucket="https://aws-fpga-developer-ami.s3.amazonaws.com/1.7.0/Patches/AR73068" + local patch_object="AR73068_Vivado_2019_1_preliminary_rev1.zip" + + install_patch "AR73068" "$patch_bucket" "$patch_object" +} + +function patch_AR73068_2018_3 { + info_msg "Patching Vivado 2018.3 with Xilinx Patch AR73068" + + local patch_bucket="https://aws-fpga-developer-ami.s3.amazonaws.com/1.6.0/Patches/AR73068" + local patch_object="AR73068_Vivado_2018_3_preliminary_rev1.zip" + + install_patch "AR73068" "$patch_bucket" "$patch_object" +} + +function patch_AR73068_2018_2 { + info_msg "Patching Vivado 2018.2 with Xilinx Patch AR73068" + + local patch_bucket="https://aws-fpga-developer-ami.s3.amazonaws.com/1.5.0/Patches/AR73068" + local patch_object="AR73068_Vivado_2018_2_preliminary_rev1.zip" + + install_patch "AR73068" "$patch_bucket" "$patch_object" +} + +function patch_AR73068_2017_4 { + info_msg "Patching Vivado 2017.4 with Xilinx Patch AR73068" + + local patch_bucket="https://aws-fpga-developer-ami.s3.amazonaws.com/1.4.0/Patches/AR73068" + local patch_object="AR73068_Vivado_2017_4_preliminary_rev2.zip" + + install_patch "AR73068" "$patch_bucket" "$patch_object" +} + +function patch_AR73068 { + local base_vivado_version=$(get_base_vivado_version) + + if [[ "${base_vivado_version}" =~ "Vivado v2019.2" ]]; then + patch_AR73068_2019_2 + elif [[ "${base_vivado_version}" =~ "Vivado v2019.1" ]]; then + patch_AR73068_2019_1 + elif [[ "${base_vivado_version}" =~ "Vivado v2018.3" ]]; then + patch_AR73068_2018_3 + elif [[ "${base_vivado_version}" =~ "Vivado v2018.2" ]]; then + patch_AR73068_2018_2 + elif [[ "${base_vivado_version}" =~ "Vivado v2017.4" ]]; then + patch_AR73068_2017_4 + else + warn_msg "Unknown Vivado version: ${base_vivado_version}. Not applying Xilinx Patch AR73068" + fi +} function allow_non_root { [ ! -z ${AWS_FPGA_ALLOW_NON_ROOT} ] diff --git a/shared/tests/bin/check_md_links.py b/shared/tests/bin/check_md_links.py index b3addcf4..8ec80eb9 100755 --- a/shared/tests/bin/check_md_links.py +++ b/shared/tests/bin/check_md_links.py @@ -134,7 +134,7 @@ def contains_link(path): if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--exclude', action='store', nargs='*', default=[], help="Paths to ignore") - parser.add_argument('--ignore-url', action='store', nargs='*', default=[], help="URLs to ignore. Will ignore all URLs starting with this prefix.") + parser.add_argument('--ignore-url', nargs='*', default=[], help="URLs to ignore. Will ignore all URLs starting with this prefix.") parser.add_argument('--debug', action='store_true', default=False, help="Enable debug messages") args = parser.parse_args() if args.debug: diff --git a/shared/tests/test_md_links.py b/shared/tests/test_md_links.py index 1d03c111..a4c684fa 100755 --- a/shared/tests/test_md_links.py +++ b/shared/tests/test_md_links.py @@ -59,6 +59,6 @@ def test_md_links(self): cmd = self.test_dir + "/bin/check_md_links.py" cmd += " --exclude SDAccel/examples/xilinx" # This is a valid link but sometimes it 404s - cmd += " --ignore-url https://docs.pytest.org/en/latest/" + cmd += " --ignore-url https://docs.pytest.org/en/latest/ https://forums.xilinx.com/t5/SDAccel/bd-p/SDx" (rc, stdout, stderr) = self.run_cmd(cmd, echo=True) assert rc == 0 diff --git a/supported_vivado_versions.txt b/supported_vivado_versions.txt index f04c4093..38d9300d 100644 --- a/supported_vivado_versions.txt +++ b/supported_vivado_versions.txt @@ -9,5 +9,9 @@ Vivado v2018.3 (64-bit) Vivado v2018.3_AR72667 (64-bit) Vivado v2019.1.op (64-bit) Vivado v2019.1 (64-bit) +Vivado v2019.1_AR73068 (64-bit) +Vivado v2019.1_AR73068_op (64-bit) Vivado v2019.1_AR72668 (64-bit) Vivado v2019.2 (64-bit) +Vivado v2019.2_AR73068_op (64-bit) +Vivado v2019.2_AR73068 (64-bit) diff --git a/vitis_setup.sh b/vitis_setup.sh index a979b17e..8a4dc548 100644 --- a/vitis_setup.sh +++ b/vitis_setup.sh @@ -165,8 +165,8 @@ fi info_msg " XILINX_VITIS is set to $XILINX_VITIS" # Install patches as required. -info_msg " Checking & installing required patches" -setup_patches +#info_msg " Checking & installing required patches" +#setup_patches # Update Xilinx Vitis Examples from GitHub From 7a6093a51c739630d73faee7dff117775ada1c9d Mon Sep 17 00:00:00 2001 From: Deep Patel Date: Thu, 10 Sep 2020 09:15:01 -0500 Subject: [PATCH 21/31] Upgrade DDR IP and regenerate outputs to fix AR73068 issue (#500) * Add upgrade ip changes to the init.tcl file * Updated the cl_dram_dma public AFI --- hdk/cl/examples/cl_dram_dma/README.md | 4 ++-- hdk/common/verif/scripts/init.tcl | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/hdk/cl/examples/cl_dram_dma/README.md b/hdk/cl/examples/cl_dram_dma/README.md index 00d1b33e..1f5713a4 100644 --- a/hdk/cl/examples/cl_dram_dma/README.md +++ b/hdk/cl/examples/cl_dram_dma/README.md @@ -188,6 +188,6 @@ Alternatively, you can directly use a pre-generated AFI for this CL. | PCI Vendor ID | 0x1D0F (Amazon) | | PCI Subsystem ID | 0x1D51 | | PCI Subsystem Vendor ID | 0xFEDC | -| Pre-generated AFI ID | afi-08a7d9c0480bea3bd | -| Pre-generated AGFI ID | agfi-02f141212beac0cfb | +| Pre-generated AFI ID | afi-063e6afe717a22158 | +| Pre-generated AGFI ID | agfi-0b5c35827af676702 | diff --git a/hdk/common/verif/scripts/init.tcl b/hdk/common/verif/scripts/init.tcl index 682767b8..d04e4e9e 100644 --- a/hdk/common/verif/scripts/init.tcl +++ b/hdk/common/verif/scripts/init.tcl @@ -26,10 +26,11 @@ export_ip_user_files -of_objects [get_files $::env(HDK_SHELL_DIR)/design/ip/dd remove_files [get_files $::env(HDK_SHELL_DIR)/design/ip/ddr4_core/ddr4_core.xci] -quiet import_files -norecurse $::env(HDK_SHELL_DIR)/design/ip/ddr4_core/ddr4_core.xci -quiet -upgrade_ip [get_ips ddr4_core] -quiet +upgrade_ip -vlnv xilinx.com:ip:ddr4:2.2 [get_ips ddr4_core] -log ip_upgrade.log +generate_target all [get_files $::env(HDK_SHELL_DIR)/design/ip/ddr4_core/ddr4_core.xci] +report_ip_status -file ddr4_core_ip_report.txt open_example_project -force -dir ./tmp/tmp_ddr_ex [get_ips ddr4_core] - exit From 49c92afc79d48a7c8fa3fa3f2ad0e14133e1f9bb Mon Sep 17 00:00:00 2001 From: Deep Patel Date: Thu, 17 Sep 2020 16:47:16 -0500 Subject: [PATCH 22/31] Release v1.4.16 (#502) * FPGA developer kit now supports Xilinx Vivado/Vitis 2020.1 * Updated Vitis examples to include usage of Vitis Libraries. * Added documentation and examples to show Xilinx Alveo design migration to F1. * Removed support for Xilinx toolsets 2017.4, 2018.2 and 2018.3. --- .gitmodules | 15 +- ERRATA.md | 2 + FAQs.md | 29 +- Jenkinsfile | 62 +- Jenkinsfile_int_sims | 6 + README.md | 312 +- RELEASE_NOTES.md | 82 +- SDAccel/README.md | 4 +- SDAccel/docs/README_GUI.md | 6 +- SDAccel/examples/xilinx_2017.4 | 1 - SDAccel/examples/xilinx_2018.2 | 1 - SDAccel/examples/xilinx_2018.3 | 1 - Vitis/README.md | 44 +- Vitis/docs/Alveo_to_AWS_F1_Migration.md | 242 + .../example/README.md | 149 + .../example/f1/Makefile | 48 + .../example/f1/options.cfg | 6 + .../example/src/host.cpp | 183 + .../example/src/host.hpp | 85 + .../example/src/vadd.cpp | 111 + .../example/u200/Makefile | 48 + .../example/u200/options.cfg | 6 + .../Alveo_to_AWS_F1_Migration/img/image01.png | Bin 0 -> 40763 bytes .../Alveo_to_AWS_F1_Migration/img/image02.png | Bin 0 -> 19341 bytes Vitis/docs/Create_Runtime_AMI.md | 3 +- Vitis/docs/Debug_Vitis_Kernel.md | 3 +- Vitis/docs/XRT_installation_instructions.md | 3 +- Vitis/examples/xilinx_2020.1 | 1 + Vitis/kernel_version.txt | 3 +- Vitis/vitis_xrt_version.txt | 5 +- docs/examples/example_list.md | 28 + .../on_premise_licensing_help.md | 21 +- hdk/README.md | 59 +- hdk/cl/examples/cl_hello_world/README.md | 24 +- hdk/cl/examples/cl_hello_world_vhdl/README.md | 43 +- hdk/common/verif/scripts/.gitignore | 2 +- .../verif/tb/scripts/Makefile.common.inc | 68 +- hdk/docs/AFI_Manifest.md | 1 + .../AWS_Shell_V1.4_Migration_Guidelines.md | 2 +- hdk/docs/HOWTO_detect_shell_timeout.md | 16 +- hdk/docs/IPI_GUI_Vivado_Setup.md | 2 +- hdk/docs/RTL_Simulating_CL_Designs.md | 2 +- hdk/docs/Virtual_JTAG_XVC.md | 20 +- hdk/docs/ppts/simulation.pptx | Bin 36174 -> 0 bytes hdk/docs/ppts/simulation/Slide1.PNG | Bin 2294 -> 0 bytes hdk/docs/ppts/simulation/Slide2.PNG | Bin 51853 -> 0 bytes hdk/docs/ppts/simulation/Slide3.PNG | Bin 23966 -> 0 bytes hdk/hdk_version.txt | 2 +- hdk/tests/test_gen_dcp.py | 3 + hdk_setup.sh | 12 +- sdk/linux_kernel_drivers/xocl/10-xocl.rules | 1 - sdk/linux_kernel_drivers/xocl/LICENSE | 339 -- sdk/linux_kernel_drivers/xocl/Makefile | 70 - sdk/linux_kernel_drivers/xocl/cdev_sgdma.h | 79 - sdk/linux_kernel_drivers/xocl/ert.h | 310 -- sdk/linux_kernel_drivers/xocl/libxdma.c | 4375 ----------------- sdk/linux_kernel_drivers/xocl/libxdma.h | 612 --- sdk/linux_kernel_drivers/xocl/libxdma_api.h | 135 - sdk/linux_kernel_drivers/xocl/xclfeatures.h | 146 - sdk/linux_kernel_drivers/xocl/xocl_bo.c | 1041 ---- sdk/linux_kernel_drivers/xocl/xocl_ctx.c | 42 - sdk/linux_kernel_drivers/xocl/xocl_drv.c | 832 ---- sdk/linux_kernel_drivers/xocl/xocl_drv.h | 301 -- sdk/linux_kernel_drivers/xocl/xocl_exec.c | 1426 ------ sdk/linux_kernel_drivers/xocl/xocl_exec.h | 128 - sdk/linux_kernel_drivers/xocl/xocl_ioctl.c | 433 -- sdk/linux_kernel_drivers/xocl/xocl_ioctl.h | 375 -- sdk/linux_kernel_drivers/xocl/xocl_sysfs.c | 135 - sdk/linux_kernel_drivers/xocl/xocl_test.c | 76 - sdk/linux_kernel_drivers/xocl/xocl_xdma.c | 91 - sdk/linux_kernel_drivers/xocl/xocl_xdma.h | 30 - sdk/linux_kernel_drivers/xocl/xocl_xvc.c | 330 -- sdk/linux_kernel_drivers/xocl/xocl_xvc.h | 44 - .../xocl/xvc_pcie_ioctl.h | 38 - shared/bin/set_common_env_vars.sh | 3 + shared/bin/set_common_functions.sh | 2 +- .../aws_fpga_test_utils/AwsFpgaTestBase.py | 6 +- shared/lib/check_src_headers.py | 3 +- supported_vivado_versions.txt | 10 +- vitis_runtime_setup.sh | 6 +- vitis_setup.sh | 4 +- 81 files changed, 1323 insertions(+), 11866 deletions(-) delete mode 160000 SDAccel/examples/xilinx_2017.4 delete mode 160000 SDAccel/examples/xilinx_2018.2 delete mode 160000 SDAccel/examples/xilinx_2018.3 create mode 100644 Vitis/docs/Alveo_to_AWS_F1_Migration.md create mode 100644 Vitis/docs/Alveo_to_AWS_F1_Migration/example/README.md create mode 100644 Vitis/docs/Alveo_to_AWS_F1_Migration/example/f1/Makefile create mode 100644 Vitis/docs/Alveo_to_AWS_F1_Migration/example/f1/options.cfg create mode 100644 Vitis/docs/Alveo_to_AWS_F1_Migration/example/src/host.cpp create mode 100644 Vitis/docs/Alveo_to_AWS_F1_Migration/example/src/host.hpp create mode 100644 Vitis/docs/Alveo_to_AWS_F1_Migration/example/src/vadd.cpp create mode 100644 Vitis/docs/Alveo_to_AWS_F1_Migration/example/u200/Makefile create mode 100644 Vitis/docs/Alveo_to_AWS_F1_Migration/example/u200/options.cfg create mode 100644 Vitis/docs/Alveo_to_AWS_F1_Migration/img/image01.png create mode 100644 Vitis/docs/Alveo_to_AWS_F1_Migration/img/image02.png create mode 160000 Vitis/examples/xilinx_2020.1 create mode 100644 docs/examples/example_list.md rename {hdk/docs => docs}/on_premise_licensing_help.md (80%) delete mode 100644 hdk/docs/ppts/simulation.pptx delete mode 100644 hdk/docs/ppts/simulation/Slide1.PNG delete mode 100644 hdk/docs/ppts/simulation/Slide2.PNG delete mode 100644 hdk/docs/ppts/simulation/Slide3.PNG delete mode 100644 sdk/linux_kernel_drivers/xocl/10-xocl.rules delete mode 100644 sdk/linux_kernel_drivers/xocl/LICENSE delete mode 100644 sdk/linux_kernel_drivers/xocl/Makefile delete mode 100644 sdk/linux_kernel_drivers/xocl/cdev_sgdma.h delete mode 100644 sdk/linux_kernel_drivers/xocl/ert.h delete mode 100644 sdk/linux_kernel_drivers/xocl/libxdma.c delete mode 100644 sdk/linux_kernel_drivers/xocl/libxdma.h delete mode 100644 sdk/linux_kernel_drivers/xocl/libxdma_api.h delete mode 100644 sdk/linux_kernel_drivers/xocl/xclfeatures.h delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_bo.c delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_ctx.c delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_drv.c delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_drv.h delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_exec.c delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_exec.h delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_ioctl.c delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_ioctl.h delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_sysfs.c delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_test.c delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_xdma.c delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_xdma.h delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_xvc.c delete mode 100644 sdk/linux_kernel_drivers/xocl/xocl_xvc.h delete mode 100644 sdk/linux_kernel_drivers/xocl/xvc_pcie_ioctl.h diff --git a/.gitmodules b/.gitmodules index 6d9dd010..7133941d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,15 +1,3 @@ -[submodule "SDAccel/examples/xilinx_2017.4"] - path = SDAccel/examples/xilinx_2017.4 - url = https://github.com/Xilinx/SDAccel_Examples.git - branch = aws_2017.4 -[submodule "SDAccel/examples/xilinx_2018.2"] - path = SDAccel/examples/xilinx_2018.2 - url = https://github.com/Xilinx/SDAccel_Examples.git - branch = 2018.2_xdf -[submodule "SDAccel/examples/xilinx_2018.3"] - path = SDAccel/examples/xilinx_2018.3 - url = https://github.com/Xilinx/SDAccel_Examples.git - branch = master [submodule "SDAccel/examples/xilinx_2019.1"] path = SDAccel/examples/xilinx_2019.1 url = https://github.com/Xilinx/SDAccel_Examples.git @@ -17,3 +5,6 @@ path = Vitis/examples/xilinx_2019.2 branch = master url = https://github.com/Xilinx/Vitis_Accel_Examples +[submodule "Vitis/examples/xilinx_2020.1"] + path = Vitis/examples/xilinx_2020.1 + url = https://github.com/Xilinx/Vitis_Accel_Examples diff --git a/ERRATA.md b/ERRATA.md index 7f99a344..5fbf6d82 100644 --- a/ERRATA.md +++ b/ERRATA.md @@ -20,6 +20,8 @@ If the check fails, the design is susceptible to the issue and will need to be r For designs under development, we recommend applying the patch to your on-premises tools or update to developer kit v1.4.15. For additional details, please refer to the [Xilinx Answer Record #73068](https://www.xilinx.com/support/answers/73068.html) +We recommend using [Developer Kit Release v1.4.15a](https://github.com/aws/aws-fpga/releases/tag/v1.4.15a) or newer to allow for patching and fixing the DDR4 IP timing exception by re-generating the IP. + ### 2019.1 * Vivado `compile_simlib` command fails to generate the following verilog IP libraries for the following simulators. * Please refer to the Xilinx Answer record for details. diff --git a/FAQs.md b/FAQs.md index a4e2a3cd..18707026 100644 --- a/FAQs.md +++ b/FAQs.md @@ -29,7 +29,7 @@ AWS designed its FPGA instances to provide a developer experience with ease of u - AWS provides cloud based debug tools: [Virtual JTAG](./hdk/docs/Virtual_JTAG_XVC.md) which is equivalent to debug using JTAG with on-premises development, and Virtual LED together with Virtual DIP Switch emulation the LED and DIP switches in typical development board. -- For developers who want to develop on-premises, Xilinx provides an [on-premises license](./hdk/docs/on_premise_licensing_help.md ) that matches all the needed components needed to be licensed for F1 development on premises. +- For developers who want to develop on-premises, Xilinx provides an [on-premises license](docs/on_premise_licensing_help.md ) that matches all the needed components needed to be licensed for F1 development on premises. - The developers' output is a Design Checkpoint (DCP) and not an FPGA bitstream: The FPGA bitstream is actually generated by AWS after the developer submits the DCP. @@ -185,7 +185,7 @@ AWS prefers not to limit developers to a specific template in terms of how we ad If you decide to use the [FPGA Developer AMI on AWS Marketplace](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ), Xilinx licenses for simulation, encryption, SDAccel and Design Checkpoint generation are included at no additional cost. -If you want to run using other methods or on a local machine, you will need to obtain any necessary licenses, specifically you will need to have setup the appropriate Xilinx Vivado license. For more details, please refer to [On-premises licensing help](./hdk/docs/on_premise_licensing_help.md) +If you want to run using other methods or on a local machine, you will need to obtain any necessary licenses, specifically you will need to have setup the appropriate Xilinx Vivado license. For more details, please refer to [On-premises licensing help](docs/on_premise_licensing_help.md) **Q: Does AWS provide physical FPGA boards for on-premises development?** @@ -492,7 +492,7 @@ Parent process (pid 8160) has died. This helper process will now exit *For On Premise runs:* -You would need a valid [on premise license](./hdk/docs/on_premise_licensing_help.md) provided by Xilinx. +You would need a valid [on premise license](docs/on_premise_licensing_help.md) provided by Xilinx. *For runs using the FPGA Developer AMI:* Please contact us through [AWS FPGA Developers forum](https://forums.aws.amazon.com/forum.jspa?forumID=243) @@ -504,4 +504,25 @@ Please modify RDP options to choose any color depth less than 32 bit and try re- **Q: Why did my AFI creation fail with `***ERROR***: DCP has DNA_PORT instantiation, ingestion failed, exiting`?** -AWS does not support creating AFI's with the Device DNA instantiated within your design. Please create your design without instantiating the DNA_PORT primitive to be able to create your AFI. \ No newline at end of file +AWS does not support creating AFI's with the Device DNA instantiated within your design. Please create your design without instantiating the DNA_PORT primitive to be able to create your AFI. + +**Q: How do I know which HDK version I have on my instance/machine? ** + +Look for the ./hdk/hdk_version.txt file. + +**Q: How do I know what my Shell version is? ** + +The Shell version of an FPGA slot is available through the FPGA Image Management tools after an AFI has been loaded. +See the description of `fpga-describe-local-image` for more details on retrieving the shell version from a slot. +Prior to loading an AFI, the state of the FPGA (including shell version) is undefined and non-deterministic. + +**Q: How do I know what version of FPGA Image management tools are running on my instance? ** + +The FPGA Image management tools version is reported with any command executed from these tools. +See the description of `fpga-describe-local-image` for more details. + +**Q: How do I update my existing design with a new release?** + +1. Start by pulling changes from a new [aws-fpga github release](https://github.com/aws/aws-fpga) +1. If the [AWS Shell Interface Specification](./hdk/docs/AWS_Shell_Interface_Specification.md) has changed, update your CL design to conform to the new specification. +3. Follow the process for AFI generation diff --git a/Jenkinsfile b/Jenkinsfile index e6006785..b1a1fd95 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -126,45 +126,23 @@ task_label = [ ] // Put the latest version last -def xilinx_versions = [ '2019.1', '2019.2' ] +def xilinx_versions = [ '2019.1', '2019.2', '2020.1' ] -def vitis_versions = ['2019.2'] +def vitis_versions = ['2019.2', '2020.1'] // We want the default to be the latest. def default_xilinx_version = xilinx_versions.last() def dsa_map = [ - '2017.4' : [ 'DYNAMIC_5_0' : 'dyn'], - '2018.2' : [ 'DYNAMIC_5_0' : 'dyn'], - '2018.3' : [ 'DYNAMIC_5_0' : 'dyn'], '2019.1' : [ 'DYNAMIC_5_0' : 'dyn'], ] def xsa_map = [ - '2019.2' : [ 'DYNAMIC':'dyn'] + '2019.2' : [ 'DYNAMIC':'dyn'], + '2020.1' : [ 'DYNAMIC':'dyn'] ] def sdaccel_example_default_map = [ - '2017.4' : [ - 'Hello_World_1ddr': 'SDAccel/examples/xilinx/getting_started/host/helloworld_ocl', - 'Gmem_2Banks_2ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/gmem_2banks_ocl', - 'kernel_3ddr_bandwidth_4ddr': 'SDAccel/examples/aws/kernel_3ddr_bandwidth', - 'Kernel_Global_Bw_4ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/kernel_global_bandwidth', - 'RTL_Vadd_Debug': 'SDAccel/examples/xilinx/getting_started/rtl_kernel/rtl_vadd_hw_debug' - ], - '2018.2' : [ - 'Hello_World_1ddr': 'SDAccel/examples/xilinx/getting_started/host/helloworld_ocl', - 'Gmem_2Banks_2ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/gmem_2banks_ocl', - 'kernel_3ddr_bandwidth_4ddr': 'SDAccel/examples/aws/kernel_3ddr_bandwidth', - 'Kernel_Global_Bw_4ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/kernel_global_bandwidth', - 'RTL_Vadd_Debug': 'SDAccel/examples/xilinx/getting_started/rtl_kernel/rtl_vadd_hw_debug' - ], - '2018.3' : [ - 'Hello_World_1ddr': 'SDAccel/examples/xilinx/getting_started/host/helloworld_ocl', - 'Gmem_2Banks_2ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/gmem_2banks_ocl', - 'Kernel_Global_Bw_4ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/kernel_global_bandwidth', - 'RTL_Vadd_Debug': 'SDAccel/examples/xilinx/getting_started/rtl_kernel/rtl_vadd_hw_debug' - ], '2019.1' : [ 'Hello_World_1ddr': 'SDAccel/examples/xilinx/getting_started/hello_world/helloworld_ocl', 'Gmem_2Banks_2ddr': 'SDAccel/examples/xilinx/getting_started/kernel_to_gmem/gmem_2banks_ocl_5.0_shell', @@ -179,28 +157,18 @@ def vitis_example_default_map = [ 'Gmem_2Banks_2ddr': 'Vitis/examples/xilinx/ocl_kernels/cl_gmem_2banks', 'Kernel_Global_Bw_4ddr': 'Vitis/examples/xilinx/cpp_kernels/kernel_global_bandwidth', 'RTL_Vadd_Debug': 'Vitis/examples/xilinx/rtl_kernels/rtl_vadd_hw_debug' + ], + '2020.1' : [ + 'Hello_World_1ddr': 'Vitis/examples/xilinx/ocl_kernels/cl_helloworld', + 'Gmem_2Banks_2ddr': 'Vitis/examples/xilinx/ocl_kernels/cl_gmem_2banks', + 'Kernel_Global_Bw_4ddr': 'Vitis/examples/xilinx/cpp_kernels/kernel_global_bandwidth', + 'RTL_Vadd_Debug': 'Vitis/examples/xilinx/rtl_kernels/rtl_vadd_hw_debug', + 'gemm_blas': 'Vitis/examples/xilinx/library_examples/gemm', + 'gzip_app': 'Vitis/examples/xilinx/library_examples/gzip_app' ] ] def simulator_tool_default_map = [ - '2017.4' : [ - 'vivado': 'xilinx/SDx/2017.4_04112018', - 'vcs': 'synopsys/vcs-mx/M-2017.03-SP2-11', - 'questa': 'questa/10.6b', - 'ies': 'incisive/15.20.063' - ], - '2018.2' : [ - 'vivado': 'xilinx/SDx/2018.2_06142018', - 'vcs': 'synopsys/vcs-mx/N-2017.12-SP2', - 'questa': 'questa/10.6c_1', - 'ies': 'incisive/15.20.063' - ], - '2018.3' : [ - 'vivado': 'xilinx/SDx/2018.3_1207', - 'vcs': 'synopsys/vcs-mx/N-2017.12-SP2', - 'questa': 'questa/10.6c_1', - 'ies': 'incisive/15.20.063' - ], '2019.1' : [ 'vivado': 'xilinx/SDx/2019.1.op2552052', 'vcs': 'synopsys/vcs-mx/N-2017.12-SP2', @@ -212,6 +180,12 @@ def simulator_tool_default_map = [ 'vcs': 'synopsys/vcs-mx/O-2018.09-SP2-1', 'questa': 'questa/2019.2', 'ies': 'incisive/15.20.063' + ], + '2020.1' : [ + 'vivado': 'xilinx/Vivado/2020.1', + 'vcs': 'synopsys/vcs-mx/P-2019.06-SP1-1', + 'questa': 'questa/2019.4', + 'ies': 'incisive/15.20.079' ] ] diff --git a/Jenkinsfile_int_sims b/Jenkinsfile_int_sims index 927e0e32..7c8349c2 100644 --- a/Jenkinsfile_int_sims +++ b/Jenkinsfile_int_sims @@ -47,6 +47,12 @@ def simulator_tool_default_map = [ 'vcs': 'synopsys/vcs-mx/O-2018.09-SP2-1', 'questa': 'questa/2019.2', 'ies': 'incisive/15.20.063' + ], + '2020.1' : [ + 'vivado': 'xilinx/Vivado/2020.1', + 'vcs': 'synopsys/vcs-mx/P-2019.06-SP1-1', + 'questa': 'questa/2019.4', + 'ies': 'incisive/15.20.079' ] ] diff --git a/README.md b/README.md index 10d63b23..8dbd1764 100644 --- a/README.md +++ b/README.md @@ -1,195 +1,197 @@ - - # Table of Contents -1. [Overview of AWS EC2 FPGA Development Kit](#overviewdevkit) - - [Development environments](#overviewdevenv) - - [Runtime environments](#overviewrunenv) - - [Development tools](#overviewdevtools) - - [Example applications](#overviewexapps) -2. [Getting Started](#gettingstarted) -3. [FPGA Developer AMI available on AWS Marketplace](#devAmi) -4. [FPGA Hardware Development Kit (HDK)](#fpgahdk) -5. [FPGA Software Development Kit (SDK)](#fpgasdk) -6. [OpenCL Development Environment with Amazon EC2 F1 FPGA Instances to accelerate your C/C++ applications](#sdaccel) -7. [Developer Support](#devSupport) -8. [Recommended Documentation](#doccontents) - - +1. [Overview of AWS EC2 FPGA Development Kit](#overview-of-aws-ec2-fpga-development-kit) + - [Development Flow](#development-flow) + - [Development environments](#development-environments) + - [FPGA Developer AMI](#fpga-developer-ami) + - [FPGA Hardware Development Kit (HDK)](#hardware-development-kit-hdk) + - [FPGA Software Development Kit (SDK)](#runtime-tools-sdk) + - [Software Defined Development Environment](#software-defined-development-environment) +1. [Amazon EC2 F1 platform features](#amazon-ec2-f1-platform-features) +1. [Getting Started](#getting-started) + - [Getting Familiar with AWS](#getting-familiar-with-aws) + - [First time setup](#setting-up-development-environment-for-the-first-time) + - [Quickstarts](#quickstarts) + - [How To's](#how-tos) +1. [Documentation Overview](#documentation-overview) +1. [Developer Support](#developer-support) + # Overview of AWS EC2 FPGA Development Kit -AWS EC2 FPGA Development Kit is a set of free development and runtime tools that provide everything needed to develop, simulate, debug, compile and run hardware accelerated applications on [Amazon EC2 F1 instances](https://aws.amazon.com/ec2/instance-types/f1/), EC2 F1 instances are high-performance compute instances with field programmable gate arrays (FPGAs) that enable the development and deployment of custom hardware accelerators on AWS cloud. +AWS EC2 FPGA Development Kit is a set of development and runtime tools to develop, simulate, debug, compile and run hardware accelerated applications on [Amazon EC2 F1 instances](https://aws.amazon.com/ec2/instance-types/f1/). +It is distributed between this github repository and [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) provided by AWS with no cost of development tools. + +⚠️ NOTE: The developer kit is supported for Linux operating systems only. + +## Development Flow +After creating an FPGA design (also called CL - Custom logic), developers can create an Amazon FPGA Image (AFI) and easily deploy it to an F1 instance. AFIs are reusable, shareable and can be deployed in a scalable and secure way. -AWS EC2 FPGA Development Kit content is distributed between this github repository and [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) provided by AWS, developers are able to develop, simulate and debug an FPGA design on compute [EC2 instance](https://aws.amazon.com/ec2/) with no cost of development or runtime tools. Once the FPGA design (also called CL - Custom logic) is complete, developers create the Amazon FPGA Image (AFI), and easily deploy it to the F1 instance. AFIs are reusable, shareable and can be deployed in a scalable and secure way. ![Alt text](hdk/docs/images/f1-Instance-How-it-Works-flowchart.jpg) - -## Overview of Development Environments - -| Development Environment | Description | Accelerator Language | Development Tool | Debug Options| Typical Developer / FPGA Experience | -| --------|---------|---------|-------|-------|-------| -| Software Defined Accelerator Development - [Vitis](Vitis/README.md)/[SDAccel](SDAccel/README.md) | Development experience leverages an optimized compiler to allow easy new accelerator development or migration of existing C/C++/openCL, Verilog/VHDL to AWS FPGA instances | C/C++/OpenCL, Verilog/VHDL (RTL) | Vitis/SDx/Vivado (GUI or script) | SW/HW Emulation, Simulation, GDB, Virtual JTAG (Chipscope) | SW or HW Developer with zero FPGA experience | -| [Hardware Accelerator Development - HDK](hdk/README.md) | Fully custom hardware development experience provides hardware developers with the tools required for developing AFIs for AWS FPGA instances | Verilog/VHDL | Vivado | Simulation, Virtual JTAG | HW Developer with advanced FPGA experience | -| [IP Integrator or High Level Synthesis (HLx)](hdk/docs/IPI_GUI_Vivado_Setup.md) | Graphical interface development experience for integrating IP and high level synthesis development | Verilog/VHDL/C | Vivado (GUI) | Simulation, Virtual JTAG | HW Developer with intermediate FPGA experience | - - -## Overview of Runtime Environments - -| Runtime Environment | Hardware Interface | Host Code Language | FPGA Tools | -| --------|---------|---------|-------| -| C/C++ Software Defined Accelerator Development - [Vitis](Vitis/README.md) / [SDAccel](SDAccel/README.md) | OpenCL APIs and XRT | C/C++ | [SDK](./sdk), Vitis / SDAccel| -| [Hardware Accelerator Development](hdk/README.md) | [XDMA Driver](sdk/linux_kernel_drivers/xdma/README.md), [peek/poke](sdk/userspace/README.md) | C/C++ | [SDK](./sdk), Vivado | -| [IP Integrator or High Level Synthesis (HLx)](hdk/docs/IPI_GUI_Vivado_Setup.md) | [XDMA Driver](sdk/linux_kernel_drivers/xdma/README.md), [peek/poke](sdk/userspace/README.md) | C/C++ | [SDK](./sdk), Vivado | - - -## Overview of Development Tools - -| Tool | Development/Runtime | Tool location | Description | -| --------|---------|---------|---------| -| Vitis 2019.2 | Development | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Software Defined Accelerator Development using the new Vitis toolset](Vitis/README.md) | -| Vivado 2017.4, 2018.2, 2018.3, 2019.1 & 2019.2 | Development | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Hardware Accelerator Development](hdk/README.md) | -| SDx 2017.4, 2018.2, 2018.3 & 2019.1| Development | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Used for [Software Defined Accelerator Development](SDAccel/README.md) | -| FPGA AFI Management Tools | Runtime | [SDK - fpga\_mgmt\_tools](sdk/userspace/fpga_mgmt_tools) | Command-line tools used for FPGA management while running on the F1 instance | -| Virtual JTAG | Development (Debug) | [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | Runtime debug waveform | -| wait\_for\_afi | Development | [wait\_for\_afi.py](shared/bin/scripts/wait_for_afi.py) | Helper script that notifies via email on AFI generation completion | -| notify\_via\_sns | Development | [notify\_via\_sns.py](shared/bin/scripts/notify_via_sns.py) | Notifies developer when design build process completes | -| AFI Administration | Development | [Copy](hdk/docs/copy_fpga_image.md), [Delete](hdk/docs/delete_fpga_image.md), [Describe](hdk/docs/describe_fpga_images.md), [Attributes](hdk/docs/fpga_image_attributes.md) | AWS CLI EC2 commands for managing your AFIs | - - -> For on-premises development, SDx/Vitis/Vivado must have the correct license and use one of the [supported versions of SDx/Vitis/Vivado](./supported_vivado_versions.txt). -> The following links have more information on on-premises development: [Vivado requirements](hdk/docs/on_premise_licensing_help.md), [Vitis requirements](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_2/ug1393-vitis-application-acceleration.pdf) and [SDx requirements](SDAccel/docs/On_Premises_Development_Steps.md) - - -## Overview of Example Applications -| Accelerator Application | Example | Development Environment | Description | -| --------|---------|---------|-------| -| Custom hardware | [cl\_hello\_world](hdk/cl/examples/cl_hello_world) | HDK - RTL (Verilog) | Simple [getting started example](hdk/README.md) with minimal hardware | -| Custom hardware | [cl\_dram\_dma](hdk/cl/examples/cl_dram_dma) | HDK - RTL (Verilog) | Demonstrates CL connectivity to the F1 shell and connectivity to/from all DDRs | -| Custom hardware IP integration example using a GUI | [cl\_dram\_dma\_hlx](hdk/cl/examples/cl_dram_dma_hlx) | HLx - Verilog | Demonstrates CL connectivity to the F1 shell and connectivity to/from DRAM using the Vivado IP Integrator GUI | -| Virtual Ethernet Application | [Example Application](sdk/apps/virtual-ethernet) | [HDK SDE Example](hdk/cl/examples/cl_sde) | The Virtual Ethernet framework facilitates streaming Ethernet frames from a network interface (or any source) into the FPGA for processing and back out to some destination. Possible use cases for this include deep packet inspection, software defined networking, stream encryption or compression, and more. | -| Pipelined Workload Applications | [cl\_dram\_dma\_data\_retention](hdk/docs/data_retention.md)| [HDK](hdk/cl/examples/cl_dram_dma/software/runtime/test_dram_dma_retention.c) [SDAccel](SDAccel/examples/aws/data_retention) | Demonstrates how to preserve data in DRAMs while swapping out accelerators. Applications that use a temporal accelerator pipeline can take advantage of this feature to reduce latency between FPGA image swaps | -| Digital Up-Converter using High Level Synthesis | [cl\_hls\_dds\_hlx](hdk/cl/examples/cl_hls_dds_hlx) | HLx - C-to-RTL | Demonstrates an example application written in C that is synthesized to RTL (Verilog) | -| Security | [AES, RSA, SHA1](https://github.com/Xilinx/SDAccel_Examples/tree/2018.2/security) | SDAccel - C/C++/OpenCL | Developed using software defined acceleration, this example demonstrates methods of using hardware acceleration to speed up security software algorithms | -| Computer Vision | [Affine, Convolve, Huffman, IDCT](https://github.com/Xilinx/SDAccel_Examples/tree/master/vision) | SDAccel - C/C++/OpenCL | Developed using software defined acceleration, this example demonstrates methods of using hardware acceleration to speed up image detection algorithms | -| Misc Algorithms | [Kmeans, SmithWaterman, MatrixMult](https://github.com/Xilinx/SDAccel_Examples/tree/master/acceleration) | SDAccel - C/C++/OpenCL | Developed using software defined acceleration, this example demonstrates methods of applying hardware acceleration to a variety of sorting and search algorithms | -| Financial | [Blacksholes, Heston](https://github.com/KitAway/FinancialModels_AmazonF1) | SDAccel - C/C++/OpenCL | Developed using software defined acceleration, this example demonstrates methods of using hardware acceleration on Monte Carlo financial models | -| Custom Hardware with Software Defined Acceleration | [RTL Kernels](https://github.com/Xilinx/SDAccel_Examples/tree/master/getting_started/rtl_kernel) | SDAccel - RTL (Verilog) + C/C++/OpenCL | Developed using software defined acceleration, this example demonstrates a quick method for developing new or migrating existing hardware designs (RTL) | -| File Compression | [GZip](https://github.com/Xilinx/Applications/tree/master/GZip) | SDAccel - C/C++/OpenCL | Developed using software defined acceleration, this example demonstrates methods of using hardware acceleration to speed up GZIP compression on an FPGA | -| WebP Image Compression | [WebP](https://github.com/Xilinx/Applications/tree/master/webp) | SDAccel - C/C++/OpenCL | Developed using software defined acceleration, this example demonstrates methods of using hardware acceleration to speed up WebP encoder application on an FPGA | - - -# Getting Started +## Development Environments -### Getting familiar with AWS -If you have never used AWS before, we recommend you start with [AWS getting started training](https://aws.amazon.com/getting-started/), and focus on the basics of the [AWS EC2](https://aws.amazon.com/ec2/) and [AWS S3](https://aws.amazon.com/s3/) services. Understanding the fundamentals of these services will make it easier to work with AWS FPGAs. +| Development Environment | Description | Accelerator Language | Hardware Interface | Debug Options| Typical Developer | +| --------|---------|-------|---------|-------|-------| +| Software Defined Accelerator Development using [Vitis](Vitis/README.md)/[SDAccel](SDAccel/README.md)| Development experience leverages an optimized compiler to allow easy new accelerator development or migration of existing C/C++/openCL, Verilog/VHDL to AWS FPGA instances | C/C++/OpenCL, Verilog/VHDL (RTL) | OpenCL APIs and XRT | SW/HW Emulation, Simulation, GDB, Virtual JTAG (Chipscope) | SW or HW Developer with zero FPGA experience | +| [Hardware Accelerator Development using Vivado](hdk/README.md) | Fully custom hardware development experience provides hardware developers with the tools required for developing AFIs for AWS FPGA instances | Verilog/VHDL | [XDMA Driver](sdk/linux_kernel_drivers/xdma/README.md), [peek/poke](sdk/userspace/README.md) | Simulation, Virtual JTAG | HW Developer with advanced FPGA experience | +| [IP Integrator/High Level Design(HLx) using Vivado](hdk/docs/IPI_GUI_Vivado_Setup.md) | Graphical interface development experience for integrating IP and high level synthesis development | Verilog/VHDL/C | [XDMA Driver](sdk/linux_kernel_drivers/xdma/README.md), [peek/poke](sdk/userspace/README.md) | Simulation, Virtual JTAG | HW Developer with intermediate FPGA experience | -AWS FPGA generation and EC2 F1 instances are supported in the us-east-1 (N. Virginia), us-west-2 (Oregon), eu-west-1 (Ireland) and us-gov-west-1 ([GovCloud US](https://aws.amazon.com/govcloud-us/)) [regions](https://aws.amazon.com/about-aws/global-infrastructure/). +> For on-premise development, SDAccel/Vitis/Vivado must have the [correct license and use one of the supported tool versions](./docs/on_premise_licensing_help.md). -### Setting up development environment for the first time -The developer kit is supported for Linux operating systems only. -You have the choice to develop on AWS EC2 using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) or on-premises. Within a linux environment, you can execute `git clone https://github.com/aws/aws-fpga.git` to download the latest release to your EC2 Instance or local server. Help on cloning from github is available [here](https://help.github.com/articles/which-remote-url-should-i-use/). When using a SSH connection, execute `git clone git@github.com:aws/aws-fpga.git`. [To get help with connecting to Github via SSH](https://help.github.com/articles/connecting-to-github-with-ssh/). - -To setup your instance for development, checkout our [Developer Resources](./developer_resources/README.md) where we provide Step-By-Step guides to setting up a GUI Desktop or a compute cluster. - -Before you start your first AWS FPGA design, we recommend that you go through one of the step-by-step guides. The guides will walk through development steps for hello world examples. Based on the tables above, pick the development environment that best fits your needs and use the guide to get started: - * For fastest way to get started on FPGA accelerator development, start with the software-defined development environment. The guide starts with the [Hello World example](Vitis/README.md). - * Next use the same guide to develop using the C/C++/openCL/RTL based [60+ examples on github](https://github.com/Xilinx/Vitis_Accel_Examples/tree/bb80c8ec699c3131e8874735bd99475ac6fe2ec7). - * For custom hardware development (HDK) environment, start with the [HDK Hello World example](hdk/README.md). - * Next use the same guide to develop using the [cl\_dram\_dma](hdk/cl/examples/cl_dram_dma). - -### In-depth training and resources -Once you have completed your hello world examples, we recommend diving deeper into a training workshop or application notes - * Software-defined [re:Invent 2019 Workshop](https://github.com/Xilinx/SDAccel-AWS-F1-Developer-Labs). - * Lab modules will take you through accelerating compute intensive functions like Inverse Discrete Cosine Transform, Bloom Filter, 2D video convolution, etc. - * You will learn how to identify functions to accelerate and use profiling on example applications use that information to optimize your data movement between the HOST and FPGA. - * Software-defined [re:Invent 2018 Workshop](https://github.com/awslabs/aws-fpga-app-notes/blob/master/reInvent18_Developer_Workshop/README.md) demonstrates a 2D Filter acceleration and how to debug and optimize your accelerator. - * Custom hardware developers need to learn about how the hardware accelerator interfaces to the F1 Shell - * [Shell Interface](hdk/docs/AWS_Shell_Interface_Specification.md) - * [Shell Address Map](hdk/docs/AWS_Fpga_Pcie_Memory_Map.md) - * [Programmer view of the FPGA](./hdk/docs/Programmer_View.md) - * [Virtual JTAG](hdk/docs/Virtual_JTAG_XVC.md) - * [Application for methods of interfacing the host application to the Hardware accelerator](https://github.com/awslabs/aws-fpga-app-notes) - - -# FPGA Developer AMI - -The [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) is available on the AWS marketplace without a software charge and includes free tools and drivers needed for FPGA development on EC2 instances. FPGA development runs on several [EC2 instance types](https://aws.amazon.com/ec2/instance-types/). Given the large size of the FPGA used inside the AWS FPGA instances, the implementation tools require 32GiB Memory (ex: z1d.xlarge, z1d.2xlarge, c5.4xlarge, m5.2xlarge, r5.xlarge, t2.2xlarge). z1d.xlarge/c5.4xlarge and z1d.2xlarge/c5.8xlarge would provide the fastest execution time with 30GiB+ and 60GiB+ of memory respectively. Developers who want to save on cost, could start coding and run simulations on low-cost instances, like t2.2xlarge, and move to the aforementioned larger instances to run the synthesis of their acceleration code. - -Currently, AWS marketplace includes multiple versions of the FPGA Developer AMI, supporting Xilinx SDx 2017.4, 2018.2, 2018.3 and 2019.1 toolchain versions. The following compatibility table describes the mapping of currently supported developer kit versions to AMI versions: - -| Developer Kit Version | Tool Version Supported | Compatible FPGA Developer AMI Version | +## FPGA Developer AMI + +The [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) is available on the AWS marketplace without a software charge and includes tools needed for developing FPGA Designs to run on AWS F1. + +Given the large size of the FPGA used inside AWS F1 Instances, Xilinx tools work best with 32GiB Memory. +z1d.xlarge/c5.4xlarge and z1d.2xlarge/c5.8xlarge instance types would provide the fastest execution time with 30GiB+ and 60GiB+ of memory respectively. +Developers who want to save on cost, could start coding and run simulations on low-cost instances, like t2.2xlarge, and move to the aforementioned larger instances to run the synthesis of their acceleration code. + +AWS marketplace offers multiple versions of the FPGA Developer AMI. The following compatibility table describes the mapping of currently supported developer kit versions to AMI versions: + +| Developer Kit Version | Tool Version Supported | Compatible FPGA Developer AMI Version | |-----------|-----------|------| -| 1.3.7-1.3.X | 2017.4 | v1.4.0-v1.4.X (Xilinx Vivado/SDx 2017.4) | -| 1.4.X | 2017.4 | v1.4.0-v1.4.X (Xilinx Vivado/SDx 2017.4) | -| 1.4.3+ | 2018.2 | v1.5.0-v1.5.X (Xilinx Vivado/SDx 2018.2) | -| 1.4.8+ | 2018.3 | v1.6.0-v1.6.X (Xilinx Vivado/SDx 2018.3) | -| 1.4.11+ | 2019.1 | v1.7.0-v1.7.X (Xilinx Vivado/SDx 2019.1) | +| 1.4.16+ | 2020.1 | v1.9.0-v1.9.X (Xilinx Vivado/Vitis 2020.1) | | 1.4.13+ | 2019.2 | v1.8.0-v1.8.X (Xilinx Vivado/Vitis 2019.2) | +| 1.4.11+ | 2019.1 | v1.7.0-v1.7.X (Xilinx Vivado/SDx 2019.1) | +| 1.4.8 - 1.4.15a | 2018.3 | v1.6.0-v1.6.X (Xilinx Vivado/SDx 2018.3) | +| 1.4.3 - 1.4.15a | 2018.2 | v1.5.0-v1.5.X (Xilinx Vivado/SDx 2018.2) | +| 1.3.7 - 1.4.15a | 2017.4 | v1.4.0-v1.4.X (Xilinx Vivado/SDx 2017.4) | + +⚠️ Developer kit release v1.4.16 will remove support for Xilinx 2017.4, 2018.2, 2018.3 toolsets. +While developer kit release v1.4.16 onwards will not support older Xilinx tools, you can still use them using HDK releases v1.4.15a or earlier. +Please checkout [the latest v1.4.15a release tag from Github](https://github.com/aws/aws-fpga/releases/tag/v1.4.15a) to use Xilinx 2017.4, 2018.2, 2018.3 toolsets. -Developer kit versions prior to v1.3.7 and Developer AMI prior to v1.4 (2017.1) reached end-of-life. See [AWS forum announcement](https://forums.aws.amazon.com/ann.jspa?annID=6068) for additional details. +⚠️ Developer kit versions prior to v1.3.7 and Developer AMI prior to v1.4 (2017.1) reached end-of-life. See [AWS forum announcement](https://forums.aws.amazon.com/ann.jspa?annID=6068) for additional details. For software-defined development please look at the runtime compatibility table based on the Xilinx toolset in use: [SDAccel](SDAccel/docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table) or [Vitis](Vitis/docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table) - -# Hardware Development Kit (HDK) +## Hardware Development Kit (HDK) -The [HDK directory](./hdk/README.md) contains useful information, examples, and scripts for developers wanting to start building Amazon FPGA Images (AFI). It includes the development environment, simulation, build and AFI creation scripts. The HDK can be installed on any on-premises server or an EC2 instance. The developer kit is not required if you plan to use a pre-built AFI shared from another developer. +The [HDK directory](./hdk/README.md) contains documentation, examples, simulation, build and AFI creation scripts to start building Amazon FPGA Images (AFI). +The HDK can be installed on any on-premises server or an EC2 instance. +The developer kit is not required if you plan to use a pre-built AFI shared from another developer. - -# Software-defined Development Environment +## Software-defined Development Environment -The software-defined development environment allows customers to compile their C/C++/OpenCL code into the FPGA as kernels, and use OpenCL APIs to pass data to the FPGA. Software developers with no FPGA experience will find a familiar development experience that supercharges cloud applications. +The software-defined development environment allows customers to compile their C/C++/OpenCL code into the FPGA as kernels, and use OpenCL APIs to pass data to the FPGA. +Software developers with no FPGA experience will find a familiar development experience that supercharges cloud applications. -In addition, this development environment (also called SDAccel) allows the mix of C/C++ and RTL accelerator designs into a C/C++ software based development environment. This method enables faster prototyping using C/C++ while supporting manual optimization of critical blocks within RTL. This approach is similar to optimizing time critical functions using software compiler optimization methods. - -This developer kit has 80+ examples to help you get started on FPGA acceleration. +In addition, this development environment allows for a mix of C/C++ and RTL accelerator designs into a C/C++ software based development environment. This method enables faster prototyping using C/C++ while supporting manual optimization of critical blocks within RTL. This approach is similar to optimizing time critical functions using software compiler optimization methods. To get started with Xilinx SDAccel, review the [Software-defined development environment readme](SDAccel/README.md). To get started with Xilinx Vitis, review the [Vitis unified development environment readme](Vitis/README.md). - - -# Runtime Tools (SDK) +## Runtime Tools (SDK) The [SDK directory](./sdk/README.md) includes the runtime environment required to run on EC2 FPGA instances. It includes the drivers and tools to manage the AFIs that are loaded on the FPGA instance. The SDK isn't required during the AFI development process; it is only required once an AFI is loaded onto an EC2 FPGA instance. The following sdk resources are provided: * Linux Kernel Drivers - The developer kit includes three drivers: * [XDMA Driver](sdk/linux_kernel_drivers/xdma/README.md) - DMA interface to/from HDK accelerators. - * [XOCL Driver](sdk/linux_kernel_drivers/xocl) - DMA interface with software defined accelerators (also called hardware kernels). * [FPGA Libraries](sdk/userspace/fpga_libs) - APIs used by C/C++ host applications. * [FPGA Management Tools](sdk/userspace/fpga_mgmt_tools/README.md) - AFI management APIs for runtime loading/clearing FPGA image, gathering metrics and debug interface on the F1 instance. - -# Developer Support +# Amazon EC2 F1 Platform Features +* 1-8 Xilinx UltraScale+ VU9P based FPGA slots +* Per FPGA Slot, Interfaces available for Custom Logic(CL): + * One x16 PCIe Gen 3 Interface + * Four DDR4 RDIMM interfaces (with ECC) + * AXI4 protocol support on all interfaces +* User-defined clock frequency driving all CL to Shell interfaces +* Multiple free running auxiliary clocks +* PCI-E endpoint presentation to Custom Logic(CL) + * Management PF (physical function) + * Application PF +* Virtual JTAG, Virtual LED, Virtual DIP Switches +* PCI-E interface between Shell(SH) and Custom Logic(CL). + * SH to CL inbound 512-bit AXI4 interface + * CL to SH outbound 512-bit AXI4 interface + * Multiple 32-bit AXI-Lite buses for register access, mapped to different PCIe BARs + * Maximum payload size set by the Shell + * Maximum read request size set by the Shell + * AXI4 error handling +* DDR interface between SH and CL + * CL to SH 512-bit AXI4 interface + * 1 DDR controller implemented in the SH (always available) + * 3 DDR controllers implemented in the CL (configurable number of implemented controllers allowed) + +# Getting Started + +### Getting familiar with AWS +If you have never used AWS before, we recommend you start with [AWS getting started training](https://aws.amazon.com/getting-started/), and focus on the basics of the [AWS EC2](https://aws.amazon.com/ec2/) and [AWS S3](https://aws.amazon.com/s3/) services. +Understanding the fundamentals of these services will make it easier to work with AWS F1 and the FPGA Developer Kit. + +FPGA Image generation and EC2 F1 instances are supported in the us-east-1 (N. Virginia), us-west-2 (Oregon), eu-west-1 (Ireland) and us-gov-west-1 ([GovCloud US](https://aws.amazon.com/govcloud-us/)) [regions](https://aws.amazon.com/about-aws/global-infrastructure/). + +> ⚠️ NOTE: By default, your AWS Account will have an EC2 F1 Instance launch limit of 0. +> Before using F1 instances, you will have to open a [Support Case](https://console.aws.amazon.com/support/home#/case/create) to increase the EC2 Instance limits to allow launching F1 instances. + +### Setting up development environment for the first time + +You have the choice to develop on AWS EC2 using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) or on-premise. + +> ℹ️ INFO: We suggest starting with the FPGA Developer AMI with [build instances](#fpga-developer-ami) on EC2 as it has Xilinx tools and licenses setup for you to be able to quickly get into development. -The [**Amazon FPGA Development User Forum**](https://forums.aws.amazon.com/forum.jspa?forumID=243&start=0) is the first place to go to post questions, learn from other users and read announcements from the EC2 FPGA team. +> ℹ️ INFO: For on-premise development, you will need to have [Xilinx tools and licenses available for you to use](./docs/on_premise_licensing_help.md) -* Click the "Watch" button in GitHub upper right corner to get regular updates. -* We recommend you will join the [AWS forum](https://forums.aws.amazon.com/forum.jspa?forumID=243) to engage with the FPGA developer community and get help when needed (both AWS and Xilinx engineers monitor this forum). -* In case you can't see "Your Stuff" details, you will need to logout using the logout button on the forums page and log back in again. +1. Start a Build Instance first to start your development. + > 💡 TIP: This instance does not have to be an F1 instance. You only require an F1 instance to run your AFI's(Amazon FPGA Image) once you have gone through your design build and AFI creation steps. + + > ℹ️ INFO: If you need to follow GUI Development flows, please checkout our [Developer Resources](./developer_resources/README.md) where we provide Step-By-Step guides to setting up a GUI Desktop. +1. Clone the [FPGA Developer Kit](https://github.com/aws/aws-fpga) on your instance. + ```git clone https://github.com/aws/aws-fpga.git``` +1. Follow the quickstarts from the next section. + +### Quickstarts +Before you create your own AWS FPGA design, we recommend that you go through one of the step-by-step Quickstart guides: + +| Description | Quickstart | Next Steps | +|----|----|----| +| Software Defined Accelerator Development using Xilinx Vitis | [Vitis hello_world Quickstart](Vitis/README.md) | [60+ Vitis examples](./Vitis/examples/), [Vitis Library Examples](./docs/examples/example_list.md) | +| Software Defined Accelerator Development using Xilinx SDAccel | [SDAccel hello_world Quickstart](SDAccel/README.md) | [60+ SDAccel examples](./SDAccel/examples/) | +| Custom Hardware Development(HDK) | [HDK hello_world Quickstart](hdk/README.md) | [CL to Shell and DRAM connectivity example](./hdk/cl/examples/cl_dram_dma), [Virtual Ethernet Application](./sdk/apps/virtual-ethernet) using the [Streaming Data Engine](./hdk/cl/examples/cl_sde) | +| IP Integrator/High Level Design(HLx) | [IPI hello_world Quickstart](hdk/cl/examples/cl_hello_world_hlx/README.md) | [IPI GUI Examples](hdk/docs/IPI_GUI_Examples.md) | + +ℹ️ INFO: For more in-depth applications and examples of using High level synthesis, Vitis Libraries, App Notes and Workshops, please refer to our [Example List](./docs/examples/example_list.md) + +### How Tos +| How To | Description | +|----|----| +| [Migrate Alveo U200 designs to F1](./Vitis/docs/Alveo_to_AWS_F1_Migration.md) | This application note shows the ease of migrating an Alveo U200 design to F1. | - # Documentation Overview -The documentation is located throughout this developer kit, therefore, to help developers find information quicker the table below consolidates a list of key documents: +Documentation is located throughout this developer kit and the table below consolidates a list of key documents to help developers find information: | Topic | Document Name | Description | |-----------|-----------|------| -| Developer Kit Features | [RELEASE\_NOTES](./RELEASE_NOTES.md), [Errata](./ERRATA.md) | Release notes and Errata for all developer kit features, excluding the shell | -| Frequently asked questions | [FAQ](./FAQs.md), [Errata](./ERRATA.md) | Q/A are added based on developer feedback and common AWS forum questions | -| F1 Shell (HDK) | [AWS\_Shell\_RELEASE\_NOTES](./hdk/docs/AWS_Shell_RELEASE_NOTES.md), [AWS\_Shell\_ERRATA](./hdk/docs/AWS_Shell_ERRATA.md) | Release notes and Errata for F1 shell | -| F1 Shell (HDK) | [AWS\_Shell\_Interface\_Specification](hdk/docs/AWS_Shell_Interface_Specification.md) | Shell-CL interface specification for HDK developers building AFI | -| AWS setup | [Setup\_AWS\_CLI\_and\_S3\_Bucket](SDAccel/docs/Setup_AWS_CLI_and_S3_Bucket.md) | Setup instructions for preparing for AFI creation | -| SDx graphical interface (SDAccel) | [README\_GUI](SDAccel/docs/README_GUI.md) | Instructions using the SDx GUI for software defined acceleration development and debug | -| Software defined acceleration using RTL (SDAccel) | [Debug\_RTL\_Kernel](SDAccel/docs/Debug_RTL_Kernel.md) | Instructions on debugging RTL Kernel | -| Software defined acceleration Run time (SDAccel) | [Create\_Runtime\_AMI](SDAccel/docs/Create_Runtime_AMI.md) | Instructions on creating a runtime AMI | -| Host Application (HDK) | [Programmer\_View](hdk/docs/Programmer_View.md) | Host application to CL interface specification | -| CL Debug (HDK) | [Virtual\_JTAG\_XVC](hdk/docs/Virtual_JTAG_XVC.md) | Debugging CL using Virtual JTAG (Chipscope) | -| CL/Shell Simulation (HDK) | [RTL\_Simulating\_CL\_Designs](hdk/docs/RTL_Simulating_CL_Designs.md) | Shell-CL simulation specification | -| Driver (HDK) | [README](sdk/linux_kernel_drivers/xdma/README.md) | Describes the DMA driver (XDMA) used by HDK examples and includes a link to an installation guide | -| Shell Timeout and AXI Protocol Protection | [HOWTO\_detect\_shell\_timeout](hdk/docs/HOWTO_detect_shell_timeout.md) | The shell will terminate transactions after a time period or on an illegal transaction. This describes how to detect and gather data to help debug CL issues caused by timeouts. | -| AFI Power | [afi\_power](hdk/docs/afi_power.md) | Helps developers with understanding AFI power and preventing power violations on the F1 instance | -| AFI Management | [README](sdk/userspace/fpga_mgmt_tools/README.md) | CLI documentation for managing AFI on the F1 instance | -| AFI Administration | [copy\_fpga\_image](hdk/docs/copy_fpga_image.md), [delete\_fpga\_image](hdk/docs/delete_fpga_image.md), [describe\_fpga\_images](hdk/docs/describe_fpga_images.md), [fpga\_image\_attributes](hdk/docs/fpga_image_attributes.md) | CLI documentation for administering AFIs | -| AFI Creation Error Codes | [create\_fpga\_image\_error\_codes](hdk/docs/create_fpga_image_error_codes.md) | CLI documentation for managing AFIs | -| Developing on-premises | [HDK: on\_premise\_licensing\_help](hdk/docs/on_premise_licensing_help.md), [SDAccel: On\_Premises\_Development\_Steps](SDAccel/docs/On_Premises_Development_Steps.md) | Guidance for developer wanting to develop AFIs from on-premises instead of using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) running on AWS EC2 | +| AWS setup | [Setup AWS CLI and S3 Bucket](./SDAccel/docs/Setup_AWS_CLI_and_S3_Bucket.md) | Setup instructions for preparing for AFI creation | +| Developer Kit | [RELEASE NOTES](./RELEASE_NOTES.md), [Errata](./ERRATA.md) | Release notes and Errata for all developer kit features, excluding the shell | +| Developer Kit | [Errata](./ERRATA.md) | Errata for all developer kit features, excluding the shell | +| F1 Shell | [AWS Shell RELEASE NOTES](./hdk/docs/AWS_Shell_RELEASE_NOTES.md) | Release notes for F1 shell | +| F1 Shell | [AWS Shell ERRATA](./hdk/docs/AWS_Shell_ERRATA.md) | Errata for F1 shell | +| F1 Shell | [AWS Shell Interface Specification](./hdk/docs/AWS_Shell_Interface_Specification.md) | Shell-CL interface specification for HDK developers building AFI | +| F1 Shell - Timeout and AXI Protocol Protection | [How to detect a shell timeout](hdk/docs/HOWTO_detect_shell_timeout.md) | The shell will terminate transactions after a time period or on an illegal transaction. This describes how to detect and gather data to help debug CL issues caused by timeouts. | +| Vitis | [Debug Vitis Kernel](./Vitis/docs/Debug_Vitis_Kernel.md) | Instructions on debugging Vitis Kernel | +| Vitis | [Create Runtime AMI](./Vitis/docs/Create_Runtime_AMI.md) | Instructions on creating a runtime AMI when using Xilinx Vitis| +| Vitis | [XRT Instructions](./Vitis/docs/XRT_installation_instructions.md) | Instructions on building, installing XRT with MPD daemon considerations for F1 | +| SDAccel | [Debug RTL Kernel](./SDAccel/docs/Debug_RTL_Kernel.md) | Instructions on debugging RTL Kernel with SDAccel | +| SDAccel | [Create Runtime AMI](./SDAccel/docs/Create_Runtime_AMI.md) | Instructions on creating a runtime AMI when using Xilinx SDAccel| +| HDK - Host Application | [Programmer View](./hdk/docs/Programmer_View.md) | Host application to CL interface specification | +| HDK - CL Debug | [Debug using Virtual JTAG](./hdk/docs/Virtual_JTAG_XVC.md) | Debugging CL using Virtual JTAG (Chipscope) | +| HDK - Simulation | [Simulating CL Designs](./hdk/docs/RTL_Simulating_CL_Designs.md) | Shell-CL simulation specification | +| HDK - Driver | [README](./sdk/linux_kernel_drivers/xdma/README.md) | Describes the DMA driver (XDMA) used by HDK examples and includes a link to an installation guide | +| AFI | [AFI Management SDK](./sdk/userspace/fpga_mgmt_tools/README.md) | CLI documentation for managing AFI on the F1 instance | +| AFI - EC2 CLI | [copy\_fpga\_image](./hdk/docs/copy_fpga_image.md), [delete\_fpga\_image](./hdk/docs/delete_fpga_image.md), [describe\_fpga\_images](./hdk/docs/describe_fpga_images.md), [fpga\_image\_attributes](./hdk/docs/fpga_image_attributes.md) | CLI documentation for administering AFIs | +| AFI - Creation Error Codes | [create\_fpga\_image\_error\_codes](hdk/docs/create_fpga_image_error_codes.md) | CLI documentation for managing AFIs | +| AFI - Power | [FPGA Power, recovering from clock gating](./hdk/docs/afi_power.md) | Helps developers with understanding FPGA power usage, preventing power violations on the F1 instance and recovering from a clock gated slot. | +| On-premise Development | [Tools, Licenses required for on-premise development](./docs/on_premise_licensing_help.md) | Guidance for developer wanting to develop AFIs from on-premises instead of using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) | +| Frequently asked questions | [FAQ](./FAQs.md)| Q/A are added based on developer feedback and common AWS forum questions | + + +# Developer Support + +* The [**Amazon FPGA Development User Forum**](https://forums.aws.amazon.com/forum.jspa?forumID=243&start=0) is the first place to go to post questions, learn from other users and read announcements. + * We recommend joining the [AWS forums](https://forums.aws.amazon.com/forum.jspa?forumID=243) to engage with the FPGA developer community, AWS and Xilinx engineers to get help. + +* You could also file a [Github Issue](https://github.com/aws/aws-fpga/issues) for support. We prefer the forums as this helps the entire community learn from issues, feedback and answers. + * Click the "Watch" button in GitHub upper right corner to get regular updates. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 443d2bea..363a00eb 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,28 +1,15 @@ # AWS EC2 FPGA HDK+SDK Release Notes -## AWS EC2 F1 Platform Features: - * 1-8 Xilinx UltraScale+ VU9P based FPGA slots - * Per FPGA Slot, Interfaces available for Custom Logic(CL): - * One x16 PCIe Gen 3 Interface - * Four DDR4 RDIMM interfaces (with ECC) - * AXI4 protocol support on all interfaces - * User-defined clock frequency driving all CL to Shell interfaces - * Multiple free running auxiliary clocks - * PCI-E endpoint presentation to Custom Logic(CL) - * Management PF (physical function) - * Application PF - * Virtual JTAG, Virtual LED, Virtual DIP Switches - * PCI-E interface between Shell(SH) and Custom Logic(CL). - * SH to CL inbound 512-bit AXI4 interface - * CL to SH outbound 512-bit AXI4 interface - * Multiple 32-bit AXI-Lite buses for register access, mapped to different PCIe BARs - * Maximum payload size set by the Shell - * Maximum read request size set by the Shell - * AXI4 error handling - * DDR interface between SH and CL - * CL to SH 512-bit AXI4 interface - * 1 DDR controller implemented in the SH (always available) - * 3 DDR controllers implemented in the CL (configurable number of implemented controllers allowed) +## Release 1.4.16 (See [ERRATA](./ERRATA.md) for unsupported features) +* FPGA developer kit now supports Xilinx Vivado/Vitis 2020.1 + * To upgrade, use [Developer AMI v1.9.0](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) on the AWS Marketplace. +* Updated Vitis examples to include usage of Vitis Libraries. +* Added documentation and examples to show Xilinx Alveo design migration to F1. + +## Release 1.4.15a (See [ERRATA](./ERRATA.md) for unsupported features) +* Fixed Xilinx AR#73068 patching + * DDR4 IP needs to be regenerated for the patch to take effect. +* Updated cl_dram_dma public AFI. ## Release 1.4.15 (See [ERRATA](./ERRATA.md) for unsupported features) * Added Xilinx AR#73068 patching @@ -235,55 +222,6 @@ * Release 1.4.0 greatly improves the performance of the DMA (for interrupt driven DMA on the cl\_dram\_dma example design). This is accomplished through a combination of shell changes to relax DMA timeouts and a new XDMA software driver option. We have ported the relevant HDK examples to the XDMA driver in this release. EDMA is still supported, and developers can freely choose which DMA driver to use as part of their host application. -## Supported Tools and Environment - -* The HDK and SDK are designed for **Linux** environment and has not been tested on other platforms -* The First installation of AWS FPGA SDK requires having gcc installed on the instance. If it's not available, try `sudo yum update && sudo yum group install "Development Tools"` -* The HDK build step requires having Xilinx's Vivado tool and Vivado License Management running. These are provided with AWS FPGA Developer AMI at no additional cost -* This release is tested and validated with Xilinx 2017.4 SDx/Vivado -* Developers that choose to develop on-premises need to have Xilinx license 'EF-VIVADO-SDX-VU9P-OP' installed. For more help, please refer to the [on-premises licensing help](./hdk/docs/on_premise_licensing_help.md) -* The following simulators are supported with this HDK: -**Vivado XSIM RTL simulator -** Mentor Graphics' Questa RTL simulator (with a separate license from MentorGraphics) -** Synopsys' VCS RTL simulator (with a separate license from Synopsys) - -## License Requirements - -The HDK and SDK in the FPGA development kit have different licenses. For more details please refer to the [HDK License](./hdk/LICENSE.txt) and the [SDK License](./sdk/LICENSE.txt). - -## FAQs - -**Q: How do I know which HDK version I have on my instance/machine? ** - -Look for the ./hdk/hdk_version.txt file. - -**Q: How do I know what my Shell version is? ** - -The Shell version of an FPGA slot is available through the FPGA Image Management tools after an AFI has been loaded. See the description of `fpga-describe-local-image` for more details on retrieving the shell version from a slot. Prior to loading an AFI, the state of the FPGA (including shell version) is undefined and non-deterministic. - -**Q: How do I know what version of FPGA Image management tools are running on my instance? ** - -The FPGA Image management tools version is reported with any command executed from these tools. See the description of `fpga-describe-local-image` for more details. - -**Q: How do I update my existing design with this release?** - -1. Start by either cloning the entire GitHub structure for the HDK release or downloading new directories that have changed. AWS recommends an entire GitHub clone to ensure no files are missed -2. Update the CL design to conform to the new AWS_Shell_Interface_Specification TODO: add link. TODO: need a doc to outline what changes are a MUST in this upgrade, and which ones are optional? -3. Follow the process for AFI generation outlined in aws-fpga/hdk/cl/examples/readme.md -4. Update FPGA Image Management Tools to the version included in aws-fpga/sdk/management -TODO: SDaccel design have different steps? - -**Q: How do I get support?** - -The FPGA Development forum provides an easy access to Developer support. It's the first place to go to post questions, suggestions and receive important announcements from the AWS FPGA team. To gain access to the user forum, please go to https://forums.aws.amazon.com/index.jspa and login. To be notified of important messages you will need to click the “Watch Forum” button on the right side of the screen. - -**Q: How do I know which HDK GitHub release I am working with? ** - -See the release notes at the top of the GitHub directory to identify the version of your GitHub clone. - -TODO: The following major features are included in this HDK release: - - ## Previous release notes ## Release 1.3.X Details (See [ERRATA](./ERRATA.md) for unsupported features) diff --git a/SDAccel/README.md b/SDAccel/README.md index a6fd741a..da59da6e 100644 --- a/SDAccel/README.md +++ b/SDAccel/README.md @@ -43,7 +43,7 @@ It is highly recommended you read the documentation and utilize software and har * Launch an instance using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) which comes pre-installed with SDAccel and required licenses. * You may use this F1 instance to [build your host application and Xilinx FPGA binary](#createapp), however, it is more cost efficient to either: * Launch the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) on a compute EC2 instance, with a minimum of 30GiB RAM), **OR** - * Follow the [On-Premises Instructions](../hdk/docs/on_premise_licensing_help.md) to purchase and install a license from Xilinx. + * Follow the [On-Premises Instructions](../docs/on_premise_licensing_help.md) to purchase and install a license from Xilinx. * Setup AWS IAM permissions for creating FPGA Images (CreateFpgaImage and DescribeFpgaImages). [EC2 API Permissions are described in more detail](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ec2-api-permissions.html). It is highly recommended that you validate your AWS IAM permissions prior to proceeding with this quick start. By calling the [DescribeFpgaImages API](../hdk/docs/describe_fpga_images.md) you can check that your IAM permissions are correct. * [Setup AWS CLI and S3 Bucket](docs/Setup_AWS_CLI_and_S3_Bucket.md) to enable AFI creation. * Install optional [packages](packages.txt) required to run all examples. If you do not install these packages, some examples may not work properly. The setup scripts will warn you of any missing packages. @@ -191,7 +191,7 @@ For help with AFI creation issues, see [create-fpga-image error codes](../hdk/do # 3. Run the FPGA accelerated application on Amazon FPGA instances -* Start an FPGA instance using [FPGA Developer AMI on AWS Marketplace](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) and check the AMI [compatibility table](../README.md#devAmi) and [runtime compatibility table](docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table). Alternatively, you can [create your own Runtime AMI](docs/Create_Runtime_AMI.md) for running your SDAccel applications on Amazon FPGA instances. +* Start an FPGA instance using [FPGA Developer AMI on AWS Marketplace](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) and check the AMI [compatibility table](../README.md#fpga-developer-ami) and [runtime compatibility table](docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table). Alternatively, you can [create your own Runtime AMI](docs/Create_Runtime_AMI.md) for running your SDAccel applications on Amazon FPGA instances. * *Assuming the developer flow (compilation) was done on a separate instance you will need to:* * Copy the compiled host executable (exe) to the new instance * Copy the \*.awsxclbin AWS FPGA binary file to the new instance diff --git a/SDAccel/docs/README_GUI.md b/SDAccel/docs/README_GUI.md index 9c84be84..4d3f5485 100644 --- a/SDAccel/docs/README_GUI.md +++ b/SDAccel/docs/README_GUI.md @@ -31,11 +31,7 @@ First change directory to **helloworld_ocl** example. ``` $ cd /SDAccel/examples/xilinx/getting_started/hello_world/helloworld_ocl ``` -The github examples use common header files and those needs to be copied in the local project source folder to make it easier to use. -Type the command **make local-files** to copy all necessary files in the local directory. -``` - $ make local-files -``` + The SDAccel GUI is invoked with the **sdx** command. ``` diff --git a/SDAccel/examples/xilinx_2017.4 b/SDAccel/examples/xilinx_2017.4 deleted file mode 160000 index cd196250..00000000 --- a/SDAccel/examples/xilinx_2017.4 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cd196250dfdd63491080e8c6f3e79fe6d1718997 diff --git a/SDAccel/examples/xilinx_2018.2 b/SDAccel/examples/xilinx_2018.2 deleted file mode 160000 index a41b5892..00000000 --- a/SDAccel/examples/xilinx_2018.2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a41b58921188ad90ace2d34a22a2513d8f74b549 diff --git a/SDAccel/examples/xilinx_2018.3 b/SDAccel/examples/xilinx_2018.3 deleted file mode 160000 index b2884db9..00000000 --- a/SDAccel/examples/xilinx_2018.3 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b2884db9768d6589ae094cd06d9b491b3bd39816 diff --git a/Vitis/README.md b/Vitis/README.md index a3248372..5e34083e 100644 --- a/Vitis/README.md +++ b/Vitis/README.md @@ -2,10 +2,10 @@ There are three steps for accelerating your application on an Amazon EC2 FPGA instance using the software-defined development flow: 1. Build the host application, and the Xilinx FPGA binary -2. Create an AFI +2. Create an AFI 3. Run the FPGA accelerated application on AWS FPGA instances -This quick start guide will utilize a simple "Hello World" Vitis example to get you started. +This quick start guide will utilize a simple "Hello World" Vitis example to get you started. It is highly recommended you read the documentation and utilize software and hardware emulation prior to running on F1. The F1 HW Target compile time is ~50 minutes, therefore, software and hardware emulation should be used during development. @@ -31,7 +31,7 @@ The F1 HW Target compile time is ~50 minutes, therefore, software and hardware e # Overview * Vitis is a complete development environment for applications accelerated using Xilinx FPGAs * It leverages the OpenCL heterogeneous computing framework to offload compute intensive workloads to the FPGA -* The accelerated application is written in C/C++, OpenCL or RTL with OpenCL APIs +* The accelerated application is written in C/C++, OpenCL or RTL with OpenCL APIs # Prerequisites @@ -41,26 +41,28 @@ The F1 HW Target compile time is ~50 minutes, therefore, software and hardware e * Launch an instance using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) which comes pre-installed with Vitis and required licenses. * You may use this F1 instance to [build your host application and Xilinx FPGA binary](#createapp), however, it is more cost efficient to either: * Launch the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) on a compute EC2 instance, with a minimum of 30GiB RAM), **OR** - * Follow the [On-Premises Instructions](../hdk/docs/on_premise_licensing_help.md) to purchase and install a license from Xilinx. + * Follow the [On-Premises Instructions](../docs/on_premise_licensing_help.md) to purchase and install a license from Xilinx. * Setup AWS IAM permissions for creating FPGA Images (CreateFpgaImage and DescribeFpgaImages). [EC2 API Permissions are described in more detail](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ec2-api-permissions.html). It is highly recommended that you validate your AWS IAM permissions prior to proceeding with this quick start. By calling the [DescribeFpgaImages API](../hdk/docs/describe_fpga_images.md) you can check that your IAM permissions are correct. * [Setup AWS CLI and S3 Bucket](docs/Setup_AWS_CLI_and_S3_Bucket.md) to enable AFI creation. -* Install optional [packages](packages.txt) required to run all examples. If you do not install these packages, some examples may not work properly. The setup scripts will warn you of any missing packages. +* Install optional [packages](packages.txt) required to run all examples. If you do not install these packages, some examples may not work properly. The setup scripts will warn you of any missing packages. * Additional dependencies may get flagged during the AWS Vitis scripts as warnings or errors. ## Github and Environment Setup -* Clone this github repository and source the *vitis_setup.sh* script. This will take care of: - * Downloading the required files: - * [AWS Platform](./aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_2) that allows Xilinx FPGA Binary files to target AWS F1 instances - * [AFI Creation script](./tools/create_vitis_afi.sh) that generates an AFI and AWS FPGA Binary from a Xilinx FPGA Binary - * Installing the required XRT, libraries and drivers - - ``` - $ git clone https://github.com/aws/aws-fpga.git $AWS_FPGA_REPO_DIR - $ cd $AWS_FPGA_REPO_DIR - $ source vitis_setup.sh - ``` +* Clone this github repository and source the *vitis_setup.sh* script: +``` + $ git clone https://github.com/aws/aws-fpga.git $AWS_FPGA_REPO_DIR + $ cd $AWS_FPGA_REPO_DIR + $ source vitis_setup.sh +``` + +* Sourcing the *vitis_setup.sh* script: + * Downloads and sets the correct AWS Platform: + * [AWS Vitis Platform](./aws_platform/xilinx_aws-vu9p-f1_shell-v04261818_201920_2) that contains the dynamic hardware that enables Vitis kernels to run on AWS F1 instances. * Valid platforms for shell_v04261818: `AWS_PLATFORM_201920_2` (Default) AWS F1 Vitis platform. + * Sets up the Xilinx Vitis example submodules. + * Installs the required libraries and package dependencies. + * Run environment checks to verify supported tool/lib versions. # 1. Build the host application, Xilinx FPGA binary and verify you are ready for FPGA acceleration @@ -70,13 +72,15 @@ This section will walk you through creating, emulating and compiling your host a # Emulate your Code - The main goal of emulation is to ensure functional correctness and to determine how to partition the application between the host CPU and the FPGA. +HW/SW Emulation does not require use of actual FPGA's and can be run on any compute instances. Using non-F1 EC2 compute instances for initial development will help reduce costs. ## Software (SW) Emulation -For CPU-based (SW) emulation, both the host code and the FPGA binary code are compiled to run on an x86 processor. The SW Emulation enables developers to iterate and refine the algorithms through fast compilation. The iteration time is similar to software compile and run cycles on a CPU. +For CPU-based (SW) emulation, both the host code and the FPGA binary code are compiled to run on an x86 processor. +SW Emulation enables developers to iterate and refine the algorithms through fast compilation. +The iteration time is similar to software compile and run cycles on a CPU. The instructions below describe how to run the Vitis SW Emulation flow using the Makefile provided with a simple "hello world" example @@ -183,7 +187,7 @@ For help with AFI creation issues, see [create-fpga-image error codes](../hdk/do # 3. Run the FPGA accelerated application on Amazon FPGA instances -* Start an FPGA instance using [FPGA Developer AMI on AWS Marketplace](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) and check the AMI [compatibility table](../README.md#devAmi) and [runtime compatibility table](./docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table). Alternatively, you can [create your own Runtime AMI](docs/Create_Runtime_AMI.md) for running your Vitis applications on Amazon FPGA instances. +* Start an FPGA instance using [FPGA Developer AMI on AWS Marketplace](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) and check the AMI [compatibility table](../README.md#fpga-developer-ami) and [runtime compatibility table](./docs/Create_Runtime_AMI.md#runtime-ami-compatibility-table). Alternatively, you can [create your own Runtime AMI](docs/Create_Runtime_AMI.md) for running your Vitis applications on Amazon FPGA instances. * *Assuming the developer flow (compilation) was done on a separate build instance you will need to:* * Copy the compiled host executable (exe) to the new F1 instance * Copy the \*.awsxclbin AWS FPGA binary file to the new instance @@ -203,8 +207,6 @@ For help with AFI creation issues, see [create-fpga-image error codes](../hdk/do # Additional Vitis Information -* [Vitis Environment tutorial](https://www.github.com/Xilinx/Vitis-Tutorials) - * [Vitis User Guide](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_2/ug1393-vitis-application-acceleration.pdf) * [Vitis Product Info](https://www.xilinx.com/products/design-tools/vitis.html) diff --git a/Vitis/docs/Alveo_to_AWS_F1_Migration.md b/Vitis/docs/Alveo_to_AWS_F1_Migration.md new file mode 100644 index 00000000..cdcb5fc3 --- /dev/null +++ b/Vitis/docs/Alveo_to_AWS_F1_Migration.md @@ -0,0 +1,242 @@ +# Application Migration between Alveo U200 platform & Amazon EC2 F1 instances + +The Vitis development environment provides a unified environment to develop FPGA accelerated applications across Alveo™ products and Amazon EC2 F1 instances. +The Vitis® flow is based on standard programming languages for both software and hardware components, along with an open-source runtime library and optimizing compilation technology. +This approach enables seamless application migration across acceleration platforms. + +Using the Vitis tool flow, Xilinx was able to seamlessly port over 40+ designs from the Alveo U200 platform to F1 instances without touching the kernel source code and making only minor cosmetic changes to application source code. +One example is Xilinx Real-Time Anti Money Laundering Watch List Management Compute Solution that was developed with Vitis and can be deployed to Alveo U200 and F1 instances. + +## Introduction to Vitis + +FPGA-applications built with the Vitis flow rely on a stack of standardized software and hardware components that insulate the application from platform-specific details, as seen in the figure below. + + +![img](./Alveo_to_AWS_F1_Migration/img/image01.png) + +In the Vitis flow, user applications are developed in C or C++ and use standard user-space APIs to interact with accelerated functions (also known as kernels) implemented in the FPGA device. +These APIs are implemented by the Xilinx Runtime library (XRT) and are built on top drivers that manage communication to and from the FPGA device. +On the hardware side, a platform-specific shell is responsible for essential services such as managing the PCIe link, DMA transfers (to and from the host), and interfacing with off-chip DDR memory. +The shell also exposes standard AXI interfaces to which the user kernels can be connected. + +With this architecture, the user’s source code (host application and acceleration kernel) remains mostly agnostic of platform-specific platform details. +The application sees the standardized XRT APIs and AXI interfaces which are common to all Vitis acceleration platforms. +This aspect is key to enabling application portability across similar FPGA platforms. For most designs, porting from an Alveo U200 platform to F1 instances **can be as simple as changing the --platform option when building the design with Vitis.** + +More details about the Vitis programming and execution model can be found in the [Introduction](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/chunkbreaker1.html#ctb1559866511109) chapter of the Vitis documentation. + + +## Comparison of the Alveo U200 platform and AWS EC2 F1 instances + +FPGA accelerated applications developed with Vitis are highly portable across similar acceleration platforms. +While Vitis greatly facilitates the migration process, it is important to recognize that the features and characteristics of the acceleration platform or instance targeted will have an impact on functionality and achievable performance. + +The following table contrasts the key characteristics of the Alveo U200 and AWS EC2 F1 platforms. + +| | **Feature** | **AWS f1.2xlarge instance** | **Alveo U200 platform** | +| ----------------------- | -------------------- | ------------------------------------------------- | --------------------------- | +| **Available resources** | SLRs | 3 | 3 | +| | LUTs | 895k | 983k | +| | Registers | 1790k | 1966k | +| | DSP Slices | 5640 | 5856 | +| | URAM | 800*288kb = 225Mb | 800*288kb = 225Mb | +| | BRAM | 1680*36kb = 59Mb | 1848*36kb = 64.9Mb | +| **Off-chip memory** | DDR total capacity | 64GB (4x16GB) | 64GB (4x16GB) | +| | DDR Total BW | 68GB/s | 77GB/s | +| **Interfaces** | PCI Express | Gen3x16 | Gen3x16 | +| **Floorplan** | Shell Occupancy | SLR0 and SLR1 | SLR1 | +| | SLR0 | DDR3 | DDR0 | +| | SLR1 | DDR0 (in shell)
DDR2 | DDR1 (in shell)
DDR2 | +| | SLR2 | DDR1 | DDR3 | +| **Tool support** | Vitis | Yes | Yes | +| | ERT | Disabled | Available | +| | XRT | Full Access | Full Access | + + + +### FPGA Resources + +FPGA resources are the key building blocks for any FPGA design. +Resources are physically distributed across 3 different logic regions (SLRs) on both platforms, due to the nature of the FPGA architecture. +The FPGA devices on the Alveo U200 platform and AWS F1 instance have very similar numbers of available resources and performance is expected to be comparable across both platforms. + +The slight variance in resources is due to inherent differences between the shells for each platform. As shown in the figure below, the size and layout of the shell vary between the Alveo U200 platform and the AWS F1 instance. +Physical shell differences may impact the layout of available resources across the devices. +Developers should keep this in mind when migrating large and complex designs between the Alveo U200 platform and the F1 instances. +Advanced design considerations such as timing closure techniques may need to be considered. + +![img](./Alveo_to_AWS_F1_Migration/img/image02.png) + +For FPGA designs that utilize more than 70% of the FPGA resources, portability between platforms may require additional optimizations. +Please refer to the [UltraFast Design Methodology Timing Closure Quick Reference Guide (UG1292)](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_2/ug1292-ultrafast-timing-closure-quick-reference.pdf) for recommendations on timing closure. + +### Clock Frequency + +Both the Alveo U200 platform and F1 instances will support data clock rates up to 250MHz. +Applications running at 250MHz and below will seamlessly port between both platforms. +In addition, the Alveo U200 platform can support data clock rates between 250Mhz and 300MHz. +The data clock is used to transfer data between kernels and DDR, and deltas in clock rate may impact performance. + + +### Off-Chip DDR Memory + +Both the Alveo U200 platform and F1 instances provide identical off-chip DDR memory: 4 banks of 16GBytes each for a total of 64GBytes. +It is important to note that the placement and identification of DDR banks vary across platforms. +On the Alveo U200 platform, the DDR interface placed in the shell is DDR1. +On F1 instances the equivalent DDR interface placed in the shell is DDR0. +If the application only needs a single DDR interface, it is recommended to use the dedicated controller located in the shell. + +The following table details the naming and location of DDR interfaces on the F1 instances and Alveo U200 platforms: + +| **AWS name** | **Vitis tag** | **Location** | **U200 Equivalent** | +| --------------- | ---------------| ----------------------------- | --------------------- | +| DDR A | DDR[1] | SLR2 (top SLR) | DDR[3] | +| DDR B | DDR[2] | SLR1 (mid SLR) | DDR[2] | +| DDR C | DDR[0] | SLR1 (mid SLR, shell region) | DDR[1] | +| DDR D | DDR[3] | SLR0 (bottom SLR) | DDR[0] | + +The same information can be extracted from the platform file using the `platforminfo` Vitis utility: + +```bash +# Run this after you have sourced vitis_setup.sh +platforminfo $AWS_PLATFORM +``` + +When building the FPGA design, the Vitis linker takes care of connecting kernel ports to DDR interfaces. +For both the Alveo U200 and F1 instances, Vitis will default to use the DDR interface placed in the shell. +This default behavior can be modified by using command line options to specify which DDR interfaces should be used for each connection. +This is especially useful when the FPGA design needs to access multiple DDR banks. +When migrating applications between the Alveo U200 platform and F1 instances updates may be required to the Vitis compilation script to achieve the desired DDR mapping. +The example provided at the end of this document explains how to do update the Vitus scripts for DDR mapping. + + +## Migration Results using Vitis 2020.1 + +To demonstrate the seamless migration path offered by Vitis as well as the potential impact on the performance of the differences between the Alveo U200 platform and F1 instances, we ran over 40+ full system level applications across both platforms. + +For the vast majority of these designs, migrating between the Alveo U200 platform and the F1 instances require zero code changes (to either the host application or the kernel code). Porting the design was as simple as changing a few command line options in the Vitis compilation scripts such as the --platform and --sp switches. See [here](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/vitiscommandcompiler.html#qcm1528577331870__section_N10049_N10019_N10001) and [here](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/vitiscommandcompiler.html#clt1568640709907__section_tfc_zxm_1jb) for more details about these options. + +In a few cases, the host application relied on the XCL_MEM_TOPOLOGY flag, and this flag had to be modified to port between the Alveo 200 platform and F1 instances. This optional flag can be used to explicitly specify in which DDR bank a given buffer needs to be allocated. See [here](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/optimizingperformance.html#utc1504034308941) for more details about this flag. + +The following table shows results for a subset of these applications and compares the performance of each kernel (CU), looking at both the duration and primary kernel clock frequency. All these applications could be easily ported between the Alveo U200 platform and F1 instances maintaining application performance. + +| **TEST CASE** | **KERNEL NAMEs** | **CU Time AWS F1 (ms)** | **CU Time Alveo U200 (ms)** | **CU Clock AWS F1 (MHz)** | **CU Clock Alveo U200 (MHz)** | +| ----------------------------------------------- | ---------------------- | ----------------------- | --------------------------- | ------------------------- | ----------------------------- | +| Data Analytics (Bayes classification training) | naiveBayesTrain_kernel | 0.5491 | 0.5114 | 250 | 279 | +| Compression (gzip) | xilDecompressFull | 0.0335 | 0.0334 | 250 | 231 | +| | xilHuffmanKernel | 0.0435 | 0.0549 | 250 | 231 | +| | xilLz77Compress | 0.0203 | 0.0324 | 250 | 231 | +| Compression (zlib) | xilDecompressFull | 0.0254 | 0.0440 | 245 | 243 | +| | xilHuffmanKernel | 0.0440 | 0.0535 | 245 | 243 | +| | xilLz77Compress | 0.0211 | 0.0358 | 245 | 243 | +| Database (Compound Sort) | SortKernel | 1.1088 | 1.2326 | 250 | 234 | +| Quantitative Finance (BlackScholes) | bs_kernel | 0.0566 | 0.0541 | 250 | 300 | +| Quantitative Finance (BlackScholesMerton) | bsm_kernel | 0.2469 | 0.1984 | 250 | 280 | +| Quantitative Finance (HestonFD) | fd_kernel | 744.6795 | 704.1600 | 156 | 169 | +| Quantitative Finance (MonteCarlo) | mc_euro_k | 0.1351 | 0.1198 | 250 | 300 | +| Quantitative Finance (MonteCarloDJE) | kernel_mc_0 | 0.5365 | 0.4587 | 250 | 300 | +| Quantitative Finance (PortfolioOptimisation) | po_kernel | 0.1678 | 0.2154 | 138 | 115 | +| Quantitative Finance (b76) | b76_kernel | 0.5407 | 0.4251 | 250 | 300 | +| Quantitative Finance (cds) | CDS_kernel | 0.0489 | 0.0459 | 250 | 300 | +| Quantitative Finance (fdbslv) | fd_bs_lv_kernel | 2.3244 | 1.8575 | 250 | 300 | +| Quantitative Finance (hcf) | hcf_kernel | 0.2393 | 0.2144 | 250 | 300 | +| Matrix Solver (gesvdj) | kernel_gesvdj_0 | 0.2579 | 0.2595 | 250 | 273 | +| Matrix Solver (gesvj) | kernel_gesvj_0 | 0.0201 | 0.0377 | 250 | 300 | +| Computer Vision (Color detection) | color_detect | 0.0785 | 0.0755 | 250 | 300 | +| Computer Vision (Pixel pipeline) | pp_pipeline_accel | 0.1603 | 0.1459 | 250 | 300 | +| Computer Vision (Gaussian difference) | gaussiandiference | 33.5225 | 28.0049 | 250 | 300 | +| Computer Vision (Letterbox) | letterbox_accel | 0.0344 | 0.0394 | 250 | 300 | +| Computer Vision (Stereo vision pipeline) | stereopipeline_accel | 11.6349 | 9.7058 | 250 | 300 | +| Computer Vision (Corner Tracker) | cornerTracker | 0.2409 | 0.2160 | 250 | 300 | + +It should also be noted that these results only look at kernel performance, some of which are able to run the full clock rate available, for the F1 instances this is up to 250MHz and for the Alveo U200 platform, this is 300MHz. +Algorithms such as Compression libraries implemented in hardware can be seen to have nearly identical performance as the maximum clock rates are not quite achievable for these libraries. +Additional system level application advantages of either the Alveo U200 platform or F1 instances are not captured with this benchmark. + + +## Migration Example + +A detailed working example walking through all the steps required to migrate an application from U200 to F1 instances can be found [here](./Alveo_to_AWS_F1_Migration/example/README.md). + +In this example, the source code for the software program and the FPGA kernels remains identical whether targeting U200 or F1 instances. +Only command line changes are necessary to port the application. + +The Vitis flow leverages dedicated compilation steps to build the software program and FPGA accelerators. These steps are described below. + + + +### Compiling the software program + +The software program is compiled exactly in the same way in both case: + +```bash +g++ -D__USE_XOPEN2K8 -I/$(XILINX_XRT)/include/ -I./src -O3 -Wall -fmessage-length=0 -std=c++11 ../src/host.cpp -L/$(XILINX_XRT)/lib/ -lxilinxopencl -lpthread -lrt -o host +``` + +The software program is linked with the XRT libraries which manages the specific requirements of each FPGA platform, allowing the source code to remain the same for U200 and F1. + +See [here](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/buildinghostprogram.html#asy1528754332783) for more details about building the host program for the Vitis flow. + + +### Compiling the FPGA binary + +When building the FPGA binary only a few options need to be changed when retargeting from U200 and F1 instances. These options are contained in a specific file (called options.cfg in our example) and which is passed to the Vitis v++ compiler with the `--config` command line option. + +Here is a side-by-side view of the both options.cfg files: + +| Contents of options.cfg for Alveo U200 | Contents of options.cfg for AWS F1 | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| platform=xilinx_u200_xdma_201830_2
[connectivity]
sp=vadd_1.in1:DDR[1]
sp=vadd_1.in2:DDR[1]
sp=vadd_1.out:DDR[1] | platform=xilinx_aws-vu9p-f1_shell-v04261818_201920_2
[connectivity]
sp=vadd_1.in1:DDR[0]
sp=vadd_1.in2:DDR[0]
sp=vadd_1.out:DDR[0] | + +The platform option specifies which acceleration platform is targeted for the build. + +The `sp` option is used to specify the assignment of kernel interfaces to DDR interfaces. The original U200 design is connecting the kernel interfaces to DDR[1] which is located in the shell. Keeping the same settings would produce a working design on F1 instances, but in order to produce exactly the same configuration and target the DDR interface located in the F1 shell, the `sp` options are modified to use DDR[0]. + +Putting all the platform specific options in a dedicated file allows the v++ build commands remain strictly identical: + +```bash +// Step 1: compile the kernel from source code +v++ -c -g -t hw -R 1 -k vadd --profile_kernel data:all:all:all --profile_kernel stall:all:all:all --save-temps --temp_dir ./temp_dir --report_dir ./report_dir --log_dir ./log_dir --config ./options.cfg -I../src ../src/vadd.cpp -o ./vadd.hw.xo + +// Step 2: link the compiled kernel with the shell and produce the FPGA binary +v++ -l -g -t hw -R 1 --profile_kernel data:all:all:all --profile_kernel stall:all:all:all --temp_dir ./temp_dir --report_dir ./report_dir --log_dir ./log_dir --config ./options.cfg -I../src vadd.hw.xo -o add.hw.xclbin +``` + +See [here](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/vitiscommandcompiler.html#wrj1504034328013) for more information about the v++ command line options and configuration files. + + + +### Creating the Amazon FPGA Image + +Once you have compiled the host program and the FPGA binary, you are ready to execute the FPGA-accelerated application on a server equipped with an Alveo U200 acceleration card. + +When targeting F1 instances, you need to go through the additional step of creating an Amazon FPGA Image (AFI). This is done with the `create_vitis_afi.sh` command provided by AWS. This command reads in the FPGA binary generated by the v++ linker and requires information about the user’s AWS S3 bucket. + +In this example, the command looks as follows: + +```bash +$AWS_FPGA_REPO_DIR/Vitis/tools/create_vitis_afi.sh -xclbin=./vadd.xclbin -o=./vadd -s3_bucket= -s3_dcp_key=f1-dcp-folder -s3_logs_key=f1-logs +``` + +For more details about the `create_vitis_afi.sh` command, you can consult the AWS documentation [here](https://github.com/aws/aws-fpga/blob/master/Vitis/README.md#2-create-an-amazon-fpga-image-afi). + + + +## Summary – Migration Checklist + +Because Vitis provides platform-independent APIs and interfaces to the developer, the process of migrating applications across similar FPGA acceleration cards is greatly facilitated. + +The following summarizes the main requirements and techniques involved in migrating from Alveo U200 to F1 instances and can be used as a checklist to help along the process. + +#### Mandatory changes +* Update the --platform option in the Vitis compilation script – more details [here](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/vitiscommandcompiler.html#qcm1528577331870__section_N10049_N10019_N10001) +* Create an Amazon FPGA Image (AFI) from the FPGA binary (.xclbin) generated by Vitis – more details [here](https://github.com/aws/aws-fpga/blob/master/Vitis/README.md#2-create-an-amazon-fpga-image-afi) + +#### Design specific changes related to DDR mapping +* Use the --sp option to specify the assignment of kernel interfaces to DDR banks – more details [here](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/vitiscommandcompiler.html#clt1568640709907__section_tfc_zxm_1jb) +* Use the XCL_MEM_TOPOLOGY flag in the host source code – more details [here](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/optimizingperformance.html#utc1504034308941) + +#### Design specific changes related to timing closure +* Use the --frequency option to override the default clock frequency defined on the hardware platform– more details [here](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/vitiscommandcompiler.html#qcm1528577331870__section_frk_xtr_t3b) +* Use the –slr option to map kernels to specific SLRs in the device in order to help with timing closure – more details [here](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/vitiscommandcompiler.html#clt1568640709907__section_m3v_qxm_1jb) +* Apply advanced Vivado options to optimize implementation results - more details [here](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/buildingdevicebinary.html#hnw1523048617934) and [here](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_2/ug1292-ultrafast-timing-closure-quick-reference.pdf). diff --git a/Vitis/docs/Alveo_to_AWS_F1_Migration/example/README.md b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/README.md new file mode 100644 index 00000000..9aa4ec39 --- /dev/null +++ b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/README.md @@ -0,0 +1,149 @@ +# Alveo U200 to AWS F1 Migration Example + +This example illustrates how to port a Vitis application developed for an Alveo U200 card to an AWS EC2 F1 instance. + +The Vitis development flow provides platform independent APIs and interfaces to the developer. This greatly facilitates the process of migrating applications across similar FPGA acceleration cards. In this example, the source code for the software program and for the FPGA kernels remains unchanged. Only command line changes are necessary to port the application from Alveo U200 to AWS F1. + + +## Example Overview + +The accelerator used in this example is a simple vector-add kernel. The `src` directory contains the source code for the project: + +- `vadd.cpp` contains the C++ source code of the accelerator which adds 2 arbitrarily sized input vectors. +- `host.cpp` contains the main function running on the host CPU. The host application is written in C++ and uses OpenCL™ APIs to interact with the FPGA accelerator. + +The `u200` and `f1` directories contain the Makefiles and scripts for building for Alveo U200 and AWS F1 respectively. + + + +## Building for Alveo U200 + +*Note: The instructions below assume that the required tools and platforms are installed and that the environment is properly setup to run Vitis.* + +1. Go to the `u200` directory + +2. The example is built with the following commands: + + ```bash + g++ -D__USE_XOPEN2K8 -I/$XILINX_XRT/include/ -I./src -O3 -Wall -fmessage-length=0 -std=c++11 ../src/host.cpp -L/$XILINX_XRT/lib/ -lxilinxopencl -lpthread -lrt -o host + + v++ -c -g -t hw -R 1 -k vadd --config ./options.cfg --profile_kernel data:all:all:all --profile_kernel stall:all:all:all --save-temps --temp_dir ./temp_dir --report_dir ./report_dir --log_dir ./log_dir -I../src ../src/vadd.cpp -o ./vadd.hw.xo + + v++ -l -g -t hw -R 1 --config ./options.cfg --profile_kernel data:all:all:all --profile_kernel stall:all:all:all --temp_dir ./temp_dir --report_dir ./report_dir --log_dir ./log_dir -I../src vadd.hw.xo -o add.hw.xclbin + ``` + + * The `g++` command compiles the host program and links it with the Xilinx Runtime (XRT) libraries. XRT provides platform-independent APIs to interact with the FPGA, allowing the source code to remain the same for U200 and F1. + * The `v++ -c` command compiles the source code for vector-add kernel (vadd.cpp) and generates the compiled kernel object (.xo). + * The `v++ -l` command links the compiled kernel to the shell and produces the FPGA binary (.xclbin file) which can then be loaded on the U200 acceleration card. + +3. For both `v++`commands, the `--config` option is used to pass the name of a file called `options.cfg` containing additional options specific to building for U200. The `options.cfg` file contains the following options: + + ``` + platform=xilinx_u200_xdma_201830_2 + [connectivity] + sp=vadd_1.in1:DDR[1] + sp=vadd_1.in2:DDR[1] + sp=vadd_1.out:DDR[1] + ``` + + * The `platform` option specifies which acceleration platform is targeted for the build. Here we are using the U200 shell. + * The `sp` options are used to specify the assignment of kernel arguments to DDR banks. In this case, we are mapping all three kernel arguments to DDR[1], which is the DDR interface located in the shell on Alveo U200. + + > Putting all the platform-specific options in one file is not mandatory but it is very convenient and facilitates the porting process. With this approach, the main command line can be reused as is for all platforms. Refer to the [Vitis Documentation](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/kme1569523964461.html) for more information on v++ related commands and options. + +4. The Makefile provided in the directory can be used to build the project for U200. Running `make build` will build the host application, compile the kernel and finally create the FPGA binary for U200. + + +## Building for AWS F1 + +In order to port the vector-add example from Alveo U200 to AWS F1, the only change required is in the `options.cfg` file. The source code remains unchanged and the g++ and v++ commands remain identical. + +1. Go to the `f1` directory + +2. The `options.cfg` file for AWS F1 contains the following options: + + ``` + platform=xilinx_aws-vu9p-f1_shell-v04261818_201920_2 + [connectivity] + sp=vadd_1.in1:DDR[0] + sp=vadd_1.in2:DDR[0] + sp=vadd_1.out:DDR[0] + ``` + + * The `platform` option is set to target the AWS F1 shell. The string used corresponds to the name of the latest shell which can be found [here](https://github.com/aws/aws-fpga/tree/master/Vitis/aws_platform) on the aws-fpga repo. + * The `sp` options are set to connect the kernel arguments to DDR[0], which is the DDR interface located in the AWS F1 shell. Keeping the same settings as the U200 would produce a working design on AWS F1. But in order to produce exactly the same configuration and target the DDR interface located in the AWS F1 shell, the sp options are modified to use DDR[0]. + + These changes are the only ones needed to port this project from U200 to F1. + +3. You can build the project for AWS F1 using the exact same commands that were used for U200: + + ```bash + export PLATFORM_REPO_PATHS=/home/centos/src/project_data/aws-fpga/Vitis/aws_platform + + g++ -D__USE_XOPEN2K8 -I/$XILINX_XRT/include/ -I./src -O3 -Wall -fmessage-length=0 -std=c++11 ../src/host.cpp -L/$XILINX_XRT/lib/ -lxilinxopencl -lpthread -lrt -o host + + v++ -c -g -t hw -R 1 -k vadd --config ./options.cfg --profile_kernel data:all:all:all --profile_kernel stall:all:all:all --save-temps --temp_dir ./temp_dir --report_dir ./report_dir --log_dir ./log_dir -I../src ../src/vadd.cpp -o ./vadd.hw.xo + + v++ -l -g -t hw -R 1 --config ./options.cfg --profile_kernel data:all:all:all --profile_kernel stall:all:all:all --temp_dir ./temp_dir --report_dir ./report_dir --log_dir ./log_dir -I../src vadd.hw.xo -o add.hw.xclbin + ``` + + *NOTE: The PLATFORM_REPO_PATHS environment variable is used to specify the directory where the AWS platform (xilinx_aws-vu9p-f1_shell-v04261818_201920_2) is installed.* + +4. When targeting AWS F1, you need to go through the additional step of creating an Amazon FPGA Image (AFI). This is done with the `create_vitis_afi.sh` command provided by AWS. More information about this command is available on the [AWS documentation](https://github.com/aws/aws-fpga/blob/master/Vitis/README.md#2-create-an-amazon-fpga-image-afi). + + Use the command below to generate the AFI and the .awsxclbin file: + + ```bash + $AWS_FPGA_REPO_DIR/Vitis/tools/create_vitis_afi.sh -xclbin=./vadd.xclbin -o=./vadd -s3_bucket= -s3_dcp_key=f1-dcp-folder -s3_logs_key=f1-logs + ``` + + *NOTE: Make sure to use your S3 bucket information when running the create_vitis_afi command.* + + Check the status of the AFI creation process by using the AFI ID with the follow command: + + ```bash + aws ec2 describe-fpga-images --fpga-image-ids + ``` + + The AFI is ready to use when the state is reported as 'available'. + + ```json + "State": { + "Code": "available" + }, + ``` + + *NOTE: The AFI ID can be found in the _afi_id.txt file created by the create_vitis_afi command.* + + + +## Running the Application on AWS F1 + +1. Execute the following command to source the Vitis runtime environment + + ```bash + source $AWS_FPGA_REPO_DIR/vitis_runtime_setup.sh + ``` + +2. Execute the host application with the .awsxclbin FPGA binary + + ```bash + ./host vadd.awsxclbin + ``` + +3. The messages below will indicate that the program ran successfully. + + ```bash + Found Platform + Platform Name: Xilinx + INFO: Reading ./vadd.awsxclbin + Loading: './vadd.awsxclbin' + TEST PASSED + ``` + + +## Summary + +In the Vitis flow, the user can develop source code which remains mostly agnostic of platform-specific platform details. This greatly facilitates the process of migrating applications across similar FPGA acceleration cards. In this example, the same source code could be ported from Alveo U200 to AWS F1 without any changes at all. Only a couple of changes to the v++ compilation options were required. + +For a complete application migration checklist, refer to the [Migration between Alveo U200 platform & Amazon EC2 F1 instances](../../Alveo_to_AWS_F1_Migration.md) application note. diff --git a/Vitis/docs/Alveo_to_AWS_F1_Migration/example/f1/Makefile b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/f1/Makefile new file mode 100644 index 00000000..28023dbd --- /dev/null +++ b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/f1/Makefile @@ -0,0 +1,48 @@ +TARGET := hw + +build: xclbin host + +run: build + ./host ./vadd.xclbin + +vadd.xo: ../src/vadd.cpp + v++ -c -g -t $(TARGET) -R 1 -k vadd \ + --profile_kernel data:all:all:all \ + --profile_kernel stall:all:all:all \ + --save-temps \ + --temp_dir ./temp_dir \ + --report_dir ./report_dir \ + --log_dir ./log_dir \ + --config ./options.cfg \ + -I../src \ + ../src/vadd.cpp \ + -o ./vadd.xo + +vadd.xclbin: vadd.xo + v++ -l -g -t $(TARGET) -R 1 \ + --profile_kernel data:all:all:all \ + --profile_kernel stall:all:all:all \ + --temp_dir ./temp_dir \ + --report_dir ./report_dir \ + --log_dir ./log_dir \ + --config ./options.cfg \ + -I../src \ + vadd.xo \ + -o vadd.xclbin + +host: ../src/host.cpp ../src/host.hpp + g++ -D__USE_XOPEN2K8 \ + -I$(XILINX_XRT)/include/ \ + -I./src \ + -O3 -Wall -fmessage-length=0 -std=c++11\ + ../src/host.cpp \ + -L$(XILINX_XRT)/lib/ \ + -lxilinxopencl -lpthread -lrt \ + -o ./host + +xclbin: vadd.xclbin + +xo: vadd.xo + +clean: + rm -rf temp_dir log_dir report_dir *log host vadd.* *.csv *summary .run .Xil vitis* xclbin *.protoinst *.wdb *.wcfg diff --git a/Vitis/docs/Alveo_to_AWS_F1_Migration/example/f1/options.cfg b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/f1/options.cfg new file mode 100644 index 00000000..a5eca86f --- /dev/null +++ b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/f1/options.cfg @@ -0,0 +1,6 @@ +platform=xilinx_aws-vu9p-f1_shell-v04261818_201920_2 +[connectivity] +sp=vadd_1.in1:DDR[0] +sp=vadd_1.in2:DDR[0] +sp=vadd_1.out:DDR[0] + diff --git a/Vitis/docs/Alveo_to_AWS_F1_Migration/example/src/host.cpp b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/src/host.cpp new file mode 100644 index 00000000..1b426733 --- /dev/null +++ b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/src/host.cpp @@ -0,0 +1,183 @@ +/********** +Copyright (c) 2018, Xilinx, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**********/ + +#include "host.hpp" + +int main(int argc, char** argv) +{ + if (argc != 2) { + std::cout << "Usage: " << argv[0] << " " << std::endl; + return EXIT_FAILURE; + } + + std::string binaryFile = argv[1]; + size_t vector_size_bytes = sizeof(int) * DATA_SIZE; + cl_int err; + unsigned fileBufSize; + // Allocate Memory in Host Memory + std::vector> source_in1(DATA_SIZE); + std::vector> source_in2(DATA_SIZE); + std::vector> source_hw_results(DATA_SIZE); + std::vector> source_sw_results(DATA_SIZE); + + // Create the test data + for(int i = 0 ; i < DATA_SIZE ; i++){ + source_in1[i] = rand() % DATA_SIZE; + source_in2[i] = rand() % DATA_SIZE; + source_sw_results[i] = source_in1[i] + source_in2[i]; + source_hw_results[i] = 0; + } + +// OPENCL HOST CODE AREA START + +// ------------------------------------------------------------------------------------ +// Step 1: Get All PLATFORMS, then search for Target_Platform_Vendor (CL_PLATFORM_VENDOR) +// Search for Platform: Xilinx +// Check if the current platform matches Target_Platform_Vendor +// ------------------------------------------------------------------------------------ + std::vector devices = get_devices("Xilinx"); + devices.resize(1); + cl::Device device = devices[0]; + +// ------------------------------------------------------------------------------------ +// Step 1: Create Context +// ------------------------------------------------------------------------------------ + OCL_CHECK(err, cl::Context context(device, NULL, NULL, NULL, &err)); + +// ------------------------------------------------------------------------------------ +// Step 1: Create Command Queue +// ------------------------------------------------------------------------------------ + OCL_CHECK(err, cl::CommandQueue q(context, device, CL_QUEUE_PROFILING_ENABLE, &err)); + +// ------------------------------------------------------------------ +// Step 1: Load Binary File from disk +// ------------------------------------------------------------------ + char* fileBuf = read_binary_file(binaryFile, fileBufSize); + cl::Program::Binaries bins{{fileBuf, fileBufSize}}; + +// ------------------------------------------------------------- +// Step 1: Create the program object from the binary and program the FPGA device with it +// ------------------------------------------------------------- + OCL_CHECK(err, cl::Program program(context, devices, bins, NULL, &err)); + +// ------------------------------------------------------------- +// Step 1: Create Kernels +// ------------------------------------------------------------- + OCL_CHECK(err, cl::Kernel krnl_vector_add(program,"vadd", &err)); + +// ================================================================ +// Step 2: Setup Buffers and run Kernels +// ================================================================ +// o) Allocate Memory to store the results +// o) Create Buffers in Global Memory to store data +// ================================================================ + +// ------------------------------------------------------------------ +// Step 2: Create Buffers in Global Memory to store data +// o) buffer_in1 - stores source_in1 +// o) buffer_in2 - stores source_in2 +// o) buffer_ouput - stores Results +// ------------------------------------------------------------------ + +// ....................................................... +// Allocate Global Memory for source_in1 +// ....................................................... + OCL_CHECK(err, cl::Buffer buffer_in1 (context,CL_MEM_USE_HOST_PTR | CL_MEM_READ_ONLY, + vector_size_bytes, source_in1.data(), &err)); +// ....................................................... +// Allocate Global Memory for source_in2 +// ....................................................... + OCL_CHECK(err, cl::Buffer buffer_in2 (context,CL_MEM_USE_HOST_PTR | CL_MEM_READ_ONLY, + vector_size_bytes, source_in2.data(), &err)); +// ....................................................... +// Allocate Global Memory for sourcce_hw_results +// ....................................................... + OCL_CHECK(err, cl::Buffer buffer_output(context,CL_MEM_USE_HOST_PTR | CL_MEM_WRITE_ONLY, + vector_size_bytes, source_hw_results.data(), &err)); + +// ============================================================================ +// Step 2: Set Kernel Arguments and Run the Application +// o) Set Kernel Arguments +// ---------------------------------------------------- +// Kernel Argument Description +// ---------------------------------------------------- +// in1 (input) --> Input Vector1 +// in2 (input) --> Input Vector2 +// out (output) --> Output Vector +// size (input) --> Size of Vector in Integer +// o) Copy Input Data from Host to Global Memory on the device +// o) Submit Kernels for Execution +// o) Copy Results from Global Memory, device to Host +// ============================================================================ + int size = DATA_SIZE; + OCL_CHECK(err, err = krnl_vector_add.setArg(0, buffer_in1)); + OCL_CHECK(err, err = krnl_vector_add.setArg(1, buffer_in2)); + OCL_CHECK(err, err = krnl_vector_add.setArg(2, buffer_output)); + OCL_CHECK(err, err = krnl_vector_add.setArg(3, size)); + +// ------------------------------------------------------ +// Step 2: Copy Input data from Host to Global Memory on the device +// ------------------------------------------------------ + OCL_CHECK(err, err = q.enqueueMigrateMemObjects({buffer_in1, buffer_in2},0/* 0 means from host*/)); + +// ---------------------------------------- +// Step 2: Submit Kernels for Execution +// ---------------------------------------- + OCL_CHECK(err, err = q.enqueueTask(krnl_vector_add)); + +// -------------------------------------------------- +// Step 2: Copy Results from Device Global Memory to Host +// -------------------------------------------------- + OCL_CHECK(err, err = q.enqueueMigrateMemObjects({buffer_output},CL_MIGRATE_MEM_OBJECT_HOST)); + + q.finish(); + +// OPENCL HOST CODE AREA END + + // Compare the results of the Device to the simulation + bool match = true; + for (int i = 0 ; i < DATA_SIZE ; i++){ + if (source_hw_results[i] != source_sw_results[i]){ + std::cout << "Error: Result mismatch" << std::endl; + std::cout << "i = " << i << " CPU result = " << source_sw_results[i] + << " Device result = " << source_hw_results[i] << std::endl; + match = false; + break; + } + } + +// ============================================================================ +// Step 3: Release Allocated Resources +// ============================================================================ + delete[] fileBuf; + + std::cout << "TEST " << (match ? "PASSED" : "FAILED") << std::endl; + return (match ? EXIT_SUCCESS : EXIT_FAILURE); +} + diff --git a/Vitis/docs/Alveo_to_AWS_F1_Migration/example/src/host.hpp b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/src/host.hpp new file mode 100644 index 00000000..2f294f4d --- /dev/null +++ b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/src/host.hpp @@ -0,0 +1,85 @@ +#define CL_HPP_CL_1_2_DEFAULT_BUILD +#define CL_HPP_TARGET_OPENCL_VERSION 120 +#define CL_HPP_MINIMUM_OPENCL_VERSION 120 +#define CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY 1 +#define CL_USE_DEPRECATED_OPENCL_1_2_APIS + +//OCL_CHECK doesn't work if call has templatized function call +#define OCL_CHECK(error,call) \ + call; \ + if (error != CL_SUCCESS) { \ + printf("%s:%d Error calling " #call ", error code is: %d\n", \ + __FILE__,__LINE__, error); \ + exit(EXIT_FAILURE); \ + } +#define DATA_SIZE 4096 + +#include +#include +#include +#include +#include + +template +struct aligned_allocator +{ + using value_type = T; + T* allocate(std::size_t num) + { + void* ptr = nullptr; + if (posix_memalign(&ptr,4096,num*sizeof(T))) + throw std::bad_alloc(); + return reinterpret_cast(ptr); + } + void deallocate(T* p, std::size_t num) + { + free(p); + } +}; + +std::vector get_devices(const std::string& vendor_name) { + + size_t i; + cl_int err; + std::vector platforms; + OCL_CHECK(err, err = cl::Platform::get(&platforms)); + cl::Platform platform; + for (i = 0 ; i < platforms.size(); i++){ + platform = platforms[i]; + OCL_CHECK(err, std::string platformName = platform.getInfo(&err)); + if (platformName == vendor_name){ + std::cout << "Found Platform" << std::endl; + std::cout << "Platform Name: " << platformName.c_str() << std::endl; + break; + } + } + if (i == platforms.size()) { + std::cout << "Error: Failed to find Xilinx platform" << std::endl; + exit(EXIT_FAILURE); + } + + //Getting ACCELERATOR Devices and selecting 1st such device + std::vector devices; + OCL_CHECK(err, err = platform.getDevices(CL_DEVICE_TYPE_ACCELERATOR, &devices)); + return devices; +} + +char* read_binary_file(const std::string &xclbin_file_name, unsigned &nb) +{ + std::cout << "INFO: Reading " << xclbin_file_name << std::endl; + + if(access(xclbin_file_name.c_str(), R_OK) != 0) { + printf("ERROR: %s xclbin not available please build\n", xclbin_file_name.c_str()); + exit(EXIT_FAILURE); + } + //Loading XCL Bin into char buffer + std::cout << "Loading: '" << xclbin_file_name.c_str() << "'\n"; + std::ifstream bin_file(xclbin_file_name.c_str(), std::ifstream::binary); + bin_file.seekg (0, bin_file.end); + nb = bin_file.tellg(); + bin_file.seekg (0, bin_file.beg); + char *buf = new char [nb]; + bin_file.read(buf, nb); + return buf; +} + diff --git a/Vitis/docs/Alveo_to_AWS_F1_Migration/example/src/vadd.cpp b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/src/vadd.cpp new file mode 100644 index 00000000..805daffd --- /dev/null +++ b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/src/vadd.cpp @@ -0,0 +1,111 @@ +/********** +Copyright (c) 2018, Xilinx, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**********/ + +/******************************************************************************* +Description: + HLS pragmas can be used to optimize the design : improve throughput, reduce latency and + device resource utilization of the resulting RTL code + This is vector addition example to demonstrate how HLS optimizations are used in kernel. +*******************************************************************************/ + + +#define BUFFER_SIZE 1024 + +/* + Vector Addition Kernel Implementation + Arguments: + in1 (input) --> Input Vector1 + in2 (input) --> Input Vector2 + out (output) --> Output Vector + size (input) --> Size of Vector in Integer + */ +extern "C" { +void vadd( + const unsigned int *in1, // Read-Only Vector 1 + const unsigned int *in2, // Read-Only Vector 2 + unsigned int *out, // Output Result + int size // Size in integer + ) +{ +// SDAccel kernel must have one and only one s_axilite interface which will be used by host application to configure the kernel. +// Here bundle control is defined which is s_axilite interface and associated with all the arguments (in1, in2, out and size), +// control interface must also be associated with "return". +// All the global memory access arguments must be associated to one m_axi(AXI Master Interface). Here all three arguments(in1, in2, out) are +// associated to bundle gmem which means that a AXI master interface named "gmem" will be created in Kernel and all these variables will be +// accessing global memory through this interface. +// Multiple interfaces can also be created based on the requirements. For example when multiple memory accessing arguments need access to +// global memory simultaneously, user can create multiple master interfaces and can connect to different arguments. +#pragma HLS INTERFACE m_axi port=in1 offset=slave bundle=gmem +#pragma HLS INTERFACE m_axi port=in2 offset=slave bundle=gmem +#pragma HLS INTERFACE m_axi port=out offset=slave bundle=gmem +#pragma HLS INTERFACE s_axilite port=in1 bundle=control +#pragma HLS INTERFACE s_axilite port=in2 bundle=control +#pragma HLS INTERFACE s_axilite port=out bundle=control +#pragma HLS INTERFACE s_axilite port=size bundle=control +#pragma HLS INTERFACE s_axilite port=return bundle=control + + unsigned int v1_buffer[BUFFER_SIZE]; // Local memory to store vector1 + unsigned int v2_buffer[BUFFER_SIZE]; // Local memory to store vector2 + unsigned int vout_buffer[BUFFER_SIZE]; // Local Memory to store result + + + //Per iteration of this loop perform BUFFER_SIZE vector addition + for(int i = 0; i < size; i += BUFFER_SIZE) + { + int chunk_size = BUFFER_SIZE; + //boundary checks + if ((i + BUFFER_SIZE) > size) + chunk_size = size - i; + + // Transferring data in bursts hides the memory access latency as well as improves bandwidth utilization and efficiency of the memory controller. + // It is recommended to infer burst transfers from successive requests of data from consecutive address locations. + // A local memory vl_local is used for buffering the data from a single burst. The entire input vector is read in multiple bursts. + // The choice of LOCAL_MEM_SIZE depends on the specific applications and available on-chip memory on target FPGA. + // burst read of v1 and v2 vector from global memory + read1: for (int j = 0 ; j < chunk_size ; j++){ + v1_buffer[j] = in1[i + j]; + } + read2: for (int j = 0 ; j < chunk_size ; j++){ + v2_buffer[j] = in2[i + j]; + } + + // PIPELINE pragma reduces the initiation interval for loop by allowing the + // concurrent executions of operations + vadd: for (int j = 0 ; j < chunk_size; j ++){ + #pragma HLS PIPELINE II=1 + //perform vector addition + vout_buffer[j] = v1_buffer[j] + v2_buffer[j]; + } + //burst write the result + write: for (int j = 0 ; j < chunk_size ; j++){ + out[i + j] = vout_buffer[j]; + } + } +} +} diff --git a/Vitis/docs/Alveo_to_AWS_F1_Migration/example/u200/Makefile b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/u200/Makefile new file mode 100644 index 00000000..28023dbd --- /dev/null +++ b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/u200/Makefile @@ -0,0 +1,48 @@ +TARGET := hw + +build: xclbin host + +run: build + ./host ./vadd.xclbin + +vadd.xo: ../src/vadd.cpp + v++ -c -g -t $(TARGET) -R 1 -k vadd \ + --profile_kernel data:all:all:all \ + --profile_kernel stall:all:all:all \ + --save-temps \ + --temp_dir ./temp_dir \ + --report_dir ./report_dir \ + --log_dir ./log_dir \ + --config ./options.cfg \ + -I../src \ + ../src/vadd.cpp \ + -o ./vadd.xo + +vadd.xclbin: vadd.xo + v++ -l -g -t $(TARGET) -R 1 \ + --profile_kernel data:all:all:all \ + --profile_kernel stall:all:all:all \ + --temp_dir ./temp_dir \ + --report_dir ./report_dir \ + --log_dir ./log_dir \ + --config ./options.cfg \ + -I../src \ + vadd.xo \ + -o vadd.xclbin + +host: ../src/host.cpp ../src/host.hpp + g++ -D__USE_XOPEN2K8 \ + -I$(XILINX_XRT)/include/ \ + -I./src \ + -O3 -Wall -fmessage-length=0 -std=c++11\ + ../src/host.cpp \ + -L$(XILINX_XRT)/lib/ \ + -lxilinxopencl -lpthread -lrt \ + -o ./host + +xclbin: vadd.xclbin + +xo: vadd.xo + +clean: + rm -rf temp_dir log_dir report_dir *log host vadd.* *.csv *summary .run .Xil vitis* xclbin *.protoinst *.wdb *.wcfg diff --git a/Vitis/docs/Alveo_to_AWS_F1_Migration/example/u200/options.cfg b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/u200/options.cfg new file mode 100644 index 00000000..c48bf33d --- /dev/null +++ b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/u200/options.cfg @@ -0,0 +1,6 @@ +platform=xilinx_u200_xdma_201830_2 +[connectivity] +sp=vadd_1.in1:DDR[1] +sp=vadd_1.in2:DDR[1] +sp=vadd_1.out:DDR[1] + diff --git a/Vitis/docs/Alveo_to_AWS_F1_Migration/img/image01.png b/Vitis/docs/Alveo_to_AWS_F1_Migration/img/image01.png new file mode 100644 index 0000000000000000000000000000000000000000..b760d4c09b15fd58adef8821e9e8c1b2bf9d2caa GIT binary patch literal 40763 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 IWK4tp1v{uGXaE2J literal 0 HcmV?d00001 diff --git a/Vitis/docs/Alveo_to_AWS_F1_Migration/img/image02.png b/Vitis/docs/Alveo_to_AWS_F1_Migration/img/image02.png new file mode 100644 index 0000000000000000000000000000000000000000..d0fc2bd278bc9e7dd63fa17bc51e942300965db5 GIT binary patch literal 19341 zcmeIacQ}>*A3uI*5Qzqgj8Y1rvMP>ELuDR&B-yJnJ9eQVNrjL-&#|&MrBJfBbBxN~ z^Vs9}ys7u6?||+}}b|e4s^C~4gHwxvM`v3m@zZ(atX6tpM-JgWNEaqjDt+vNDJ)3Ldy#r*4F++TXntftdD+jdN4?uR_R}mCr(K7Q){$zV&rx{yq*iZv|6dltplaW;-p;jYu@iYqE#i=u8!GF{3YY57IsP=-9 z^%GJ@7RzRVzr?QSq~GF#9v8%fJm28rJ-pAGSzG5;RdIH-Je$!}QXOX_Teh{Z9N*yZ zmJ^FKTPti|IaF~n^ybRdZzA6E?A3QO-v+@9H0%5! zQXVCloRi0yn*J(Mp8Xu9zvQdaZ?7{RCqq&Csc{?E)$x|?W*m@zV$R1m|R% z6hnG*c0uGua&gK$yuA83-z88eDMo+!)RK}~6ezgdi`cv6gEuYTd@*Ih!J*Nt31mM89pUHkKZneFZB zmS$#moVii#g4#OABB{Lh!N9<48b6nP(MXA+^tZp##&Ep<@3d6jl~Y$&uj!^m-sp#a z%?-F|#p6cGf%n=*4k#2I1J0iChHFgt&)go`XK7(!xPA9S&*Oz!MV9{zSRzK%@5Rae zihEGr^6_alew8oW{=BGP`K)wQ*y&0q=nChDuHeH`3N$AH}G z_pEnr&POb~wO9_;!bo*zUW`PrQ-#A;4d|turnsxb{66>bhOoMDkp{lPfkSHxEs7h* z2HvW1|9Z?3b5OETP(+02zBXyfarIS>Y2>4-D7}%@@r?XxR+rk4*S2rI$LHp3xT7d3 zq>V%#&3!*Jspzr#mgeaBPvWa19L!hjlhGRsEmMUAg0{===Vz>@x(m}^t{?KZaJJxr z3ElmIy#L~lbNv-kT3Vt0OhPrc#b#ymmr|2s7DyciP62@)cQcbQ>gqe=>G)R1rm(Ue zy`)>bI+kKx;l0msFi3;&nS#yAwv-f1n(8593YyGX4g6gXJwKvpXh;Sx5G}So^JOu- zZ@p@&Y|W;4kzi>}$T1f-s@h*X66@DJKR7rD6Y-msgAHfXFMODidNZu}Ij6T}ueL9i zr9ooLmFUo+H`%6Pko)_t@TWQr*u3fneRptbHBn@qk^G0A7wA{L91PZ}w<(#GXFNGw zx}>i$-E=g#{P%1DMx*1;lOOi^O0+HSq3QU3^uk?l7ROFQ$4_JwogD@qw+6$KP6j6H zNCmM;c(Qkygj-wHf4H0;l9`*^7NKLF5M#ttM)jMhtQj^h-6vuCST+R#)(fEZgm-JMOl&m>X_e)@4!` zX6)eLu$kI5?Y<@>5>?zCupj95@m(B{oy-}Lgd z(#4E3yeikmtu@U$v(yzagEwsLoX;iWa#6hS>6^5ZZ2xVf=Le0@U3s^%RRyhSye$Ar3i>3Dka z`mupA~O(?v+%`IiqoLLE_JH2&>++cyzBadmOB zUjg;_Rb%HZ&f6c%Og}vEoh;wlOdrg};lAe)ZA3ey*I+qzvbs$C%8)HnrZqA#5I|AB z`2O|`5q8b=nDCzJ(xqPFEAdsc{Ftrf+5XA7AN-~~II-Z{NrbVyg6+a-B+@h^!^^}@ zc&j{kOStPRtMgAUx#7Sl!Rffn%;!)T$mOQ>HdaaVr|sypIOH8kKA z&zwG8Y18}E7e_9sc{579r`L77jl3mSN@rP|@?0XCbgLG03LC3eN ztJrV>(^qv7qDvIjkM~epZLY7_%%TR8Dk{i_1js3m(@3<|{A3vyVhQCHd0kFLP1T*p zjH>V|AF{dVx_qDc(*0ETRHEpVY<7W!f)~JT&{dll!Z7REx zL1*GB448j(VgD=9)YQ~ksF`uRB0~+PKWLDq)-!-hihLNuPP|~*evXkf(1VJKiucej z#eVsqb#KB@cZj?VfS_Ce2NQm8p_JG+@UR$$Q1O*+A(ddc9auf zyZ){bFsc1`kVC!`wv6SODAz3XLZi%-*j#|{=XNSPiy#V5_G2P8ABdj})@Upn#5>j7vl=JZD*N}Pq@?WNjtNdh@s;?}wW;E~4tX!Y#Za(>oznMPTkiFA&I7DR}@{&r%%K_Z{owxlWXR`}46 z7}V(&7=X7o6VLS$pp|deg-G{RbH<|@TE_JGcgLVWSwZ8pZ=hkh(mH8O`hF&=;Nsj5 zsLM54k*t!@B@4|8dCfO?x}bK9*VvZK`daSSgX-C{hBN|`w`UX`8%}JQIdkjSpngfg z=A0j@%kC|8DXwM;!`H1-&@c_u#P)Jx!{*+)FKS1!q8`f<<#11x)vDcA21A7JeWTN0 zXfrR#AI!)}I2ZYInAUp_bPlVJpZ6jgbZI&8Dr+Xay5{Fq()e)Am|^R0G6nw993GBx zGcyZSRRRCKC~{+{l@Ch&<~G-+iw_E>q!;0N{Ny{6hYzlB^@e@K4hfRSAP@GG&Ap&> zW07c+QMKKiac^m;^&8th((;4#OT<2b9oxAM$sYzJ5cp}RW z7Jt`N@${504)3)PwY8pPd9>%QAFtJXoyd{~N1trmK^`tHK=J@sCphtHxf=aXXvNK1 zk`(iAiS)EaG*}fs_~}Jaba77cT;9jK#y@CKQg);^jbfkPoH}2I%7eE)UxG!`BYo+c zLEyEoH8nK|c6<;*@E1%{rrvcfw^e2HWfzN6cc$4vvVk+!g-wl(-vG#Z<;+$w7sud_ z5gcW7uAeA3pRNZ8vxCEcpP&m2`?9%q9|NVVkGOvRuI&OSN=M5@K z+RZSp<1N9={{FXi@T8?>#n{-`U*PN~OU29J*GxpP?6vq$X$KClA4hlrPKB43_p~56 zN}7YoUkke3Uo4r^BX4b8nxMkvu@~ie$I{$9_tE?i0+R0B+zo^LT zIKbD`)Rzb_ooRGb0ch|SE}LswoD5tzjY2)<54us*whd4KUOS7~+`6@m@@a*9+dKY; zicg4bzruAvrrZ}V{sX=z11Z;#2bFW73wihMzp(+tZ_)X17mALR@X%XPAVQh_m^@6Uei=i5ZERWfj2qRVq%*9&Xte+ zViq~d`*~isnU%%g-@lpi1EZ$4L%u32<=QiB+5Q_joCNdQE>wkV8xw|^j`a^_Pfbtv z`U#^?bF28hL^qu*z*8%JZi}LUVhCql%;%9S|ni9eFi1R6OSf8epv)2*WmI z7#JW=+MPgtIrt{0o+1bG&W3?E6Vq~i{$r!tjD>T1Sp+`Q(bJ3g%h&)uLr>oxZzepk zrsl`a0^4;~<>+hx-Cn$AZU}wM1zkKh&pHQci-vf>M^TU|bMB(FQRl}^=}qoy0-StG z!hP5R8m62NavTSJ1$;f-A5-}g8g8T{pFG}*YHV%2*XJr)9eLEFSb{oQfKk`pA1yE# zg_J=}?$8C(gZHS%^PW}Sy*%-}L#7b@(s=)@;^av54zT4v_wjhkm~JJ&|- zX$-a7a`&mrNY6{l>;5`9`SgBcFthduFT=PNDU94m)hI5)WlC#tt#7M$GU#PgQgZS) z{YS>WrOOrboBQYX#ay_9z~MUAL30D?qd7S~Ra^k>5a5uRCo%xImGWZGyVmyh+&xwM zglC_hS=T~ET%J$O6dn-aAx3%-x}wP3^>}&fgsnQyi!L;NNi8h=9#!d~s;zC3-;4FT z_2F7+aKO>`$0ffX`QlU|o07z-%HSt z&6-4Om&UXfZV>|?ZrOZO1j;>fm+!nvHu*Oro2aUGhJOkduXjs|M&ZtMLnSNH^wK%9 zU-HsS$9|Bo_!3rD9URbhw>dnwKstb*>)}6s{507@iBuE#azusdB?d#kvtGBq=H*Qj zwsp__-wk!8h+7EU*}nS57gZi^>>vFAg^E^4P`PetXy<{Tv+c{D%QlBGh3_mfG8C#Y z0o0(NkdQxx2)SZMv)E|?Ah=0}GzT-=4b{%?Y;5Ek+~>~a{Jx82^7;sJ0dh&@U1ccB z(%!)A;hlo6ok}e$`@FN0kXPaky{QFg@_&!42Eq$zyrbivUx~P_b20Rv548Y2>T%ef ze_p)F4BE+!9rXL>$&*Rk{5x1<=Rs#$|Bt4DQ@f#K^S9_D&l&XY2=SBGu7BP>XHb5- zk|O#H@@f`PmsjS8{~3cS{Oe_cisLfr3{%v4Y>0yWW*k$FlgVeEU zF~E#yAU?o+rhwuS&Eov6IzJjZwkluk0>)D^a#YCTo&Pa`sL*j%Cobu8(VGr>HmYh$Tzx&cKEYb7N)d1eP;$U{>T z#x9tNyrV#Qp6>*NJJBdZOFDfg2Gq%X4GyHoIA-JV+>ETE_>>eoipG{vd3MkM0dx88tNHO$T6}VNr2*4%(n_EETAI$yewYR)DP@t^q$u~IHD=h8r!J9Sj=f^l z7%k-plT%3l2^gObZE$yF&B5JsCAlIZ%cr)-4W z4t+}@AtAo6qe=}=uzgi!1Ri^c zuV!&MD`1$3wvqShR_QkdzUKP9`>ZF~uDu1mO^8+zC0Ew`q1{<*>JP8D()*KJFpF>; zdu5~7!VU=N-j0zN$)v)UMOs$o<_`iov`kruumtq@<82OI1UNYv7a;y{EgyGgZYbQ= z@w19Z@GN?;pdgFO_duZ!K3#=-zLw8-x+Db?SYT#9S1-&%5Zhog16W#D$JH z9BY+^{-a91(gl_L3(nQ7S5fGvV;Qe#L_^teS8mZLOv;>|^BbcTI!C^(Gd5YgU7If7 ziami1qmE@|3KDWv^!r(|G8DdP5pCK?6XkBu<`RAX(xbV1qVu%^lir7Ke=MFV`q7IW z=Vd(JwhLz|AoA==(uow1#0n!^=e~m)_q1@&1=!HmL$#q(CMq%Wu%bSCY>XS&u)Z6T zLxjoFGT#dPQ)O=`L8T0rJ!$Um z@4wS4dIo$L^)*{p@sV=q`kac-dtUq4I)DTI5yUH!(lY@T3>Srj^Xq@SPuXGC&6-ym&Cgpto+iZJ3*VtO%h( zX|>724gyrs!9K!Xe5^J20uvrTdA`*p-N#B+x&h$$~V zOW$CgvCm`6%?Si6(J4!iA_?mH`kPN0DCmxdwWRv851eUZoFCTM>5_}6qRjR@=1_g6 z=%mK!c!p0+C8z2Ptk|d=WTN%wFzQ;Byzk;pn8!-KZ`yp|vbqjUeCYvn7aP`AgUvZc zr?by2zK!d+eY?xcAW?TIw=o6FEZqU|0WuOu00G z@TNb~W$J;2q_H|q9}X2@6iwyn8I`GE&4_j81xF7wtE!Cv!c} z=7G}WCYooTak=8EwY~_soFp;aW5{c|uSQ}&TVVcd^tT`XRHVk`I8dhQp0?5$t>qux z$bT_(#n?gpba0T#rqU}Rl^I1rAgS;)lg<7((SR!G{%$9Z4FnK8kbVjuGyo$ zO(EuC+vg`%UweyJ1t_1W;V02zp;@u41=erIPEJasuFT_|X6DVPc_(9TmIg=bJG~JdqX+@-$kQhTl-|b$?p29hLi>VRYvRNqodi zF)C#|SlfaNk^Xh*+AjM@HZv)QCQ!ytBA1G^NLw_Le-dA@x7#uPR)rM=Ie4=G)b@w11V^ zoJZxpB=cXi$3z`dturebZ0es5J;Xi6D4qh465Sa(2umIslD@KA=h@7d6K zJjuF}Uc=s)H>|1awHP2rZXr+nQ)Q&=<@IV==eFr;WziU1bvH9Nw=Q17{neP5Z3<#; zMT&Ky+fR}`p`guk-&if21Jj^iIw6>g0>w@#+<9kLNAX#FwfM$@>RO$xdwlduq`X6;A*s9}t~5pU)VPN7=Yur5q<;IJ-%hwt=l;(A=%-*K1do3_33zKuRfS zqzr8>%e4Xxoq*Acl1U^`KJ%U*KEoH*M~RYD(tY^-^frP=x~<0=v9J3wN!-Fq#G1=z zJ?N%IN}~EU9jvm6r>O%2$_-JCC5&vS5AZSo<)BN;ZP!lkxFAEc8Ig2v$-9|KMT_WM z+r){%PYcslu?I!Ao9)kc4sqrD{(bi!epzSwLBzJ~f86TBV$5FfWOm5P@82iKiTMHl z`>EQ=z?{THlmA_hlRaq&7S%sI3*?jWp5pv}u91?80aEzSHNn9QuyFoiYuxAJlMYfI z2B{4g?z{=mv@ZpVGrOmy7{_4yCg zNn^4sH&u+qS}gmo1qr90r$Of~k`-xJ;1YU>(zAazK(gLJpe znBxwPW0a>9R!#sjiSF#~wz3qubisS5yjcjI%%Z%k58G zINYjk;O3xX5^6jFd~91=M~pRC0aMyORbZR(Q#~qwC*6;T??40`y_Aj7kr$0$K%ByZ ze&)xY`?k)jt21oYZM69%-AQcByYrcRZ9Zztih|WS8g`LQ9+=ggO;_2h!>#i|T{Z## zu1VP%ah~VCHdeA(m(|qKG+&gyp`_7dcO~kPb(4`B4fa?Q=8r&;so9Dp)dXDjr}7_D zJ}&0`(Yk0f(b}-ER>CN+RYjrDE-fu>aWpAPTS39k!^BWi?W3iYmA#BkIT)c!g)A~L z6$$ljFpN`IO65&E$jUk0i7=Io31Q(nVDuK29kCg!8*fVq*%+4CdQkfOjn`B=6Id5-Y`F`NaNVFW<`^v(VY?Hc&9Uq*3KXKGuxGr|WzF_SUprw-XQ-mBl4W+_aqs%&#~%0GgZERDyR%yF4!958 zChx@y{j%2V5tngpg0`%~GE}ZRZEbCffZcnlUa^c<^dsgT0297TCa?Cl(b|@+B-XvZ z@a6WUU%T_~*TWEx523-Rt4u$m?C_l7N7FbBP=oZMG45ipm#m`P7Bhz<0}x7Db`vIKLuKV(7r(aG5|p>)axJE4bsu7dwrnE^RLNLlaTY1~mGkE<$YL z~4TI6i1`nwM{KON2dut((G{&ty>G3syZ$H&JR@>Yf zeYw0&Px0<^KHfG|t=j9Kz9@FiH>ebnOAJmk>KbP>xc+F@w#&_9zB?&UEowN!t9x8t z>YCrLh4{6g$B(5orps1V1(`D&%JdE~$;BxDx;eeUl!#w>iV%Fai2K^Rtxk z-Jc1Lq{x2EFyezVQYGN=H3u&JL@};b`7@icxh(`T`{I=fAR$paADa=^(YDAMcQwE< z=3V161Lprj_S8Ie=z0g8=Zu;E8LRQh#T@en@qq@^NNuQ56@g%xW>P$Lr8Y`RQ&2=m z=eqfGe$pv(qD4xYUWUE~NzmekG-s=EBDdLRCZB5Hg4N(|lj#@-VY+MZKX~&$tQGuz z!Bh0;CGdl(dF;~Eq`E=dc=FR($b;mA(O+L$hCMBiKf#?MqGD+G_1VEZ-~`1dQoQBY z!``%1@x5HACDww2yEPJ` z`o5(Gr~Szt^GHL^mlhfFX^}-!MdL+ns+N|PJ!VI~yH32E+P9!R_f%s2GmQ}% zLA^27VmW8)i$!i8& ztNT*?s!8LG^PwEs4pj{?VLv;yFmClA?MTnGmYK!B9Qh;INy zdEU5tHz~FV6*(e4@b$NxT{-40-S;&jwjlH|0g_z~0y8o)s!V@&$RlAe+eM2|=$c@4 zk14mfKQT;Vm1^rJJW-ZW%JuP87i1AIdATuZ>tXlhdX($jbs~r})?m^(b&S~^;qI~c zY#ku5pedsxFzhfHtYc#yZk6>sJkGhxIHYicl^=+GM+$D`C8$*ku^lSWwIz|P!dUl*TDpEp$S#;Go3bf#jX8oRicfUL-nIU=)%T85VOzEZg~3Vuxa>50wp- z_oQv1LqyH0lLfy3ty+iaJ$((Si}PWto#OXRB0D;QYCEhw>i8?ia4Y^p6ztV%hRMwq z2B8ouyGOWjLSk%h-W*CvO^ptLxnp8NxBM}H5MSyDg8&5zWf*5 zO%#f9mv!L<(|X+BQUReM1bVop4fx@1Lskyn8OiWCg zXe5xCHVYzQ+J8w(8P&Jn)rcI(;~sCecF>6x+R^PO2Q&qlvYVUl@|^v-ZP0;hfF*Gw zCPB3xcjGRzd)(XhoK(c{iHeP@pxIkGGO znL(XXDtER+ojWm7diqKTe7@XHGHRYP2@3k-&`7=lCA91D9--hH=6f*U&t?=BR+=DLM1V@%1THy@6sk!Y{NZx87> zTfWi09o4w}Fh1fz)v-|1U*LMD=MdH91-hpwGJbs$vLD1-)X=Q}uw zQ!ZgUz`Xc7)UW~U5h%TK2rXeAHqh6%0h#0_4dn4?6xTs;fDqFe?KdT0w|!fiOO8Nu382Fd zssCubFI)GZ^*p9-D>);>$?MRH>94zF6JW_{=5;?*aGA{QumagK{eWs|qD+8L19*;+ zAFcDcs*r3>k-r<0*9>w~Bm@?$=cq+APm0(^WJo6Cz~uotqD}GS1mMif3r1C%P;)on z>Fet1)Kyh~z#x$ugEZ#2*kxL*EQsVawxf$*4_@t@`SnFl&uJpFnjp_?J&++^W)4;r z0IWYzro%K{g};26CqhjlAJC718a((4I#VZ2Ul$;O_btImIX%AGMo?|&1c5Ys1WfL- z7*f7oiTDsAx+D;qvP((rI*!fP&nRaMW?nn>TVpQ;-Cpoe7C-_c*fpR{Q$SG~e{>wO zJJygoL@; z4C%55u+On2-%!oKXoU0f&BzimIN*gBYn?%^I*3M2@KQYfwU9b=* zK!>y=US+Xwlv3Bx8CNIodo&!;<9NK)az$ZW7`)#dCh7PVF;>*UJPrrOLM$GGw9SJb zZ&U8J%|wEr(1NHuK<=LhpVqj4N|2oL4Pv_>$)ZKpGQc0*C05pjnGmTd=1tUhUojT3 zWn1A2y;*p94XMDLw*+@%f|7h^CW^+>ZO+Cr&?(UlK)h%ouTRpw`9nZ&X-fAEI~3g! zHjnkpw9G1|^i7qx5zcU{-&jVWo0$2f5Y4;$V4#$*U(W=v{t2mmNc_r65`6;+y~wEK z#&XYvV~@5;D=Kn$vMZOiZ@MXv!kDBW8+YGh@5;?`=E-Rn)NW=76eXJ~r`$6!!(@`} zGV}TZ=_bMHCy<~rQwuRx%7{Tjo3ZV6-EK46(M+47QBFje@A*)rm2J|shf((qR2O{2 z{fd2#U`i5@L^5pDrq{;244)xH^H`SSl)lG?gDBz;LOwbFDJ%9HQVcXQ%!~aGD~dHC z(#8>g`S;je-jwh>$3emZWxdo3h-oKR(ud!9y~%idmblxh=5%kVN8??;^%z#Ox(%?4 zDGym6bLf6hUFh}W;6E`fdN}!xL>sFH&1rSU=U1Cs3=h&6@r>XYh|y2!2xdur>xW+OTjO$W0zlq9VC) z&0nP9mI^ocz;HCkqDZs=?T`Khb@$ie{STMz5+$Cv#`=)wMA1X|wL+G|N{~dpa{Wt) zj<)uWEa8Ik@eK=OTH5Qk9v7n*6jVB5yqk_23T=AQz7M5yz-?~v3`pD((t+7lrt>7kY}ie#^> z=LWu)WDH)|wvXFXi@ysri1jm+n3sR{aM?w1AO}3OPHr9#Y|sUDMH;q^ePhwpmvy1Z z8iIx$)dd^9W7H+2x22UmZ*z5=2(4(M!SPj_>KAjvp5UwsR_F4HG2E6!Y9xqX{$w&{ z``Oa?k`lh>M$ylEfDA{uF6LczA8d4oU#Yfz;+r=cq|Da0P6!T(OeqyNfdga?t8Fc| z&=R70B|2I+iPr2MxE|k?m#D{M-F6MRUD>9^)&120`H%qb35GorF5yuo`gA?Mh&MFe zW)~a^=)8qk&qP=^dZ+Qd@v4gGHr7W22VEALuBJIn_Xz$)0R3_4_?*JYK&#?Riw9|0u-g%52tuSTW4I*UN04*RtG_Z{Aa@_? zH=B-AkHaJwq)4Lh)FCcQt9wzmccPx4yg11?4uHPnkd`r?mLJJuN#+Hh(syovYtpE# zyZeUOZo0Ghj=i+36RaY_!UQDNXqlE9%#1z(GENEXwyRSY<`gf6e*7;NYons9YzVTG zL%`Nbg9ibT;fGwWT@1|`8?%6@_e0}>kl5Iha2UmK5Yl$BZDj&>#~9CP-T~!lC6}oIAOjX0kTO-KsKTssG_cJ5`bQOAO540 zK(Jucvk%mvGi^;)wn^Vax{f;KRreQQ|7&Or|9SqCfzMc6XFl7IeE>z?sEKoP%pCm3 zGuEFx$N)icGD!_4hTA;+qMqM*ms&&KU8Pk0(^)2V!DY+6 z4^!jg-}`UCnHUwdBiX$eYUXdC$|A>x%rzOeF=aD>DW9MX2+U9l;Pknm8#))S-vM<0 zlu7#S_jiBsF;j)AzJ5&!0yw`y6atU`3pj87XtfNwj3n18q~pxAwSVta0XWKZ=y~3Y zTpt8%!ZDQpj7~U%bW)jzkI!WL91NI$I>(M9a1svnRN@~&+Q-{xF^P|l?{C5`H6fu5 z(%?I(N9c5Sr2PLr6QM=o5ZAr!`=}+EukQJC4#<}6x2aq+e9YB;*4)je@-$5+o zXmT&OGpF{?I*HwM&It7pbWMu!;uS%mej&$>EG%{qAkciPsRrb*lcsE(4{~;7dvXEk zpJM=|ud+>9Vw;jlW0?OqfSp}RTZhOFtI*cbNh>P)d(^7%2=b}iVTn;UPXE0>45Fiq z^Y*|{*R@T`5O0)dLD>g-4GHnS0`Vu$MOT zpC~J@q(o0XZBUeu-2B+$F5Dj^qT47rGn$bRpQggg{X$#Mt)=4dy=tXvoNw|5gUhoi zrjHFHN>)OMf$gyVeV@wM3kvxgw4d`o+W6)AWa|q9kl`6IsQ?uQYGy&DEK;}WaI>eoD{yigwd`<^ z>7cfNY5jIrzb&z050q@dv|PltS8Q$EV9NrWZ-)SC15kuR5gpwTy3MM9#J1E8`5{}x zcaX?#L?Yf$p!2N@2ZIrPk60(tHxacGgB;5M?UmN42RMrft=NpG$Iw&c#E~c(YrtAI`U}92(XyqtisD^SE1A&ZtM%q#G}Z)07m}6Znw!i75tAheT+#9cDxTDz z=>Uw}*6FEpF@(_|4gD^3{tv$5c!~qZM_3J@$#1^!fk!A_02jX7&YIo>3!`WkK$K1_ zN1RmbbbBV`byfxXT3pH_k?78P=roH%tMXJKy@u|E4G4s-Wm97`G?IwYx*+o9-);yM zsE)dolyo!n4Iel6!zdB^k;Vmt{<)>h0U``#g)M3=Eq; z8||!rHF{Jn5y)+^;40n#Es4#QA62v$?N6D8a3caY4-Y?oKER3YL(jcEOpuhFWlC#m z+T#ZSE^qQ)G`Y1d1^Y*~ID}df$s-Y#o?f{OH1dAhchDf8BRYU%hn`axjK^d;h^1K^ zuP#;Op3N_%C;&H!gNB@5zXJ2C*E0wD>T*hXQc(f#*`jK^otmxXDWx@;j7*rQ0?UiY z84(@R2!{z^`uU`>HcRDF%INVK4IibN-Apv-w%1G;aR@k-iFO>rs4bXzB#c3 z>XZAzhx914OCB>Tepv01V`5%jI}$Wx95_p5T;HwizyD!fe>NQ%?nmwLj-xuSdP~&idBKUv-?4G8B^EN z8fDEFvFW~~!M2%yWnj2o54aVJ9y)>R2oqI!DDA#zOQ;Yx!m9JTAO0wObTlP3>jmO` zWr7&JYU*(_?G18N49RLbLPm2XyH9nx2Ug^?wzgb`6GR;dVV3Emj|re53=L`9uQO4Z zSUg|>Q*KS%eLlRepkdsq_Zz^fn)!Tmi-NZyD~ z?FD(}h|9DY1VHjZ80zr318zJCf{8`19U)7j1LsjU0J!Ec>N|f%j62LXz^+tk{jLYTZqmA3RbS1!xOXk7h?nnT6RQT(7F5kbobTL+olfQL$|qI$JUm) zAXhK3YEJbTv4)t*vfH&SH!NtfCCfMjPud?b+2;4h^aW*y^2;~U5Duz!raHw~B`8u` z;mpnVKO5W?d1J9OJ~Ej1aq|9INL&#U|CaMs7QpXrnr&wmIil(i6*rR$CP~o^ZEC_< z$yX4^ohsjQ7x`SCLUZim*FEI`Phgh;0c&wA8SjKo;_KGSXX|zUlvWS3Pvisyw+3DhG@s7jz z*SJwelsk*Jy!R{aGff}Wl;x6EXz^B%nGUU0V%T#IKJ~c&ejk~-&y6#RP3PG#c}zt( zyRpm`*Vmv3_F}YY(F?DOZ)YULTn_tj0ce(pE28madaU=e@x3?JNz38s0b$0m$DyMz zBZHZ|Nr@wu+etV;wa+6lNWC<$va+(h*vVGIM)8-5-K{IkHPon)V}fqdXm_UB*h2T% zgQuVDrFrNd6K3~5M)@?hp~3s&p7TBmG;8mSgSD#mpwnK2&4TCzj#tK{LZ2#n39(Dt z1mL_=WVq@|lElXM#Xb)Y(cuqv-D87Y_l7v|OG>3t+C8FnX3IG25n@XY6{=iZnnU{P zFQrl&IM1omI+lEb2in+so!vi^CLoVzvl&Z%rwVMQ0dah#npzhw!5&=L^blpg2{CAS zHv8^l^us1H+BGrlgt@p4U0P+^c+@G@cQdPYK|tPpD+TUb~OwjYkzJs?x`Po)ZE>cw*%u~0$}yq00OwKQ^8HG_-Y z;y@{uSKw(y5<|hR#tlk;${@>(()R6?cDx*KY?xon3njF57%_=zA<2xCk7%Ch4w(5< zN3LKpSso1pPCddD7`U$_Fc;x!6oLr1MJMke6Wb$3LsGJ!d^IFIW+xPo$+3r*w2(Vp zH*r=VBrbd7G!fwLs9*ukSVP84X#Xg3h;eK0F($s08->}QaLg#0Z2HnX>}g`Ytm#O( z0dI4tB^e6s$B_Dcfyx5!E$^TFO7#g|ouA%c{(Ivip^Fv<@}GkZ~u$fJ=I zjityC0Iw^ku~`^t;v3=W9F60Sto=|1Euq$}R-QN3LaMFgnl&b-F}dR~FK67Rq&g(%cOBW$%K1lHq*)p;8r+jtYFglY+=bN$T5$|<45dr>U^Z{t)&UeQg_?8zsK2GY5mu#D9P~a>4T9;G+Xa2w*J#z%50ikUTts8lUA^6r-fh7IwG-%AF=Hchu z=(PPwyjZwz z=pX~3BN*NS?e%B@Dj%u@CV66{bXL7_UdOj?O0!w7SN3VzQKCAxSx~QC@JWIav!D>z z$0-V4RU*ZRRx%SXS7cGH+Kg-_1u9Ok1-HGXDi@*L?5!!d_;p*O3CIw~Kgn6KF5} z^t1;9r~GbAp3-PKY{lyyVDkWQnSv);01YUTRnSZc3v!J@KIX${-iynnumTe$AVcnf zA)qyMbwAip-yH>sF&^^ZgZ5jS8!Z5J^U6;a!{Nlj26O7v(Y)7Vn`;E_d3$5y1eZEU zzKQoR%&oVXFKvu9F2!UtF>o@n7#kapN^FcOZr0eZLKRiWfH=)45@L1pcWBo-qo=GK z2**@@v{;|$Gzhxw0bb8&oiMSsRA1-lEn2W~-25Tbe5HrMbpr#N<{tc^iK)^e-hvf@ zh#w_M4G?^Zx}Fqp={Kd*ZHL>Y=_PYFmR!#<%$vGTK)ty^3!PRk32OpjM|)DpSZJBs zS|UFjOZFI~1?6M`eq~I28q!EGhGj@BumRJvC)$#JWQ(x*$x~8QF%nDL7K^_=Cm}Q; zS86hLS&cu!*9b4ChPIo`kN#E?sVyUs~F5VB&0bcTUD$A(ddo9deSUHF&>H zmZ$5hG7F8bwan;jIN=91zSt34W;8c+lB<=!Xy=kg>YvdW7ecY;w`M0TSzCw1xH)7$ z0#?;yPtj(e?Vu~jD~*1PH_D+fx*Fz}tbAVk++@)R&)1ZOqQPB z!OiYz18O!iR @@ -146,4 +147,4 @@ WARNING: card(s) marked by '*' are not ready, is MPD runing? run 'systemctl stat # Additional Documentation * [XRT Documentation](https://xilinx.github.io/XRT/master/html/) -* [XRT MPD Documentation](https://xilinx.github.io/XRT/master/html/cloud_vendor_support.html) \ No newline at end of file +* [XRT MPD Documentation](https://xilinx.github.io/XRT/master/html/cloud_vendor_support.html) diff --git a/Vitis/examples/xilinx_2020.1 b/Vitis/examples/xilinx_2020.1 new file mode 160000 index 00000000..6dc51743 --- /dev/null +++ b/Vitis/examples/xilinx_2020.1 @@ -0,0 +1 @@ +Subproject commit 6dc5174366f13e541af446213db0c98f401ba1e6 diff --git a/Vitis/kernel_version.txt b/Vitis/kernel_version.txt index 20429c73..eb0a1e6f 100644 --- a/Vitis/kernel_version.txt +++ b/Vitis/kernel_version.txt @@ -4,4 +4,5 @@ 3.10.0-957.5.1.el7.x86_64 3.10.0-957.27.2.el7.x86_64 3.10.0-1062.4.1.el7.x86_64 -3.10.0-1062.9.1.el7.x86_64 \ No newline at end of file +3.10.0-1062.9.1.el7.x86_64 +3.10.0-1127.10.1.el7.x86_64 diff --git a/Vitis/vitis_xrt_version.txt b/Vitis/vitis_xrt_version.txt index e37a320d..3c06762f 100644 --- a/Vitis/vitis_xrt_version.txt +++ b/Vitis/vitis_xrt_version.txt @@ -1 +1,4 @@ -2019.2:9e13d57c4563e2c19bf5f518993f6e5a8dadc18a \ No newline at end of file +2019.2:9e13d57c4563e2c19bf5f518993f6e5a8dadc18a +2020.1:12115fd4054cb46a5ade62fafa74c523f59116e6 +2020.1:d09c4a458c16e8d843b3165dcf929c38f7a32b6f + diff --git a/docs/examples/example_list.md b/docs/examples/example_list.md new file mode 100644 index 00000000..5cff1e6d --- /dev/null +++ b/docs/examples/example_list.md @@ -0,0 +1,28 @@ +## Example Applications List + +| Accelerator Application | Example | Development Environment | Description | +| --------|---------|---------|-------| +| Custom hardware | [cl\_hello\_world](../../hdk/cl/examples/cl_hello_world) | HDK - RTL (Verilog) | Simple [getting started example](../../hdk/README.md) with minimal hardware | +| Custom hardware | [cl\_dram\_dma](../../hdk/cl/examples/cl_dram_dma) | HDK - RTL (Verilog) | Demonstrates CL connectivity to the F1 shell and connectivity to/from all DDRs | +| Custom hardware | [IP integration example using a GUI - cl\_dram\_dma\_hlx](../../hdk/cl/examples/cl_dram_dma_hlx) | HLx - Verilog | Demonstrates CL connectivity to the F1 shell and connectivity to/from DRAM using the Vivado IP Integrator GUI | +| Custom hardware | [Virtual Ethernet Application](../../sdk/apps/virtual-ethernet) | [Streaming Data Engine](../../hdk/cl/examples/cl_sde) | The Virtual Ethernet framework facilitates streaming Ethernet frames from a network interface (or any source) into the FPGA for processing and back out to some destination. Possible use cases for this include deep packet inspection, software defined networking, stream encryption or compression, and more. | +| Custom hardware | [Pipelined Workload Applications - cl\_dram\_dma\_data\_retention](../../hdk/docs/data_retention.md)| [HDK](../../hdk/cl/examples/cl_dram_dma/software/runtime/test_dram_dma_retention.c) [SDAccel](../../SDAccel/examples/aws/data_retention) | Demonstrates how to preserve data in DRAMs while swapping out accelerators. Applications that use a temporal accelerator pipeline can take advantage of this feature to reduce latency between FPGA image swaps | +| High Level Synthesis | [Digital Up-Converter - cl\_hls\_dds\_hlx](../../hdk/cl/examples/cl_hls_dds_hlx) | HLx - C-to-RTL | Demonstrates an example application written in C that is synthesized to RTL (Verilog) | +| Custom Hardware with Software Defined Acceleration | [RTL Kernels](https://github.com/Xilinx/Vitis_Accel_Examples/tree/master/rtl_kernels) | Vitis - RTL (Verilog) + C/C++/OpenCL | These examples demonstrate developing new hardware designs (RTL) in a Software Defined workflow| +| Vitis Compression Libraries | [File Compression using GZip](https://github.com/Xilinx/Vitis_Accel_Examples/tree/master/library_examples/gzip_app) | Vitis - C/C++/OpenCL | This example demonstrates how to use Vitis Libraries to speed up GZIP compression on an FPGA | +| Vitis BLAS libraries | [Matrix Transposer using BLAS](https://github.com/Xilinx/Vitis_Accel_Examples/tree/master/library_examples/transp) | Vitis - C/C++/OpenCL | This example shows how to use Vitis BLAS Libraries to create a Matrix Transposer on an FPGA | +| Vitis Financial libraries | [Monte Carlo European Engine](https://github.com/Xilinx/Vitis_Accel_Examples/tree/master/library_examples/MCEuropeanEngine) | Vitis - C/C++/OpenCL | This example shows how to use Vitis Financial Libraries to accelerate MCEuropean Engine on an FPGA| + +## Application Notes + +App Note | Description | +|---------|---------| +| [Using PCIe Peer-2-Peer connectivity](https://github.com/awslabs/aws-fpga-app-notes/tree/master/Using-PCIe-Peer2Peer) | This app note shows how to use PCIe P2P connectivity on F1.16XL instances | +| [Using PCIM Port](https://github.com/awslabs/aws-fpga-app-notes/tree/master/Using-PCIM-Port) | This app note shows how to use the PCIM AXI port to transfer data between card and host memory | +| [Using PCIe User Interrupts](https://github.com/awslabs/aws-fpga-app-notes/tree/master/Using-PCIe-Interrupts) | This app note describes the basic kernel calls needed for a developer to write a custom interrupt service routine (ISR) and provides an example that demonstrates those calls | +| [Using PCIe Write Combining](https://github.com/awslabs/aws-fpga-app-notes/tree/master/Using-PCIe-Write-Combining) | This app note describes when to use write combining and how to take advantage of write combining in software for a F1 accelerator | + +## Workshops + +* [ReInvent:19 Workshop](https://github.com/awslabs/aws-fpga-app-notes/tree/master/reInvent19_Developer_Workshop) +* [ReInvent:18 Workshop](https://github.com/awslabs/aws-fpga-app-notes/tree/master/reInvent18_Developer_Workshop) diff --git a/hdk/docs/on_premise_licensing_help.md b/docs/on_premise_licensing_help.md similarity index 80% rename from hdk/docs/on_premise_licensing_help.md rename to docs/on_premise_licensing_help.md index cab84d18..d58903e6 100644 --- a/hdk/docs/on_premise_licensing_help.md +++ b/docs/on_premise_licensing_help.md @@ -1,39 +1,42 @@ - # Enabling on-premises development with Xilinx tools **NOTE: If you are developing on the AWS cloud and using AWS FPGA Developer AMI provided on AWS Marketplace, you can skip this document.** This document helps developers who choose to develop on-premises with specifying and licensing AWS-compatible Xilinx tools for use with the AWS FPGA HDK. +## Requirements for AWS HDK 1.4.16+ (2020.1) + * Xilinx Vivado or Vitis v2020.1 + * License: EF-VIVADO-SDX-VU9P-OP + * URL: https://www.xilinx.com/member/forms/download/xef.html?filename=Xilinx_Unified_2020.1_0602_1208.tar.gz + * MD5 SUM Value: b018f7b331ab0446137756156ff944d9 + + ## Requirements for AWS HDK 1.4.13+ (2019.2) + * Xilinx Vivado or Vitis v2019.2 + * License: EF-VIVADO-SDX-VU9P-OP + * URL: https://www.xilinx.com/member/forms/download/xef-vitis.html?filename=Xilinx_Vitis_2019.2_1106_2127.tar.gz + * MD5 SUM Value: d63bae9cad9bcaa4b2c7f6df9480eaa6 + ## Requirements for AWS HDK 1.4.11+ (2019.1) * Xilinx Vivado v2019.1 or v2019.1.op (64-bit) * License: EF-VIVADO-SDX-VU9P-OP - * SW Build 2552052 on Fri May 24 14:47:09 MDT 2019 - * IP Build 2548770 on Fri May 24 18:01:18 MDT 2019 * URL: https://www.xilinx.com/member/forms/download/xef.html?filename=Xilinx_SDAccel_2019.1_0524_1430_Lin64.bin * MD5 SUM Value: aa20eba36ebe480ec7ae59a4a8c85896 ## Requirements for AWS HDK 1.4.8+ (2018.3) * Xilinx Vivado v2018.3 or v2018.3.op (64-bit) * License: EF-VIVADO-SDX-VU9P-OP - * SW Build 2405991 on Thu Dec 6 23:36:41 MST 2018 - * IP Build 2404404 on Fri Dec 7 01:43:56 MST 2018 * URL: https://www.xilinx.com/member/forms/download/xef.html?filename=Xilinx_SDx_op_Lin_2018.3_1207_2324_Lin64.bin&akdm=0 * MD5 SUM Value: aa20eba36ebe480ec7ae59a4a8c85896 ## Requirements for AWS HDK 1.4.4+ (2018.2) * Xilinx Vivado v2018.2 or v2018.2.op (64-bit) * License: EF-VIVADO-SDX-VU9P-OP - * SW Build 2258646 on Thu Jun 14 20:02:38 MDT 2018 - * IP Build 2256618 on Thu Jun 14 22:10:49 MDT 2018 * URL: https://www.xilinx.com/member/forms/download/xef.html?filename=Xilinx_SDx_op_Lin_2018.2_0614_1954_Lin64.bin&akdm=0 * MD5 SUM Value: 6b6939e70d4fa90677d2c54a37ec25c7 ## Requirements for AWS HDK 1.3.7+ (2017.4) * Xilinx Vivado v2017.4.op (64-bit) * License: EF-VIVADO-SDX-VU9P-OP - * SW Build 2193838 on Tue Apr 10 18:06:59 MDT 2018 - * IP Build 2189296 on Tue Apr 10 19:39:46 MDT 2018 * URL: https://www.xilinx.com/member/forms/download/xef.html?filename=Xilinx_SDx_op_2017.4_0411_1_Lin64.bin&akdm=0 * MD5 SUM Value: e0b59c86d5ddee601ab17a069d231207 diff --git a/hdk/README.md b/hdk/README.md index 032d0859..f3b74fa9 100644 --- a/hdk/README.md +++ b/hdk/README.md @@ -27,9 +27,9 @@ * Familiarity with concepts related to designing for FPGAs, DMA, DDR, AXI protocol and linux drivers * RTL simulation * Experience with simulation debug or FPGA runtime waveform viewer debug methods -* Developers not familiar with these areas should start with [software defined acceleration](../SDAccel/README.md) -* Developers with existing RTL IP that are not familiar with the areas listed above should start with RTL Kernel development using [software defined acceleration](../SDAccel/README.md). -* Developers looking for a faster HDK development path, should start with RTL Kernel development using [software defined acceleration](../SDAccel/README.md) +* Developers not familiar with these areas should start with [software defined acceleration](../Vitis/README.md) +* Developers with existing RTL IP that are not familiar with the areas listed above should start with RTL Kernel development using [software defined acceleration](../Vitis/README.md). +* Developers looking for a faster HDK development path, should start with RTL Kernel development using [software defined acceleration](../Vitis/README.md) * The [documents directory](./docs) provides the specification for the AWS Shell (SH) to Custom Logic (CL) interface: * [Shell Interface](./docs/AWS_Shell_Interface_Specification.md) @@ -44,7 +44,8 @@ * Developers should not need to change any file under the `/common` directory * `shell_stable` directory contains the files needed by developers to build a CL using a current production shell. -* The [Custom Logic (cl) directory](./cl) is where the Custom Logic is expected to be developed (For RTL-based development using Verilog or VHDL). It includes a number of examples under the [examples directory](./cl/examples), as well as a placeholder for the developer's own Custom Logic under [developer_designs directory](./cl/developer_designs). For more details on the examples, see the [examples table](./cl/examples/cl_examples_list.md). +* The [Custom Logic (cl) directory](./cl) is where the Custom Logic is expected to be developed (For RTL-based development using Verilog or VHDL). It includes a number of examples under the [examples directory](./cl/examples), as well as a placeholder for the developer's own Custom Logic under [developer_designs directory](./cl/developer_designs). +For more details on the examples, see the [examples table](./cl/examples/cl_examples_list.md). ## Getting Started @@ -52,18 +53,19 @@ #### AWS Account, F1/EC2 Instances, On-Premises, AWS IAM Permissions, AWS CLI and S3 Setup (One-time Setup) * [Setup an AWS Account](https://aws.amazon.com/free/) -* Launch an instance using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) which comes pre-installed with Vivado and required licenses. Given the large size of the FPGA used inside the AWS FPGA instances, the implementation tools require 32GiB Memory (ex: c4.4xlarge, m4.2xlarge, r4.xlarge, t2.2xlarge). c4.4xlarge and c4.8xlarge would provide the fastest execution time with 30 and 60GiB of memory respectively. Developers who want to save on cost, would start coding and run simulations on low-cost instances, like t2.2xlarge, and move to the aforementioned larger instances to run the synthesis of their acceleration code. Follow the [On-Premises Instructions](docs/on_premise_licensing_help.md) to purchase and install a license from Xilinx. +* Launch an instance using the [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) which comes pre-installed with Vivado and required licenses. Given the large size of the FPGA used inside the AWS FPGA instances, the implementation tools require 32GiB Memory (ex: c4.4xlarge, m4.2xlarge, r4.xlarge, t2.2xlarge). c4.4xlarge and c4.8xlarge would provide the fastest execution time with 30 and 60GiB of memory respectively. Developers who want to save on cost, would start coding and run simulations on low-cost instances, like t2.2xlarge, and move to the aforementioned larger instances to run the synthesis of their acceleration code. Follow the [On-Premises Instructions](../docs/on_premise_licensing_help.md) to purchase and install a license from Xilinx. * The compatibility table describes the mapping of developer kit version to [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) version: | Developer Kit Version | Tool Version Supported | Compatible FPGA Developer AMI Version | |-----------|-----------|------| | 1.3.0-1.3.6 | 2017.1(Deprecated) | v1.3.5(Deprecated) | | 1.3.7-1.3.X | 2017.1(Deprecated) | v1.3.5-v1.3.X(Deprecated) | -| 1.3.7-1.3.X | 2017.4 | v1.4.0-v1.4.X (Xilinx SDx 2017.4) | -| 1.4.0-1.4.2 | 2017.4 | v1.4.0-v1.4.X (Xilinx SDx 2017.4) | -| 1.4.3-1.4.7 | 2018.2 | v1.5.0 (Xilinx SDx 2018.2) | -| 1.4.8-1.4.10 | 2018.3 | v1.6.0 (Xilinx SDx 2018.3) | -| 1.4.11-1.4.X | 2019.1 | v1.7.0 (Xilinx SDx 2019.1) | +| 1.3.7-1.4.15a | 2017.4 | v1.4.0-v1.4.X (Xilinx Vivado 2017.4) | +| 1.4.3-1.4.15a | 2018.2 | v1.5.0 (Xilinx Vivado 2018.2) | +| 1.4.8-1.4.15a | 2018.3 | v1.6.0 (Xilinx Vivado 2018.3) | +| 1.4.11-1.4.x | 2019.1 | v1.7.0 (Xilinx Vivado 2019.1) | +| 1.4.11-1.4.x | 2019.2 | v1.8.x (Xilinx Vivado 2019.2) | +| 1.4.16-1.4.x | 2020.1 | v1.9.x (Xilinx Vivado 2020.1) | * The FPGA Developer Kit version is listed in [hdk_version.txt](./hdk_version.txt) @@ -73,23 +75,31 @@ * [Setup AWS CLI and S3 Bucket](../SDAccel/docs/Setup_AWS_CLI_and_S3_Bucket.md) to enable AFI creation. * To install the AWS CLI, please follow the [AWS CLI Installation guide](http://docs.aws.amazon.com/cli/latest/userguide/installing.html). - + ``` $ aws configure # to set your credentials (found in your console.aws.amazon.com page) and default region + ``` Use the aws-cli [region](http://docs.aws.amazon.com/cli/latest/userguide/cli-command-line.html) command line argument to override the profile default region. Supported regions include: us-east-1, us-west-2, eu-west-1 and us-gov-west-1. #### Install the HDK and setup environment -The AWS FPGA HDK can be cloned to your EC2 instance or server by executing: +The AWS FPGA HDK can be cloned to your instance by executing: -When using the developer AMI: ```AWS_FPGA_REPO_DIR=/home/centos/src/project_data/aws-fpga``` +> When using the FPGA Developer AMI, add: +> `AWS_FPGA_REPO_DIR=/home/centos/src/project_data/aws-fpga` +```bash $ git clone https://github.com/aws/aws-fpga.git $AWS_FPGA_REPO_DIR $ cd $AWS_FPGA_REPO_DIR $ source hdk_setup.sh +``` -Note that sourcing `hdk_setup.sh` will set required environment variables that are used throughout the examples in the HDK. DDR simulation models and DCP(s) are downloaded from S3 during hdk setup. New terminal or xterm requires `hdk_setup.sh` to be rerun. +Sourcing `hdk_setup.sh` does the following: +* It sets required environment variables that are used throughout the examples in the HDK. +* Downloads DDR simulation models and DCP(s) from S3. + +New terminals or xterm require `hdk_setup.sh` to be rerun so that the correct environment variables are set. #### Review examples @@ -102,15 +112,18 @@ The [Examples readme](./cl/examples/cl_examples_list.md) provides an overview of #### Fast path to running CL Examples on FPGA Instance -For developers that want to skip the development flow and start running the examples on the FPGA instance. You can skip steps 1 through 3 if you are not interested in the development process. Step 4 through 6 will show you how to use one of the predesigned AFI examples. By using the public AFIs, developers can skip the build flow steps and jump to step 4. [Public AFIs are available for each example and can be found in the example/README](cl/examples/cl_hello_world/README.md#metadata). +For developers that want to skip the development flow and start running the examples on the FPGA instance. You can skip steps 1 through 3 if you are not interested in the development process. Step 4 through 6 will show you how to use one of the pre-designed AFI examples. +By using the public AFIs, developers can skip the build flow steps and jump to step 4. [Public AFIs are available for each example and can be found in the example/README](cl/examples/cl_hello_world/README.md#metadata). #### Step 1. Pick one of the examples and start in the example directory It is recommended that you complete this step-by-step guide using HDK hello world example. Next use this same guide to develop using the [cl\_dram\_dma](cl/examples/cl_dram_dma). When your ready, copy one of the examples provided and modify the design files, scripts and constraints directory. +``` $ cd $HDK_DIR/cl/examples/cl_hello_world # you can change cl_hello_world to cl_dram_dma, cl_uram_example or cl_hello_world_vhdl $ export CL_DIR=$(pwd) +``` Setting up the CL_DIR environment variable is crucial as the build scripts rely on that value. Each example follows the recommended directory structure to match the expected structure for HDK simulation and build scripts. @@ -121,20 +134,25 @@ Each example follows the recommended directory structure to match the expected s This [checklist](./cl/CHECKLIST_BEFORE_BUILDING_CL.md) should be consulted before you start the build process. **NOTE** *This step requires you to have Xilinx Vivado Tools and Licenses installed* - +``` $ vivado -mode batch # Verify Vivado is installed. +``` Executing the `aws_build_dcp_from_cl.sh` script will perform the entire implementation process converting the CL design into a completed Design Checkpoint that meets timing and placement constrains of the target FPGA. The output is a tarball file comprising the DCP file, and other log/manifest files, formatted as `YY_MM_DD-hhmm.Developer_CL.tar`. This file would be submitted to AWS to create an AFI. By default the build script will use Clock Group A Recipe A0 which uses a main clock of 125 MHz. +``` $ cd $CL_DIR/build/scripts $ ./aws_build_dcp_from_cl.sh +``` In order to use a 250 MHz main clock the developer can specify the A1 Clock Group A Recipe as in the following example: +``` $ cd $CL_DIR/build/scripts $ ./aws_build_dcp_from_cl.sh -clock_recipe_a A1 +``` Other clock recipes can be specified as well. More details on the [Clock Group Recipes Table](./docs/clock_recipes.csv) and how to specify different recipes can be found in the following [README](./common/shell_v04261818/new_cl_template/build/README.md). @@ -296,7 +314,7 @@ If fpga-describe-local-image API call returns a status 'Busy', the FPGA is still Now, let us try loading your AFI to FPGA `slot 0`: ``` - $ sudo fpga-load-local-image -S 0 -I agfi-0f0e045f919413242 + $ sudo fpga-load-local-image -S 0 -I agfi-0fcf87119b8e97bf3 ``` @@ -305,11 +323,10 @@ Now, let us try loading your AFI to FPGA `slot 0`: Now, you can verify that the AFI was loaded properly. The output shows the FPGA in the “loaded” state after the FPGA image "load" operation. The "-R" option performs a PCI device remove and recan in order to expose the unique AFI Vendor and Device Id. ``` $ sudo fpga-describe-local-image -S 0 -R -H - Type FpgaImageSlot FpgaImageId StatusName StatusCode ErrorName ErrorCode ShVersion - AFI 0 agfi-0f0e045f919413242 loaded 0 ok 0 + AFI 0 agfi-0fcf87119b8e97bf3 loaded 0 ok 0 0x04261818 Type FpgaImageSlot VendorId DeviceId DBDF - AFIDEVICE 0 0x6789 0x1d50 0000:00:0f.0 + AFIDEVICE 0 0x1d0f 0xf000 0000:00:1d.0 ``` @@ -338,7 +355,7 @@ Follow the [RTL simulation environment setup](./docs/RTL_Simulating_CL_Designs.m * Before starting your new design review the specification for the AWS Shell (SH) to Custom Logic (CL) [interface](./docs/AWS_Shell_Interface_Specification.md). * Try the [debug flow](docs/Virtual_JTAG_XVC.md) and understand the [shell timeout behavior](docs/HOWTO_detect_shell_timeout.md). -* When your ready, copy an example to [start your own CL design](./cl/developer_designs/Starting_Your_Own_CL.md) and make a simple modification to get familiar with customizing the hardware developer kit for your development needs. +* When you are ready, copy an example to [start your own CL design](./cl/developer_designs/Starting_Your_Own_CL.md) and make a simple modification to get familiar with customizing the hardware developer kit for your development needs. diff --git a/hdk/cl/examples/cl_hello_world/README.md b/hdk/cl/examples/cl_hello_world/README.md index fdf690af..213086ef 100644 --- a/hdk/cl/examples/cl_hello_world/README.md +++ b/hdk/cl/examples/cl_hello_world/README.md @@ -1,7 +1,7 @@ # Hello World CL Example -## :exclamation: NOTE: If this is your first time using F1, you should read [How To Create an Amazon FPGA Image (AFI) From One of The CL Examples: Step-by-Step Guide](./../../../README.md) first!! +## **⚠️ NOTE:** If this is your first time using F1, you should read [How To Create an Amazon FPGA Image (AFI) From One of The CL Examples: Step-by-Step Guide](./../../../README.md) first!! ## Table of Contents @@ -13,29 +13,24 @@ ## Overview -This simple *hello_world* example builds a Custom Logic (CL) that will enable the instance to "peek" and "poke" registers in the Custom Logic (CL). -These registers will be in the memory space behind AppPF BAR0, which is the ocl\_cl\_ AXI-lite bus on the Shell to CL interface. - +This *hello_world* example builds a Custom Logic (CL) that will enable the instance to "peek" and "poke" registers in the Custom Logic (CL). This example demonstrate a basic use-case of the Virtual LED and Virtual DIP switches. -All of the unused interfaces between AWS Shell and the CL are tied to fixed values, and it is recommended that the developer use similar values for every unused interface in the developer's CL. - - ## Functional Description -The cl_hello_world example demonstrates basic Shell-to-CL connectivity, memory-mapped register instantiations and the use of the Virtual LED and DIP switches. The cl_hello_world example implements two registers in the FPGA AppPF BAR0 memory space connected to the OCL AXI-L interface. The two registers are: +The cl_hello_world example demonstrates basic Shell-to-CL connectivity, memory-mapped register instantiations and the use of the Virtual LED and DIP switches. +The cl_hello_world example implements two registers in the [FPGA AppPF BAR0 memory space](../../../docs/AWS_Fpga_Pcie_Memory_Map.md) connected to the OCL AXI-L interface. +The two registers are: 1. Hello World Register (offset 0x500) 2. Virtual LED Register (offset 0x504) -Please refer to the [FPGA PCIe memory space overview](../../../docs/AWS_Fpga_Pcie_Memory_Map.md) - The Hello World Register is a 32-bit read/write register. However, in order to demonstrate that the register is being accessed correctly, the read data returned for the register will be byte swapped. The Virtual LED register is a 16-bit read-only register that shadows the lower 16 bits of the Hello World Register such that it will hold the same value as bits 15:0 of the Hello World Register. -The cl_hello_world design utilizes the Virtual LED and DIP switch interface which consistes of two signals described in the [cl_ports.vh] (./../../../common/shell_stable/design/interfaces/cl_ports.vh) file: +The cl_hello_world design utilizes the Virtual LED and DIP switch interface which consists of two signals described in the [cl_ports.vh](./../../../common/shell_stable/design/interfaces/cl_ports.vh) file: ``` @@ -43,9 +38,12 @@ The cl_hello_world design utilizes the Virtual LED and DIP switch interface whic output logic[15:0] cl_sh_status_vled, //Virtual LEDs, monitored through FPGA management PF and tools ``` -In this example the Virtual LED Register is used to drive the Virtual LED signal, cl_sh_status_vled. In addition, the Virtual DIP switch, sh_cl_status_vdip, is used to gate the Virtual LED Register value sent to the Virtual LEDs. So, for example, if the sh_cl_status_vdip is set to 16'h00FF, then only the lower 8 bits of the Virtual LED Register will be signaled on the Virtual LED signal cl_sh_status_vled. +In this example the Virtual LED Register is used to drive the Virtual LED signal, cl_sh_status_vled. +In addition, the Virtual DIP switch, sh_cl_status_vdip, is used to gate the Virtual LED Register value sent to the Virtual LEDs. +So, for example, if the sh_cl_status_vdip is set to 16'h00FF, then only the lower 8 bits of the Virtual LED Register will be signaled on the Virtual LED signal cl_sh_status_vled. -While running on F1, the developer can use the FPGA tools `fpga-get-virtual-led` to read the LED values on the CL-to-Shell interface. While `fpga-set-virtual-dip-switch` tool is used to set the DIP switch values on the Shell-to-CL interface. +While running on F1, the developer can use the FPGA tools `fpga-get-virtual-led` to read the LED values on the CL-to-Shell interface. +While `fpga-set-virtual-dip-switch` tool is used to set the DIP switch values on the Shell-to-CL interface. ### Unused interfaces diff --git a/hdk/cl/examples/cl_hello_world_vhdl/README.md b/hdk/cl/examples/cl_hello_world_vhdl/README.md index 1722a67c..76e8158b 100644 --- a/hdk/cl/examples/cl_hello_world_vhdl/README.md +++ b/hdk/cl/examples/cl_hello_world_vhdl/README.md @@ -10,14 +10,9 @@ ## Overview -The purpose of this example is to provide an environment for VHDL users which uses the hello_world example. -This hello_world_vhdl example is based upon the main hello_world example except for a VHDL wrapper is provided for VHDL users. -This design can be modified to include or exclude certain interfaces for VHDL logic and mean't to be modified for VHDL designs/users. -Unused interfaces interfaces between AWS Shell and the CL are automatically tied off based upon `define in cl_hello_world_defines.vh. - -This simple *hello_world* example builds a Custom Logic (CL) that will enable the instance to "peek" and "poke" registers in the Custom Logic (C). These registers will be in the memory space behind AppPF BAR0, which is the ocl\_cl\_ AXI-lite bus on the Shell to CL interface. - -This example demonstrate a basic use-case of the Virtual LED and Virtual DIP switches. +The purpose of this example is to provide an environment for VHDL users which uses the `hello_world` example. +This `hello_world_vhdl` example is based upon the main `hello_world` example except for a VHDL wrapper is provided for VHDL users. +This design can be modified to include or exclude certain interfaces for VHDL logic. Please read here for [general instructions to build the CL, register an AFI, and start using it on an F1 instance](./../../../README.md). @@ -25,20 +20,20 @@ Please read here for [general instructions to build the CL, register an AFI, and ## Functional Description -The cl_hello_world example demonstrates basic Shell-to-CL connectivity, memory-mapped register instantiations and the use of the Virtual LED and DIP switches. The cl_hello_world example implements two registers in the FPGA AppPF BAR0 memory space connected to the OCL AXI-L interface. The two registers are: +The cl_hello_world example demonstrates basic Shell-to-CL connectivity, memory-mapped register instantiations and the use of the Virtual LED and DIP switches. +The cl_hello_world example implements two registers in the [FPGA AppPF BAR0 memory space](../../../docs/AWS_Fpga_Pcie_Memory_Map.md) connected to the OCL AXI-L interface. +The two registers are: 1. Hello World Register (offset 0x500) 2. Virtual LED Register (offset 0x504) -Please refer to the [FPGA PCIe memory space overview](../../../docs/AWS_Fpga_Pcie_Memory_Map.md) - -The Hello World logic is incorporated into a verilog module and called out in the VHDL wrapper. However, the debug logic is written in the VHDL wrapper. +The Hello World logic is incorporated into a verilog module and called out in the VHDL wrapper. However, the debug logic is written in the VHDL wrapper. The Hello World Register is a 32-bit read/write register. However, in order to demonstrate that the register is being accessed correctly, the read data returned for the register will be byte swapped. The Virtual LED register is a 16-bit read-only register that shadows the lower 16 bits of the Hello World Register such that it will hold the same value as bits 15:0 of the Hello World Register. -The cl_hello_world design utilizes the Virtual LED and DIP switch interface which consistes of two signals described in the [cl_ports.vh] (./../../../common/shell_stable/design/interfaces/cl_ports.vh) file: +The cl_hello_world design utilizes the Virtual LED and DIP switch interface which consists of two signals described in the [cl_ports.vh](./../../../common/shell_stable/design/interfaces/cl_ports.vh) file: ``` @@ -46,11 +41,17 @@ The cl_hello_world design utilizes the Virtual LED and DIP switch interface whic output logic[15:0] cl_sh_status_vled, //Virtual LEDs, monitored through FPGA management PF and tools ``` -In this example the Virtual LED Register is used to drive the Virtual LED signal, cl_sh_status_vled. In addition, the Virtual DIP switch, sh_cl_status_vdip, is used to gate the Virtual LED Register value sent to the Virtual LEDs. So, for example, if the sh_cl_status_vdip is set to 16'h00FF, then only the lower 8 bits of the Virtual LED Register will be signaled on the Virtual LED signal cl_sh_status_vled. +In this example the Virtual LED Register is used to drive the Virtual LED signal, cl_sh_status_vled. +In addition, the Virtual DIP switch, sh_cl_status_vdip, is used to gate the Virtual LED Register value sent to the Virtual LEDs. +So, for example, if the sh_cl_status_vdip is set to 16'h00FF, then only the lower 8 bits of the Virtual LED Register will be signaled on the Virtual LED signal cl_sh_status_vled. + +While running on F1, the developer can use the FPGA tools `fpga-get-virtual-led` to read the LED values on the CL-to-Shell interface. While `fpga-set-virtual-dip-switch` tool is used to set the DIP switch values on the Shell-to-CL interface. + +### Unused interfaces -While running on F1, the developer can use the FPGA tools `fpga-get-virtual-led` to read the LED values on the CL-to-Shell interface. While `fpga-set-virtual-dip-switch` tool is used to set the DIP switch values on the Shell-to-CL interface. +The Hello World example does not use most of AWS Shell interface, hence the unused signals are tied off. +At the end of `cl_hello_world.sv` file, there is a specific `include` command for an interface-specific `.inc` file, to handle the tie-off\'s for every unused interface. - ### VHDL Wrapper Information Clock/Reset/General Information @@ -61,9 +62,9 @@ MISC Interfaces are not added in wrappers (Interrupts). PCIM hasn't been fully tested in the VHDL flow. Use at your own risk but provide feedback if used. -Below is the hiearchy of the design. +Below is the hierarchy of the design. -cl_hello_world.sv - This module uses `define that are configured in cl_hello_world_defines.sv and ensure to tie off signals to the SH when necessary for seamless usage of the different flows (VHDL Flow this file shouldn't be modified) +cl_hello_world.sv - This module uses `define that are configured in cl_hello_world_defines.sv and ensure to tie off signals to the SH when necessary for seamless usage of the different flows (VHDL Flow this file shouldn't be modified) cl_hello_world_defines.sv - Comment out AXI Interfaces that are not used (AXIL_OCL, AXIL_USR, AXIL_SDA, DMA_PCIS, DDR4_SH, DDR4_CL, PCIM). -cl_vhdl_wrapper.vhd - VHDL users are encouraged to modify this wrapper based upon design requirements. VHDL Wrapper flow Can use generate statements to connect signals from top level ports when AXI Interfaces are used. Not required to use these generates statements but makes code more cleaner. This file currently connects the hello_world module for OCL AXI interface and VLED and VDIP logic and contains debug logic. @@ -79,11 +80,11 @@ Alternatively, you can directly use a pre-generated AFI for this CL. | Key | Value | |-----------|------| -| Shell Version | 0x04151701 | +| Shell Version | 0x04261818 | | PCI Device ID | 0xF000 | | PCI Vendor ID | 0x1D0F (Amazon) | | PCI Subsystem ID | 0x1D51 | | PCI Subsystem Vendor ID | 0xFEDD | -| Pre-generated AFI ID | afi-0f0927bc2649e6259 | -| Pre-generated AGFI ID | agfi-0f0e045f919413242 | +| Pre-generated AFI ID | afi-03d11a4ea66e883ef | +| Pre-generated AGFI ID | agfi-0fcf87119b8e97bf3 | diff --git a/hdk/common/verif/scripts/.gitignore b/hdk/common/verif/scripts/.gitignore index bd7e70f1..1366d166 100644 --- a/hdk/common/verif/scripts/.gitignore +++ b/hdk/common/verif/scripts/.gitignore @@ -1,2 +1,2 @@ .done - +tmp diff --git a/hdk/common/verif/tb/scripts/Makefile.common.inc b/hdk/common/verif/tb/scripts/Makefile.common.inc index 9802eb89..c9325c4e 100644 --- a/hdk/common/verif/tb/scripts/Makefile.common.inc +++ b/hdk/common/verif/tb/scripts/Makefile.common.inc @@ -107,58 +107,18 @@ COMMON_LIBLISTS =\ unimacro\ secureip\ xpm - -ifeq ($(VIVADO_TOOL_VERSION), v2017.4) - COMMON_LIBLISTS +=\ - axi_register_slice_v2_1_15\ - axi_infrastructure_v1_1_0\ - axi_crossbar_v2_1_16\ - axi_clock_converter_v2_1_14\ - fifo_generator_v13_2_1\ - fifo_generator_v13_1_4\ - axi_data_fifo_v2_1_14\ - generic_baseblocks_v2_1_0 -else ifeq ($(VIVADO_TOOL_VERSION), v2018.3) - COMMON_LIBLISTS +=\ - axi_register_slice_v2_1_18\ - axi_infrastructure_v1_1_0\ - axi_crossbar_v2_1_19\ - axi_clock_converter_v2_1_17\ - fifo_generator_v13_2_3\ - fifo_generator_v13_1_4\ - axi_data_fifo_v2_1_17\ - generic_baseblocks_v2_1_0 -else ifeq ($(VIVADO_TOOL_VERSION), v2019.1) - COMMON_LIBLISTS +=\ - axi_register_slice_v2_1_19\ - axi_infrastructure_v1_1_0\ - axi_crossbar_v2_1_20\ - axi_clock_converter_v2_1_18\ - fifo_generator_v13_2_4\ - fifo_generator_v13_1_4\ - axi_data_fifo_v2_1_18\ - generic_baseblocks_v2_1_0 -else ifeq ($(VIVADO_TOOL_VERSION), v2019.2) - COMMON_LIBLISTS +=\ - axi_register_slice_v2_1_20\ - axi_infrastructure_v1_1_0\ - axi_crossbar_v2_1_21\ - axi_clock_converter_v2_1_19\ - fifo_generator_v13_2_5\ - fifo_generator_v13_1_4\ - axi_data_fifo_v2_1_19\ - generic_baseblocks_v2_1_0 -else - COMMON_LIBLISTS +=\ - axi_register_slice_v2_1_17\ - axi_infrastructure_v1_1_0\ - axi_crossbar_v2_1_18\ - axi_clock_converter_v2_1_16\ - fifo_generator_v13_2_2\ - fifo_generator_v13_1_4\ - axi_data_fifo_v2_1_16\ - generic_baseblocks_v2_1_0 -endif +COMMON_LIBLISTS +=\ + $(shell cd $(COMPLIB_DIR) >/dev/null 2>&1;\ + for i in\ + axi_register_slice_v2_1_\ + axi_infrastructure_v1_1_\ + axi_crossbar_v2_1_\ + axi_clock_converter_v2_1_\ + fifo_generator_v13_2_\ + fifo_generator_v13_1_\ + axi_data_fifo_v2_1_\ + generic_baseblocks_v2_1_;\ + do ls | grep $$i; done) include $(HDK_COMMON_DIR)/verif/tb/scripts/Makefile.$(SIMULATOR).inc @@ -177,3 +137,7 @@ $(HDK_COMMON_DIR)/verif/models/sh_bfm/cl_ports_sh_bfm.vh: $(HDK_SHELL_DESIGN_DIR make_sim_dir: $(HDK_COMMON_DIR)/verif/models/sh_bfm/cl_ports_sh_bfm.vh mkdir -p $(SIM_ROOT) + +show_common_liblists: + @ for i in $(COMMON_LIBLISTS); do echo $$i; done + diff --git a/hdk/docs/AFI_Manifest.md b/hdk/docs/AFI_Manifest.md index 4386b68a..b120f362 100644 --- a/hdk/docs/AFI_Manifest.md +++ b/hdk/docs/AFI_Manifest.md @@ -40,6 +40,7 @@ The manifest file is a text file formatted with key=value pairs. Some keys are m | vivado tool version | field value | |------------------- | -----------| +| 2020.1 | tool_version=v2020.1 | | 2019.2 | tool_version=v2019.2 | | 2019.1 | tool_version=v2019.1 | | 2018.3 | tool_version=v2018.3 | diff --git a/hdk/docs/AWS_Shell_V1.4_Migration_Guidelines.md b/hdk/docs/AWS_Shell_V1.4_Migration_Guidelines.md index e2a9fab4..f8a4cb17 100644 --- a/hdk/docs/AWS_Shell_V1.4_Migration_Guidelines.md +++ b/hdk/docs/AWS_Shell_V1.4_Migration_Guidelines.md @@ -4,7 +4,7 @@ This document describes the changes required when migrating your design from shell v1.3 to shell v1.4. The HDK build scripts have changed to reflect the new v1.4 shell’s floorplan and newer Vivado tools. It’s strongly recommended users move to these scripts. Users who have already customized v1.3 scripts should diff those with the v1.4 scripts and be sure to include all new parameters that have been added to v1.4 scripts. -1. Upgrade Vivado Tools to version 2017.4 or later. Needs [FPGA DEVELOPER AMI 1.4 or later](../../README.md#overviewdevtools) +1. Upgrade Vivado Tools to version 2019.1 or later. Needs [FPGA DEVELOPER AMI 1.4 or later](../../README.md#fpga-developer-ami) 2. The hierarchy for CL & SH modules have changed. Now they are instantiated in "WRAPPER_INST" Module. The paths in your Build scripts, constraints & verification components have to be updated. diff --git a/hdk/docs/HOWTO_detect_shell_timeout.md b/hdk/docs/HOWTO_detect_shell_timeout.md index 2b7c750c..e304009c 100644 --- a/hdk/docs/HOWTO_detect_shell_timeout.md +++ b/hdk/docs/HOWTO_detect_shell_timeout.md @@ -1,18 +1,22 @@ # AXI Slave Timeouts (DMA_PCIS) -* The Shell provides a timeout mechanism which terminates any outstanding AXI transactions after 8 uS. There is a separate timeout per interface. Upon the first timeout, metrics registers are updated with the offending address and a counter is incremented. Upon further timeouts the counter is incremented. These metrics registers can be read via the fpga-describe-local-image found in [Amazon FPGA Image Management Tools README](../../sdk//userspace/fpga_mgmt_tools/README.md) +* The Shell provides a timeout mechanism which terminates any outstanding AXI transactions after 8 uS. + * There is a separate timeout per interface. + * Upon the first timeout, metrics registers are updated with the offending address and a counter is incremented. + * Upon further timeouts the counter is incremented. + * These metrics registers can be read via the [fpga-describe-local-image found in Amazon FPGA Image Management Tools](../../sdk/userspace/fpga_mgmt_tools/README.md) * Timeouts can occur for three reasons: - 1. The CL doesn’t respond to the address (reserved address space) + 1. The CL doesn't respond to the address (reserved address space) 2. The CL has a protocol violation on AXI which hangs the bus 3. The CL design’s latency is exceeding the timeout value. For example if the cycle is going to DDR, accumulated DDR arbitration and access latenencies may exceed the timeout value. * Best practice is to ensure addresses to reserved address space are fully decoded in your CL design. -* If accesing DDR, note DMA accesses to DDR will accumulate which can lead to timeouts if the transactions are not completed fast enough. This is especially true for CL designs operating at 125MHz or below. See [cl_dram_dma](../cl/examples/cl_dram_dma). This example illustrates best practice for DMA operations to DDR. +* If accessing DDR, note DMA accesses to DDR will accumulate which can lead to timeouts if the transactions are not completed fast enough. This is especially true for CL designs operating at 125MHz or below. See [cl_dram_dma](../cl/examples/cl_dram_dma). This example illustrates best practice for DMA operations to DDR. * CL designs which have multiple masters to the AXI "fabric" will also incur arbitration delays. * If you suspect a timeout, debug by reading the metrics registers. The saved offending address should help narrow whether this is to DDR or registers/RAMs inside the FPGA. The developer should investigate if design parameters allow for long latency responses to the offending address. If not, then the developer should investigate protocol violations. -* **WARNING**: Once a timeout happens the DMA/PCIS interface may no longer be functional and the AFI/Shell must be re-loaded. This can be done by adding the "-F" option to [fpga-load-local-image](../../sdk/userspace/fpga_mgmt_tools/README.md). +* **WARNING**: Once a timeout happens the DMA/PCIS interface may no longer be functional and the AFI/Shell must be re-loaded. This can be done by adding the "-F" option to [fpga-load-local-image](../../sdk/userspace/fpga_mgmt_tools/README.md). # AXI Master Timeouts (PCIM) * AXI Master transactions also have an 8us timeout. Timeout occur when the CL does not respond to some channel within 8us: @@ -74,9 +78,9 @@ DDR3 write-count=0 read-count=0 ``` -* For detailed infomation on metrics, see [Amazon FPGA Image Management Tools README](../../sdk//userspace/fpga_mgmt_tools/README.md) +* For detailed information on metrics, see [Amazon FPGA Image Management Tools README](../../sdk//userspace/fpga_mgmt_tools/README.md) ** NOTE **: The LSB 2 bits of timeout address (sdacl-slave-timeout-addr, virtual-jtag-slave-timeout-addr, ocl-slave-timeout-addr, bar1-slave-timeout-addr and dma-pcis-timeout-addr) in the metrics are used to report whether the timeout occurred due to READ or WRITE transaction. The bits in timeout address should be interpret as follows: > timeout-addr[1:0] == 2'b01 : Interface timed out on READ transaction (Could be either on AR or R channels). > timeout-addr[1:0] == 2'b10 : Interface timed out on WRITE transaction (Could be on AW, W or B channels). - > True 32bit aligned address that triggered first timeout = {timeout-addr[1:0], 2'b00}. \ No newline at end of file + > True 32bit aligned address that triggered first timeout = {timeout-addr[1:0], 2'b00}. diff --git a/hdk/docs/IPI_GUI_Vivado_Setup.md b/hdk/docs/IPI_GUI_Vivado_Setup.md index 5888256c..1451248f 100644 --- a/hdk/docs/IPI_GUI_Vivado_Setup.md +++ b/hdk/docs/IPI_GUI_Vivado_Setup.md @@ -48,7 +48,7 @@ In init.tcl or Vivado\_init.tcl, add the following line based upon the $HDK\_SHE Download, install, and configure the license for Vivado SDx 2017.4, 2018.2, 2018.3 or 2019.1 for Windows. More information is provided at: -[On-Premises Licensing Help](./on_premise_licensing_help.md) +[On-Premises Licensing Help](../../docs/on_premise_licensing_help.md) Clone the `https://github.com/aws/aws-fpga` repository either through Github Desktop or Download ZIP and extract to a new folder location on the Windows machine. This is the install location. diff --git a/hdk/docs/RTL_Simulating_CL_Designs.md b/hdk/docs/RTL_Simulating_CL_Designs.md index 957d79a6..d071bd12 100644 --- a/hdk/docs/RTL_Simulating_CL_Designs.md +++ b/hdk/docs/RTL_Simulating_CL_Designs.md @@ -21,7 +21,7 @@ Developers can write their tests in SystemVerilog and/or C languages. If a devel One easy way is to have a pre-installed environment is to use the [AWS FPGA Developer AMI available on AWS Marketplace](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) which comes with pre-installed Vivado tools and license. -For developers who like to work on-premises or different AMI in the cloud, AWS recommends following the [required license for on-premise document](./on_premise_licensing_help.md). +For developers who like to work on-premises or different AMI in the cloud, AWS recommends following the [required license for on-premise document](../../docs/on_premise_licensing_help.md). Please refer to the [release notes](../../RELEASE_NOTES.md) or the [supported Vivado version](../../supported_vivado_versions.txt) for the exact version of Vivado tools, and the required license components. diff --git a/hdk/docs/Virtual_JTAG_XVC.md b/hdk/docs/Virtual_JTAG_XVC.md index 2551e5a8..f5121fb7 100644 --- a/hdk/docs/Virtual_JTAG_XVC.md +++ b/hdk/docs/Virtual_JTAG_XVC.md @@ -188,7 +188,7 @@ The connection Vivado and the target instance can be terminated by closing the X # Embedding Debug Cores in the CL -Before beginning, it should be noted that the following only applies to the HDK flow. For adding debug cores to a design using SDAccel, see [Debug_RTL_Kernel.md](../../SDAccel/docs/Debug_RTL_Kernel.md) for instructions on how to do so. +> ⚠️ **NOTE:** Before beginning, it should be noted that the following only applies to the HDK flow. [SDAccel instructions](../../SDAccel/docs/Debug_RTL_Kernel.md) and [Vitis instructions](../../Vitis/docs/Debug_Vitis_Kernel.md) are also available. The Custom Logic (CL) is required to include the [CL Debug Bridge](../common/shell_v04261818/design/ip/cl_debug_bridge/sim/cl_debug_bridge.v) provided by AWS as part of the HDK, and any required standard Xilinx debug IP components like ILAs and VIOs. @@ -217,6 +217,7 @@ cl_debug_bridge CL_DEBUG_BRIDGE ( .bscanid(bscanid) ); ``` +**NOTE:** According to [UG908](https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_2/ug908-vivado-programming-debugging.pdf), the debug hub clock should be atleast 2.5x faster than the JTAG clock frequency. The JTAG clock frequency is fixed in the AWS Shell at 31.25MHz. Therefore the frequency of the clock connected to the cl_debug_bridge should be at-least 2.5 x 31.25MHz = 78.125MHz. Otherwise the debug network will not work. However, the minimum clock frequency requirement does not apply for ILA and rest of the CL logic. If CL design is running on a slower clock from the available [clock_recipes](https://github.com/aws/aws-fpga/blob/master/hdk/docs/clock_recipes.csv) then care must be taken that cl_debug_bridge is clocked at 78.125MHz or above speed. The following list describes the steps to successfully setup debug in a CL: @@ -288,7 +289,7 @@ Press CTRL-C to stop the service. No, other customer instances running on the same F1 server do not have access to the Virtual JTAG of your instance. -**Q: I am getting this error:** +**Q: Why am I getting this error?** ``` % fpga-start-virtual-jtag -P 10201 -S 0 @@ -297,11 +298,24 @@ Press CTRL-C to stop the service. Error: (1) internal-error ``` -This could mean there is already a server running with thtat TCP port. Either find this process and kill it, or choose a different TCP port. +This could mean there is already a server running with that TCP port. Either find this process and kill it, or choose a different TCP port. +**Q: Why am I getting this error?** + +``` +ERROR: [Xicom 50-38] xicom: Device:0, user chain number:1, slave index:3. Reading intermittently wrong data from core. Try slower target speed. Make sure design meets timing requirements. +ERROR: [Xicom 50-38] xicom: Device:0, user chain number:1, slave index:3, is not a valid CseXsdb Slave core. +ERROR: [Labtools 27-3176] hw_server failed during internal command. +Resolution: Check that the hw_server is running and the hardware connectivity to the target + +``` + +This means the clock connected to the cl_debug_bridge module is slower than the required minimum of 78.125MHz. Please choose a faster clock to connect to your cl_debug_bridge. **Q: What is XVC and where can I learn about it?** Xilinc Virtual Cable (XVC) is a protocol for transferring JTAG commands over TCP/IP network connection between a debug tool (like Vivado Lab Edition Hardware Manager) and a debug target. More information including a link to the full specification for XVC version 1.0 is available [here](https://www.xilinx.com/products/intellectual-property/xvc.html). + + diff --git a/hdk/docs/ppts/simulation.pptx b/hdk/docs/ppts/simulation.pptx deleted file mode 100644 index 657074a72764bcc8a7f80bbf1c1d9de855126d33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36174 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 MTAzOM`|;`j01v#&1^@s6 diff --git a/hdk/docs/ppts/simulation/Slide1.PNG b/hdk/docs/ppts/simulation/Slide1.PNG deleted file mode 100644 index 02f4e9b12fcd77c4792f5f3a2122a3d6f632bb6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2294 zcmdr}c~H`682*{LnWb25=7Hg)sHk{k3YBH0ZMuTG*g@W&KJz}``+o29W_r4xP*>Ac z0{}qX)x{YD04j=b!)sM#08k?Rr9Y!!N(9V_V?b>ecv3+&h8#s71%OASEi32Nq`!Nj zP9B%b<*BKuM~)n+s;UwSg)A1!z`#I}EG;di)9IR;no_BBetuq6RaGPsb$54bYikpU zL>`Y98XAg3BBP?B0s{kGTwFXoJ!v!=m&>)bwoXV$z+$l!3WY=>nVOm^s@bJ-@QQ0s z4949{(ed8_sK4f1Qm8jaxtt{cfCgvnC~@)kg8^WZ*wy*y$pnANkRPe&<#xdHx;ngB zxqju(kX3p2vwp}xYZ!hnA-BgUv8%T5V>v~?40AMbd%U9B8f1u~!ACB<_sat*Y=VXt zJ*68`*X{T=`r`z0j?kv?Z5`}@YCIPohKA)sW}my`zUWQ1gOFs_-aGF2$)>OUuItM6 z=p88roKco^ZK|?sv94O&o5QmG0#9W{fGOJ9i{`<7y_HYL3`g=C)02l98iOP?H)naW z3EF69bIy*%ed}eu6|G=6)?ls{(e2<&-^eF{fPJ@2Uuw8}Tn{CT>!e6c!s zR&YbDgKl~2!p-d{C}i8WzVbc!Br5Ebps@jkp)&`i3Q*2MDi{7Aa5ShzxM#Q%p%jblpwRA0)2})<-@H^ zpFOtu!FM_$qEVbn53)$o>Su^rL88&e+vGKe8=W~>QN9(leAEE?hP^q7zjv;$p~bMk zqdGR1JJeM^c^q*Q*YR--Yx3K9ikEpkCLCWaUA8G-+W_oIE z?~+p%u!{2k$CA6M7j#@3ud%oz-mMFA z$&Iff^x0Cop+a8LEy~gsKKznHG5ISbDJ9u>E79q2V*EHxCqq0q8ikYR%A)cWp8dzc chET<;n-<1lGSe4Hs%yiz9(Q-HJr;QNAH|K`SO5S3 diff --git a/hdk/docs/ppts/simulation/Slide2.PNG b/hdk/docs/ppts/simulation/Slide2.PNG deleted file mode 100644 index bbfd4e62554c0a4b4b3f8464e3ef9238250b12bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51853 zcmdSB2T)Yowl=yN1O+ytl9VW*1W`aqN|q!bNf1$qA{og!G_)HK1pyJ1Bs94tHIj4K zB9e1xGDwCdNT!KzHn_t%_uPA{Ue$Z`|5j0Uuby$t5x+6!dZVs-kDQc_6oMdfMFm+6 z2qFR>2|CUYLlCUQW2pvwgE?y4lZMc34D;a2DYLsOcOfV@lx+VQzA1^F!V^abI$MkX zgVo!9Hin=kRz=yn58d<^4=COlYrD_7YoAH?d-(D7vbG@?Rl&^|mfxPeoPYL(0K54b zM)E>4ZAts1@xa@H7KN5GErDk#`YTtvytV0!hxKprUbHYNH?ev;X<7055B)mQKgJV_ zM+G-7bPb-{U=tp0>7j=Ze#*PNP9D%nk@P|@NYf%gW4e*B?5AV0L8ZciLtK%nhca#5yji?p zp@KlO8M0ifcVX(Qw%#M2nftb4>bmZG9#2S?CjGib1eeM>V^erA7TA>f#k!lkJm|?* zCC<*Ac}(@}_K2`sch9tlbzFhdLQneI?BL*29RDc{K{Pe(y50PqK;D>^xQvC5N^wLJ z!3&2}X7{PaRdiB+e?O-|hRe_KKUQgu{vI>gO7uc~@GyJ1w_Qa!4|b!l`#GBE7Wc`7 zt7r>M@Gxs;4*g2}qzn?*H**%>;`fTn!W+Nw2`{1Ng>;1-e6J&)S!Xtjwcb8GR{k){ z$2h&;zHO_v=y%Quz3x8p>tr>vhSDAL%Ym&aGG9dRIgd?ss7&#$}{IUKQ@bkFNcc-YlZmK*Tv2S?Rg`v3!&I z7E1|DLsm(DeJ5&@xE#8=`$d#rrL-+sm97N$6Z5@%qC@VP#F&+Qd>}uP&E;mO0Y{=h zc^d7Hvaq2PE{uDRVrVJN>uNw(ICJSYt}5j=Q|uPa&ic+>zYp8(c5qYF zuZi5u5Nwo2lYX{ZtIf2nrXa^+%3m1q$EU`JF%cTjj&{X^xpS!F^3yy zk@=g)r-@lLy&BAE>Zl$L0q=&SKA(Ly&wHSwQYs2a0|=oAa}PozppZO zr(3jDu=Vu9i9ugCNr*2zLCk2{^USQK?#}Dn%qgAxkzOm1=u`#yEQse^Z`*&#|0$rg z>0RkxTi?ha(09gKH4|}B{86rLpkWgp-ysp761qV+xH&|SlG9D$y4_ePW%`$-o^4$J zzPr`RZae98*K8quTKBWJIWT4UZ2cYAwA+egxG${=jX z;qvoIz1o{oC?d~d=sAgdjy!zih7^WdJtl=1ck!K2=?~w4@3V-Gg^~AwL$tzseu(G= zH?YbwBwLB`ln)BD_DQGLK7Od8amXZlv+O&YRHUZrSWUBpV`IYj}IfXWrvu1Sx8JyI!~|1Z?41WQJ{@{SUYnB#pmJO3JdOZ zUMcnRqqvEqYafLD(s|;D-p3E|I`S zjT3D2c}SfW2iyR0=aSy!CCBS%k!P^){AJ%?E`RxtcHw_C8vpNpj46k-A3bV9qEzFq z`D9E_PaEMa%ragzq!co_?zA!2xmuOfUudPB>$$z0 zJtDoGtTXUPDq8c}6DLuZ#s0wqSD$THvKvx3A(o*xlpNp7zrG);+mySdWxs0ARQ2=R z@cZB9oLL4XWk_?O=~%((y!$OnG4CED-jL)%n?tu;mp$rwTvQaU*L<6s2(v8o+A7r~ zn+8^*NUP52X6er3Z&gmk5Tij@?=fF-h@0{-JwdFIN9OGXZZlq^9ZMBv>KCcFX1miX z88vt`pre-7CoLUK$k&TOFUv6N?_4v_5kFkNd zs+yu??*pDC^7hLWHd&RgkbR-q6PR4|j`rMpbWUZukkJzszq@F>y?{-lSg(XIk`tp< z)UulH)&Y+Zo;-TjRJ|3ytB>7l=dph7??6d7?KqPM! z!kMdUmxe;~UvF-1uB968hQ79Cp-Ir)E`z3{Km5T{li_nVjmD7jySso==sZD$9IIMg zBli>IBOP1MFBNB(P!kzZ_0f?pXbnfej83p7BYq^=M+NHer7{DD^&dGZOOal4{9`eL zyg`rS?|*EN7NQ9M0uAZY)Vud8-Cz6SxdyCnRiju3haSRNv(9-q;|oOj1R;G*T_KSs zLCi_J@;!Sf(PQ8JT>VnKmVf-2=r*_S6U6B8w~J)we!d1Slbjwxc>f14jquoZT2sYA zd~Ms3>1dv9zw2*Izw0>MNGodeuQGSGw$9#va+>VRRg83AzUSsuP07snLBYYnYl6O~ zDVP{+qj`G>B3Ozl7!2fZZt;2Yk^Pk86)$$%i<6ueYf(lva_}{fUz{v8#0=ePJ$Qd@ zYt__*kL-($pYBb#-N8ux_wtyVk|MH9zngS6kzLwglg;QSQ%44dllHm5n%0{zqnoMO zQ2~m1dI;^2-KVo#?w4*k!uk}cG4`47Hwg;%#PuQ~tJm)}M+I2yDqM^5UhAv4R`mKD znVrcjk%{03R8@!Lb=umXDU9`1lhx2H z!6%QMjj%FZR5m4^Ww+t5QRk`LwOQqm?xr3C@8xRmy=OXi1wLS0(A0KI2SdfyWccwM z^$>+!j%ZYKh6euFcXY{$nyf^(iQIlxE-#sQv=u6VA0*-{;??zOISmHhjRa6?-H=+U zr$h17TNG|LKZC6W&c)2!kUD56$OttXQqn}Pe-4iimrF#3q~^S?nkv(=yipU3iofAA z2>c7cp_2mBBB3JlcQCB!fhq>CpE2EI^2S@>TTiO4`1~O1|A?(vNSR#(?wyuyeKsjx zg57%++e>K_wKDqa`6Xj8`!iQa{(Kw_JeQ1;5S92$}tegmlIEdhk;g^#SQ5WGPooK!CrjeQZfljfv-PepuJ@FR8<;}ZD zTIWr=W}r&4kq$Uz58TEY)}$v=exUxeR|3R7wX-^@LnKZ1>dD1Lg3lR&_h0Pp$!WpF zoEIMAG!1kXc11PWwj&L8D|1fW*MpZbz@=fQ2<|6BRXe@5QG?Za>%SY#qP3|&XrNQE zS#&xmU*B%D=Lb6FHNlxvkF?xUN=k~Xc)WT|bjouovG+9tqSG^Z{Y%t15mJUOKf)d$ z_In82j$@X?wdNddpEA;fk#xnG0k?&Lwb?8Jx9KHpouI3juI@o+K#{fZcDqvGD{V+p zcsIQKtr~ir;!;7E^Xw*&Ag#kJ$2%#I<;#yq4QLYu*A?ZmEX>fnhL|>S9*Hgw{IfCa zA$}8GmRgz+?Q8tQ=(BSuA`*9bx988FW1}Y?rf5K^&EY=H(+1BDwsl3M8!OyXugGOT za?T-3z=qIs6$WM>cMDS|(`(!AJ)*O_AOs3j~5b22+a#77e?s_5tRa_!Fh znOQl~JNw_>P)@?79J3z@5_K?^>YuH`z@y~LK9z-jtY`A^;NBK5cwoBF*=K)vmom)z z9U8ZSrjl~MS)v$pr9(cmR|e*UYG*Wj!YMC_k<7z6*5Bz4z>vO+ev~QVPvEwYf4}Y! z8yPswFOMjNs{k$V=<3a%|R$6rX zoW)mX4}*DUz0Vz%S}1i$aQ*PA-j(U!7Bs^TsH95Np}oxB4Ape#yD~Fb!XehmY%)An zvh}Qs4XcRTPeYuhM60}{oV-3kcv1vuLd7Zhu{RF$!Ka%x*~)qKE7RT9t7>!gn=Klp^UPPX3%17l<#j?%EL8NYr4O}{yJ;1~7qA$3jv z3K0#udykap3x%%hu!22J&AY`h>f2=GIp4>zZ2sw6FhDOZBv1!A4)SiZo zY!z-wQw%-`}C|M7w%d_{TED_pzIT=FF-I+sMZ*nF^VQOqtWD!HO^&t}) z3=7eo6!Cf#V;487&53}Imrcr(5_M4Ew6*p3uM^pT>{Re7$D z3lWq;f|-Z=6GUCY6=z{|<*pfbC|MGz$N%i0kQFR$4riV57NwHG5#IU`fJKXDW zz{}nKKt-Q?oh%^}+GLrFe2f%|(||?f)b!BGHS3H`btg>MVe*2DzXp@%LJ}(*-JgbH zPqjAECdID6K4PG>H3D-jEy$f)cbgM&-gjn-64{Dgoa;=^CQIULLHbiv~hhvpm8?Giu-?Vcg}!l7G-qPQ!r0jaFnW>QHVyp=L>u~o5f z*i*gx;{^RT(R(Kqw^t5 z1|}OKpILr~)Uf$@ibRO@UUKgU1JM_g?^9%7hu&)s12jZ&8>el&bPy{kEK&N9q0%wE z-?LZ4ej$G-RG6DeYRbHzEVelpLW_-6j#zm)#QD^yL$uGUty|2F`C3Dl4GgIpLZq(Y z4J&?LUi@n&p6^EQyQp=y9k&vX+Zmn;id1ijM%8(!xu@#l(1+I$}_viox#lh-bKUGd%q zn=I8OHT>x}wF`&wPZ78+uA<_?IP!H%HxKU>v-T)x3tUbRoDM^=}5px(vUVb%KlG z*zME55!u~D|Netpr9?I7$$R0714Qa=gpl-`TZE?&5`XzdmRgX(QT!N(-#h=V(@y{Dw*2M4yzcX!->$kfTBv6b zKTT+w2qg)UUe>q=leMCfN(mu|dN)$;Y71BY_Wip&&e6mqb)U<4XtdI^d1Pjb!fTvx zQcrGmbi2y6!pi=n{ke5YSL5Pu*PY5*M{oE)kaT&`H!CdETL3Lghcz4N+pt7F;2AnR z*hBFoGidjpctY|)GFqoUOD-*GcuhIdm0v^bhM6^KL3JUFqIuj12XTL;aMdATFBJS1qU&-L7>}PMb)*!AvqEgMc$~tl}-YnqSZ*_vauYuDGf9cg`LdB!D`mL8KDTJ} zgTIP2!5D-Zb$ATddMKv?4j&Q%mgTpQ>-*QJYDmf-@4Rg%*qMO`G!yIq|H+X_0;q$( ze>F!R&dIbb(Qzr1?G<#lM~Ns;=0iMyxry(AMUjsC>0Ng!Vkc5}jV+yk2L#5I>*s1g z)3-GslfAWpSyjeJAo!%0pN9Jz_!HcIMnlSFRHj2Zj>pm#>>5GP&gr8B>mf)d>JW>U z&6z#+>)VWg-L0PVr#`{VVl zd&%d_J`a`DJN#7V?D2+5it7vT-TE7=$21UQ1-9AOJ2d>b5T$m*rO9<17#z?DU&H~$ zl*6$D;241o`!LzYz&)MBSBx``w*}^TC_l)*9cWJerz6ph!_m)ymM9VT+cq+zF7 zV(QKVNOQJ?zh23PNS%1emC^l$7i^!pCS$#`T_~bmD&lU%V;!Ajh;CI2q9q3|4}YSi!wmLn6CA_f*xRs&k1Dk7+>}|3t~8OY|^l0^q9;4_D5y^w)hg<3t2q%3gkZ zd$~jp7}@y4W^Siqocr%z#m;uf>vK2Q*Du}DI3*-u@q!-LVOFJes2jEFX>`Q}MzwYc zF_T{d$Trt#Mzr8{?(sKsXR~ki^}(08T<)!WTI3Bv*q20U2`I1m`OZ`Y2o`74S3eD(^iH(jasQNHKj)MVyq8`5Av1*6ji;NDl4zSxe-*WR*r2^cDkeGpA~t(b<1u-b zwx&EtKd@u+88FUFRqvC2&9%0lI-E z&uDeAb5|q*r=wb&ebZQ`+C)Eyv7?B7PBn%D1(}O%&ttW#xlFM$`-b@bJ(P6{^1k!J@&pIfDm#E{O5sj1%P>e{*epi>oj=6x4M|IoV z1nt)l631i($12J_2y4o(?4q8>9#yy?5^sAOG|Y{y%^u-Ir`2v+bqXI0VZE}SXSA@| z|H$MS8oXiEviUMOPp_IDWsKZ1a>+CUn%C|b`bY-!|haEP#{E_f1DWewyTimpHOs;SB&^JjGb zt`+olz`pm5etW+B8IE{&^!`A~<08dC`Aku^5K)_+Z&SMmFv?7b^k9wchTYoxi|&2f zJ?Vxl6&LM|25ScEoigQM_Llnk|0zkOBi6We7We!VNOem z{97N$t0<$#nE7&nQXn-PBO4aO^AD0p{qW$UPrXU;VMK$jIx;x^16A-NVcn^LHho9n z+stP`Gc`O^5|kOxLO8$1{*{Vz9)?rIOU~z=z^{o=kr@ri*yOdoNv%Vx0#7aa}16vjEPJvjR!Kbj_r}NKfKw%=lk|ZBLB6XNO z1Zqfd^fWE7@{uMmubCdlI^LtU>TCFvQ1&|S*^&9-QGuhy5Lc?PgHis;`yXjZ4aJXb zF!o6ZR)oSp@qr7GdLT0MoO9gKTF>_PNIvF#8gU}KuV6UWK5tmx^Qk!9|B|Q9Ey4GySbN> z;`*}_X{8R5*avulG$C=p_WAEwNfXZJ|BQ1SU2h&~7dKsa7{_Q%#wtAhTd87-csK3$W7=%xCY1Z4u41-+( zA3?E-NmCu-01WYp;NngEYT#5-jyxO`O1rjJLj;_&4+5Cf$d;2@Sf6>{NTa&F?t4#= zHfOZJxkQ&{fN}SJ*alhX&ZClVrKD;G8v0eW2HZX~hJ8snI?%LOi){>9o!55^yWIDE zPH*ZYNNJ;1KC_A%Z2_YS^5%NqvU>%Xj}FBj{5}gV7z;tJBuM_Pf^%X?%dSogRSmEA zWcq5AovC=~k6ojy?$TEt!ZxDIF!@nh&{fmKaHPiTLTKT~mPJd7c?Xd?lb&<2*uXO; z8dm%!Vux=!ngM=0VM1a(X!`1nwNn9Nr7T41`pc|CW1IJEuk&~;1qC*b;gY8hksj^b zDAE*$t!2q7BdnOyUd5DYUy`j3v}w=@Fy%Zl$}P;Z1*`2T`iY&V%B170#0F3*S;dSn zFBb?eZ_#pj02FvId$KXVCQpYnjlm!^xjrWxPvamesZteXQ&_|VN0^VrRVpbTq7GpD zSoxdsUE>W7MJoUfmR_r?c%Hw8C@F^`EB05XRDU3{Rq9Vj6PR+WVLi(lQRODf#a0;f zs)Qt-_o~3JlQQvkVP>CGcN91LyYk;BEs~ClQdIXo@!EZdAH|x?@cPq@l=0~D)`Kd% zRq~>df`1>_cgI65NR3milV!(!+7GLJ+MjrpwP`W${M@-P^Sm!fEfHc8bF&+=;X>?s z$Qa-!lpq^VIu@P%rus*5a-W;0%=?m7JYjDef62{9qK?P|pFG^CW=ZSQjdbc7IC5v# zjrNrv!EKq0P|Mt@hfryDz#D?wwb|Q}BBMlj3BCvW#8OPa>AH5hYX6(t*aRm+fsx4W zRe6Y*(CCNLV=JYpKkp&zZ3o`f9MP&XfJ#w&Np5vbKN&vc( zn6$bVf6Cq(8QtPvK{(|9)pa2TgnOXOWV#*Xw{#D^u+|hbk-DzUeLwOHT(z&t{UVLV zbwsep=wF>OG@%?2sp#ybLP|fvNAfaRK@J^HfsPnU&g zIYyKzUPRYnbwNcZ09zfe0p+-jC8keW_*E!)$3G$ZS(oE2gL4F6xU#h*i0O)4u=W|h zHbD<8PXVLn{yeBo!TSYbEg==ztH7Q96z008perZsu%u^j%}43<=kiv88wh9qOsFYK zjTIP#?_{Hj^morKN{o8xAP|$*?#1sjw`>UscNLd3;aqd6okcP=pYv=xqE}NnLud3?! zRPo#R=i-b^P)%AX(!|-N_@M!lg?xy+rVZSS%Q9Ju4@&{+0$uvEO~W~E`WnLr5bQS^ zqI3VZeSje1SH$Na$k5Ong8l#UMa25pFS&l>hV^|teEGn~$VgCWHUaWJb@=MFy?rwH zAt=ndxnV@$1~R`!_>@%+=UFDP+r8)FZ`&sg+t}o9=K%DFd@yvsAynB~TWhxTd40&O zGWgNq!L-XWCZACpAq1r)xsoR+Z?+KMPtq&~>8A99b#_FVPoKNeI;u6n-Midn>6(y` zP}4}0#8Gc=?*ss%C*fdXi@E7j9p09Y(`+3W9Aj^V@>@yIil{y4g$7lU<0Z*2Ly!Vv z`!fOv`t3LTmztUm2>(U7fcWR;3hrQ)2aMtL=6@pU&+$m_74DR0Xi>KpUQ2?GwYEnA zdGY6Nr9f4k5W$?Ez)NfO`;ei%00I)ZOLztvNd!5ro7Fx~mj(+nK@r-;m7zoNex(o; zs&@rNv*l`pwV3uyH>nPKAzWQs#tTj|K~w-C1$Dh!8msoHuuW1V{9G^Uy}#3EKf^d? zL*TmD{~+GNG+EKk56lyL2xL3kw~5 zhKSW;-?-Nc$I6Y&SnBRxHYVi6VDPmWd+Zr#Ns}>&L0MAF=4bMR7}vuyGJSqoC@RW{ z+%PPmGawJFVM;|Y{EJz8yo2i;u{r~A0y5^E1bN_>>#Bm?3%|V>e6da^u(x&IK}U&y zzKqEN+I#uRj1F^pApv%(gM@3#x+neW;HgY-ig_$HU63VPdT_zJgWaC01JP6DhQj7< zY4-4hvvg8W+&iN&;=)rxbnzC}Iia-GyW~3Mpd3VQTIc`=0I4C7#Vp!S+Vb1Q$JuUe0L}G7v0u+8siDjwc^NV$$z;U!lFU<%Q=l#8CDgT0zxNxP! zF4gkbDj>+5AJv}F=c`{@E!|p7mq7VN6S50xqIWaizKR*q_~bqFM5o?$8WbdzID3s` z&vMN=1MjNH#fs3aZtv`e`tr4{O$Q$>>8#l&n1GyyvDw|B77S4l$?=}}IWT+b-8xA6 zk)>OzBUpW~!OAM@PLd~-E^N=t0D7mBqs7mGa87gSlC=y+?WMvZx-Fk`-fX{5cV&Ik zQLA&)YbuPR`CwaI;NYgL^RUNJ^0Y;$_@Ps2b=&5%dpw!AnX?ver$xG|AH*74BU}w| znI?qh%&LS@ArI<8eCZ3>LQc>9k&>euDVW?-nR7qa*7qsFP}Zw^^fdVotOg;a6qfhv z@8lI@7}mKA*Y}5n5CDM68m?9#{EUiohCh_!!QwNl`@YD1|GeC8Vs(1aJIXPJ@ZAZsdbv|i7a@oj3gd9v~#KkMj!AUV=?rHxx zWNiOzRR2ft;Q4yO4Z|*NbaTvug;7jufAQTLFN055?V{G=?UDzzoH^R{zCX|1+O}Q! z$Ix>+H^OWwZdM;W$7kRSC{P9@oMYFz>T@QW{j*5Q!xXNv^sTdE0>u2Ss!C$G4 zn}LggTYq*Hygd+9ppede)|guL;|`dRfe`akLEHD8QX`h#V!k>tkHmP)h`tEa)cdKAMshNj2`cU7Ok!(SgpSbOxd&Nm-;o;g`R z4Fd&QMzK_%VW_o5T-BhI$4Wkz*~_MEJ8Vra&}E9x@hCuIJ$p^>?fP0iGw}9>a63Ul z?pviRp|%mNuO6-+mzM-m^;_|z`nkQB+LdBV4rDwnY)KY!8k3l!%Nw#}I(2)kp!N_u z60rRdn`cV3SH*+0onZyKLcLIyr~SKTd&oA+)jakVcGgrt6XKO>__yTjYo^5aF8{{q_yyL9hPaQG@;2D%bSe9;m&a zqj(BxY*)n_5t>)!%8cPMS2hIau`shLioLdN)nMD#TN|#-yZgoUI`RyWf~cusXrY|3@VuD&+Eh=u&j%sI z+VVJF%f?pRk(FeUAEnZ$^7_O6DfIdo;PeF8i{pKnJG!oQ_vWm|VxXAAwVZ0vQR+y6 zJ6*3;?ZG0K`}sgMi=J`FNgJwL4i3n$D|b7qR%1}2aGO+ob|$?9Fo(n zjVqrvi9qu#-C@|LXzhXQ;CT1F*dZCb&$4TaCysgXxSL(CIset*K1!dm180Xd zDc)AZ093-XuN_~F)1(uzW-ojbp^(4TU(XSofE8;|OdNq?>M^g>&W1NjV%c=fp>A^W z%SPdXELg5Ozo+fG98qR?1w)Kyr-eWv`}A)W6IC<;$6C@L8SDteFDmuGE7N2+YC+F!VhR==UW8! z!Kl=fIt5HFH2G$P=D*%jO8+^7I4lpuu&VR-ZKe57@V7*pF+uweqq~#r!2$uNa6H) zy%%s>XZL(#r+tyrwQ;SsI6e+U*JVmJmvE9K%uBkccxJ3Pp!y1 zC|!It-ULWf^%ub(NoUWdVHA;Fy>Kt{f6|M5Jj-^l<9oXx&;aYv$1D;y*`j27=kVhv zjqNgU+VYs(@l?-sy%mbO;)@F}mR$>rhA zKx^`Z_;xL3iLzd(X%%0(vajbrCytI&$GVR?cg;G%nVAER6@I~q`a#pyyYM%nx$4K> zYi_udVjG^D+>Au>I6S6jvE7cP@Uh0;o$KUK4Jl4qF;==6omc?HfjuM`> zP#v)qLd>|w&R(t7HlPQk^nL4D*pzE)t}&5M;%DM|E0k0v*RRiRiTHSGNsrdw#A}3q z;aBzn!RZ|xhrm%DgZ=NCCO6fxVHGPZqcvf4Pbf_ZpUr^0nmTSB#H*v0k79%nrj%Sc z?%^Y*gr8dzKdrEmCma%Xz52A=x5v!5Vl@UW#NOUO2_PI8=f_wviOU#lkC-mKJYCHp zJ>Edy{ZoIt7b_ilhcfzQ9595@vrPxqXi5uEp*7Hj zJ@$?XmpQOdg{Jksdbt>S{&#BTUq@22s`cXdB49uF>QA8qPDx`^8(G@uFiVbg0R;x5 z9$&e>zlN&XQajr{S*U_sp1gBH*!9&#$1z^tj|?iBU}3)$Rgqjw9GcQnoYy1HoRBkT zJsh(KZkPB5Rg}t&GO*?lM$8urdGBiKOX4fzrk9I;NHEpoJuUK>(-!+1s!Ejo?~^T> zxPX6__i7OM&qe0>-6lYoYR}g&%gJ*ayEKl0MJ*It4 z)UVDOb9m>wNFl%5`JXzI;CV+sRHIokzap#-l3!2h?riOJYr+PTK#|mP2b6RZZh8LkDe}u+?nBnwAF!-- z4JH&Xv8UEMAohuz!d*jLQAHJvY<;lmoct+ z!`_CeV@sEuS;wX`%QrK}b%%ILmp|fz6oE~>Ki)gGAN^P>|J~Uq){Z&UmzWQRCgzZz z@?L<=vNo(Rlk`&l)$m6k%ggi0Bt9CfOYP2|E8ctSOUta>jbOa6-)Q@0(g1xIC+tGOg#$r z?fS{__7x3)*eZLr2=hk3Qv-YT){o4=G)k#~Y|XnQV5aqa~oslfPglDyY%gS!D zu#L4OD9N&3`X~l!&6g(y~aIf$xpcZk{jB;+xl31{J56p#pi6!>nsEb3wJWr%alZxA9&MX|uU}pL zSX^PUKu#loc-Cs^f(BSy_WXycM=EquZz|!BHcIHMq1O2*S$Zj4C2z%CeUr7QYo*ab zMN1SGHvBHWv9tT>1pW7#PIr6*nqxEZ@7-%qky;$4do8>Iv ztP(ngTcXpOLWj07@5)NSRiEiW#Sa2jGvyw=6~rCh!e6jEUEeHaVl@a$Kyo1)zya^m z$P;ASW!By^A6=R~r5=-5M4n)44G6&H6Cm_E;D#{=yi)Kkm1sS1&~+a{x*s&S06m@z zQ$}R|!IJ+x{0QC23(o$h-uhx|EYbe)gWtZ0!{IT{yJv3MX9ghC%%-WJl7y2*&+jZ{jqZhietE%r9TM;G`IIdPX z`#}d4?g}*v!Pf&yb&~7W8GU~4Ivh=}>~~He$2QfPtZ5BaC$e47-)|Y4<(`uS8vYyl zYS-eNhY-s6mSFdi(dfOjhSiquN(z%xG5v{`V&axcRQV{553wx?xGFJKw3Qpf4zWV^ zgYV*Sgk~?qYZOzW!@Hwf6H0a3+xKr@JZQLR0kx*7wdr`j@<8$JssTpLwR&@B>HV7+ z<=QD7ffuHPoTxCIu7Pa(2waO&Mf1B!+ipzaRcJg?pH1hGGmHo!-8TAl0 z$yq@}o=%J?E-K3PXq8$=C3OT+nsQy3ho3&+@UIH)2LKE70jt7jN;v1C^bq;#!%QwP zveNvh=$Y8Z8AZ+0!2j6DQ!{rd(%BH{L{)A2BAv@C4U%nX!Z6x{0fOWQ(hLF!5<9`$ z>Gdzp%ACTFN^Ys>DH8oqBrI!?hde>3S}TWb(N``uj_1T!M3Eyw1G)0obdXn+@alTp2~N0J($hS$3MD znom6I0HB|arqfrbtJiY1%<^T@)|W$%oL04c*1zq<$RL3g{agQowk%`&LmWW{CDX}u z)fL-HX6yVt!y79;RV6b;6x0Up8@BZrDvir04*Z|WRjPp9wWnw-32NB2@O^rrEx#RJ zU7*LhrE#@#s8RMnCD~)0R-$e6XN+yKjBe-X(jCm>LP%cpLBt}diJmo1gXE( ztU?U@^vKeV|KWFT=BImhI4KtQ@o-y5CR8^*I5MT8tJ$zGhidsU1_5sfY3dtZ-0>dv`Cp>sw5@C45IdLZ`Kp2heC!lel>UIS}*wdW4bT(hAfijmoIiKB zY$>2#0mxrCHjn3GJ}hF$_GmMFX>i8^7#Xz;@`S9)hm>E3Y|7hlnb0qCT={E+hZVOqUvZh!TA6L|J0xf{FMb*k`n zm3LON8}05PMc(*fGu9XE}!UXoba;J;RkzcyLd%MAbQhELNS7X<8p zdL_G6P*7OBRZQZ1B?K=H^aYoARn(JK*NTBRmRI!lPWA^^T$4AP)IcB0u?M35QUiLa z0rb$6V7vnZGMMGREHs8Tf1rFOBp?V}86O{JCr{`J?QR##9QMX%z3A^+;4xo3GurtI zO{S743H;)}k2mS1tY=!R^M+nPl6JKl<^F{hDKI}pCWNN3@OiGQr%HLtyfGCD`KUr! zb}y|VCj!oL=WCpaFy(suxseaPjbt~Mp9)zVTy9#sw7ir!F@20NT3=ch8n$nn@wQkn zt`_jhGZCCIpyVGUz>1wHKa(7b(x-b*;%slygr`C$^p;z?vQHOh^+asC*$L? zQE1r(DJ?GLC)M|w11zcj${^IV0{|w6OF)DA_Kqs{y3j*oe+c9bX*c;Gp{KpJMz=n_K>?BVk1n_oEj1T(XA3)Fs;Xm_m z|B{sZKjw?96?ntIL3tj@6~A-RXXdZN%HXjn05YNwjAY0`pHwL%@j$-?Ser&?IfxcS z;=WiEq~~w9TS3k~`1YT>r4na3T1T3in%uB{?uQ^P4!{QpQe2omWe2V#4=))B>8r3K z(Cb;2(6sBEg$hUwLzhoiT0#DI(!1rALz4G43*q2~@+XlH0rLxcZqmgTvRZ_n%a%7P&G zIIaB~0r@z9L-3F2YVe>5#CJvjL5UyD@SHisfv+T}x!eJ%;+Y9?Hv#quWN{(LSBmg9 zKAQ~@za+N%9Z&dQ1AR$|U52OZq>k;8T0~K{iwRc|$A%H8HoW_aiNvvCID|k_ob0_R zF(jR6u^NDN0DT{yBfpGzXa02mM;U%_8d<_Km#@Uo_>}N~*U4 zfzh+?pMa$NkO~_nuCa<~dZ)R$dD>>(3FPGm|K7+uD`3K+1Yo8z?7=Z3R}^%~WLI{VEDDo(M-h4W#N~RC`n5HVGR$}#55ubz`e^ad0gYxx& zY(M!cJHg+!R*eZh=d8rKdd1Pi3@v`Y>bh1|4=%ifZmY!hCY0JRN3+IY#K{dM8{vGt zJ)H#>_6P9~FVGz`#g_zkx%)8$?risfX^n3Zj4gdqkD0kgM+;wnJyJ5Idg$V4X&G}o zO6hW8bV1HN00?}EeI223nmj@Bn2P|BlCG-wss?X3n*-cn#6WFU(DY`&%)PJu!S|Oz&B(CDzuE)TvIwt!M`-Q6Sy%5o;cv%eF6p$FL+4N!cr5pc|^kJaBM`OlypZu{HT<4VUBv5a~d%}#lbW)Dn!0&A+1!xkEYe;{8K{!Hk z%wx#6PHor@LCkj(&pJj_H=tg;x7~BT99Hp{`wBo90eGIlSy9hf+_X1cO#zTPvcLxg z(8GK@S?>Xki@k#pvW9qp%Q)T6J?d(n$&vz7CIft%a8Zs-N)TjcxSYS)Kx(1~Z=0;q zD8y9|RDtRb8meS-*k{vU`!Y26>xh5#ilUBwxHP;;I{VBSUoSQo^J*XrB^Rsu$G;Me zC?RGox(VDAvSBoE z!MZQFgBn%hpBwz`*Ie6`7~wCV%tN8|U>56t-v}RDaMXc~);ia?h}w{4ILFOcrD#@A z5|PV+D1$#*I5PsEtY<<_YuQZe@$4v=GJx;C+w6=dI^*Uei`g-BS>U32Z#OkWpOjrf}n#xveQ`t@5KXV-*k;}ZosuqNGzTy+U ze?#PIFUe;i#MTc${)DGyFV3~f%NdO}#!}s&ld6#{f778bi6W0yE=*Ch5QRC36J_Nb zg^z&anx3sNpPc1p-fb!VG-M`6CuQ*>b+sGSG%fPJT8&<`^l-|yr&!d`&usQ?1u z<3icVJ~-FkN%HtJP%`nQ-fGuKf`K?%#@(c=xgGN-RRHgHK)W(Ps0!OIk{dFp1k#XS z9!HMIrbGb9_#hEjpQos{O-LEY=x^tu|Ksx(#3wQLJU37*qm8!##Z+}`YYw<|d`TKW zk()*`Gc)Tzty9y;&-P=11%V)(KR|YLnmfl=U`#MOCs<%?>H3q6R_2%vpqO51WjjuJ zKAUs|LH3?$~eej;?1P--VXy;ONRKmA?L*s5^1PP}@! znPnNrh9Trjge~48%*)HuI2_J>eh;UqxbBL7b&dpGO~;8I$b?0JtW0-xkoUxFQ{i=F z;@obF+C?!@Ej0@CD2ZQVXaS#HB#b z&;l?xR&<1&nIN0_jI}Ugjp_?ik;1?Czln3$y+|}di&O1mZy`axL%rPG^ihhv3)av= z%v#uUJ|DIylGq8UDrX3Kn4Alit^u<~;%mMi-i?(1qPpy9o~(thH?;@Xb#>}eBDHxW zyNuAqJ%8GdOKoa8V;MA!cmiDNW|eMbi`R=Z}JqX$W2+c?u*1g*e)ACj!_vZ@Jo8+SIWa* zf5N0DPf|tosuGtqL*=J#pi7dO)KCZ8m)a$xSl52}MWlM9-qC9j zkA%KPf&g=#Apny@c49b~4>=cB1*FvhmY39&ebPtP53hoai%sgHIKO`Xak;DFH$!2x zCb?9&oHAwKryI$}pOBP@c$yHybsH48@dfxz(;9gAgQ>r#iT^dlp)e)$7f9kQ%M+L1 z9eQpXrvB}GF-GdthT(*037m9Wl8djS{+!jzYi~+la!ih@cPzY0DzT>y>o1EQr{B_3>C;KsAu-K# zi;|G#8{qsrIK*)hL?8}Lk0z2jd{nK*B=}#Kk)HWx&Z*8aZ-MZuxKn%Xca|Pd_ie!V zK1-B^_C@5z*nkz#nTSzkDL{Oh?<3b{DOYaeEP~yDu7crR=YIN34#x&6dCT+rqwa0f zv)j@OjTJ+^6Y+YDHBT|f4PmP$aN+J zW{tnh49jjNDeG&B3jz6XR-}nZEk-pQfd8SG736CUh)?HE@iyr#VkYC1U(!Wk8qPy| zagPdhuLWBHyAV-k3h#5#O=OFTX}6K7M@rE=asH8Q(C|d{l-~3K{oy~sEcNjXgE`h7 z9144tS5{6f#WgYUk4H)`#5EQ~Q$#f<)j5RZF2}Ios6F_yU?w%R1(5h{XUrS<;)CLU z*BdZIX;@0&T%@Hg?+-r9_uS9DZ_eXD)t2G~m3{LxRutiQ*P+?j;$f z))mRn>CqW5zRKwr1@#u zyhL2y2xejmv4bP4;NyPd0oB=$!)&@rf@Q-Z*M|o|EVCgwuFlTR`F>1kTNvXTOho8{ zS_b{%*O#9N*r0{x&>*e~M`DM{^R)SoIUu!APEuKUPrh&}d$mBrqN*=>dk<7cj7ad~ zW=91VpF=GfKpPo>Qa6C&t+E>M*3#4K%pJQY3QMH+c1HD48nBIy%<;-PrOm%*CkkV@ z-kL~k18_T)Lm_-JC#y{rLBT2*@f0ebehKvb!t_-j#>U^~cDoI$IZ{5)Hu_?#>o|%M zYi)tP6!MR_43eJFl~gC1+Sp|!b(2Q3NGU{9Cn!H~Y<9dGE$(}>mtQ${>1lC~H{(Qs zP^|WN<~tCL&VzF-Qb-#vhCp!#y3ND0wE+5d$W`WCznGwCwO7}BMobY{AR;^a#e+J| zb1EEfpS;ug2F;IMi2gLG&N@f8m3{t1DH53S?`ME~bO$bl?%d-Cfwg%Y#7#HJk1!cs z>jJo6-T!ig>6uUI8|?Q3NQ}dV%%gfPcbq3 zK$zgrzRVm!`yj_m6|KQ@r+lB}=)6?j*}gcFaGGQo9>*X0dvdfGj#E`mrYmSAXY1b6 zR+hUTUbK8PY5J&YRUud~p^yUrzRdNc{WcDDy_ME-s&Yd1gf=Jw5U2acuCHDzpCNPq zuH9#1(o9`mD!t>lh&=3%eqb~frcY+Wl688IU%1m{oqFNGO`?DX0Q!YBjalt|N>y=J z;_kQazBsZe$~rPg+DHsHYy6Cs5f^-t<{(x}HbG`7T>xfkSTjd~B2w#sTz#wo%jesj zb3S<0ol`pF9&i7MrRIWQ(LH+rP&m&EO)1ZzuE;Kankyr4EY#@Qr0T+z6{;@-$h>MA zlNLBPZYHz*MV`;$|a#(oHm%@L_j36pH}|ADG|iZ}Uq)tT##r z`^_*C0#n2R(yLJn1Bo1m8m7x{n?=MvWLur0;E`P}TK zg04Kwl4(hzNh6vlTKl~lp}0FhOexwx{o|3rMAIv26_um&t{E4-rr(VM&x%er)Bv(} z%WlI0=4n1cX;$bYLR8g){xG+mbkTeY1gP9;VWPJ|xMZnnQ*@XZW?kpP@=pc|1KIly1VR6{>1Np+L&qhdwWNu@Uvq4-3Dlw`Ai3zJDvq7Q}e+4 zrLAiPzbX*?aWP8ofb0zuwY-hwueX`GC5D?+N6VOs<1P{fwBo%?%ho88KE0G3=K$57 zZ-XC`uw45KrI?!%w}54JHwn=+6om>(jt`E%i_K41FNzaP?GCyK3&e7~w#i>i!raQ6 zcd;0ts&1-=Dmr6%a}60H6pqxJW)Z1pQQ~DwX%)kYn#@&=X%i%=gYk1%6V*3nni ztP-G8iYnoww=TuofKo<=4caJ65}S|yLAV#Sl=}N_@`;~LQ6rjs;0bQ~T5HL3McwB9z?_b^#X>)PnWE>4 zMN;r2=I+*YeRsY&I7NZUm=dt^OV9uLmo_V(y!X>5L7RjfkC?wX1nYPEmx=<ojWC#N&^pFU%f!^X!hxc8ua<#~QS< zvmAfR5lp3}u=W}xdxfdq{qAYoyuo*v6RkUi{lY>8|XY+;q$)AKg%ua@XkC5 zAH1bg=lb;{9%FFT#)McZTp$Tf9C-kn(=aDYjqV1*>^p%6GTW}BMh}13LogC+O;xvp zN#Q01J^3j#s~zx(XECV#XoL}yij@|{g)O+`)E#&Bb%e9(;L5(%Vs4Xfzv^^NJ_EF) zI><|vTTc|X9Zr^di+CER#+K(a!^cr{w+@=s)nw^`i>hVA^$2Fs^cvpd?x1${3+bBV ze9G7UQczm$@l;w}G~!besq&unbLDVZmVDp|wcK*Gy!<4M+qNY9>Z1L zbC%&M?{wHp1O_>iiD;5pmZA5|sCU#zPC2W4Uz+}^^}W3vsC}wP3T64}Cz}l{2J=m@ zXG0xD5??%GkU$om++h$cQ2 z&iq8HT(~Z9yNh1b-AynL(KXeEC91P^R3EEkTWzC%C7)Ikd2Gwwk!Pc#xK0YCzv3e( zeHq7RPHv1}VA?WecI~dAINQ`@O9#&j^FKq$?RmtjaAt5#ai5u5#-7ALX#g;>7hqT+ zijyOiF~K!u9WC-iapcCL_H7N&Z9G0$fPLY_(Miz+CHij+r@_S_CSlnO=MZ+_Kj(*K z8AnkBMF)8}uNKq?_jRPzbNVsJV0fxXg9Wo&_N&LdLwN9H48+$Z1GD2Yk9zYek<2J^Z{-Q#kzm|t~EtMhmu+9S&{jIpWA4*S_2lmq!c|zS} z{6aMwtqYdxC*Q)=CiCwxrEOk0di9Vvu%_aO`l(#4%Hc$vYjGaZEKPC3ASGmnl9lXT zUB0Q}@Q%8vM#uGGEchkV6nBZ9a2T^ls#!Q#D{-n;ptHIRwF5(Nj+lH`HreLr5+VhX z+Xm0aR{35Y*X>~c=wlLLZym`#HQq$a2-S2(-ly1z%5$czm<@;#DUKqtZRa~Z)yMPO zSMGQ-e=TZ`Hj#R>ubPKEH#j^uP=SnV2)O3c2IYpPCo-j3-#ENOS?4H#M4`Xu=uMlU z7mxHft9G<2$L4gSQaYjG+3SC-#9jVI+n&tO;c?G2(i`8$<1bvF+oMJn(x|$3=4OYvV{#Y|VXh0_)}q^V*3w{lP* z-seP%mJfHA>EddQUKTqQG~9IxTFNiVG(oU!2@wDX3HqQpBt9IIJ=^aJy0ys*?aQcE+Zm_4(qf36RIg!5|qkRxo?4Cv|O0&gpK}Z{^3Xl^x=b!~sS zM&0ie*^{$=h=o;~A1vHGOK3(%#v#n@eui651{Gs{JLYgV@>tnpt4Wr%ooX}SH9L;RPGxrMb{P|k3srB5>l?$G5B66%LUa^`~ zmEg?Ma|g*B7vUQuVVPaST+IMR-(o0WlE6Gur45UleR6oo&+-Drom_ve-m+CUZ${v= zsPw2vyt`dj!)~tyqQPp*>6}G@{HoTATE82DprXgN_8ukV;p#~7N0X`AQUC|ZGod6XFkg7Mk;n%~)DmY+ zd*kJ2Bq!TkCIgx3*cj^p7_2if_S4lulj%~E^@8NjWN-7ziRsSwb|KW9``?wO`#ob_n2;}qlGlhfeGIKm> zO4?aPWOf1&(_%na{rOkCa>U3k5Sn>45eQP9HcMT0bgYLG69e2&5W>_|NsV1tpb-Gn z6a*(a8Q2)Sb}77nrSOIw@Q;N3HSz~tR?sa#AUWVBI@CFuLJ~7GcF{67WB47mU(eJ7 zUK_hiv(W>L)o}oBx)RmG4QEi(*FpO767YU-emKj(u;7@|Mm!t|Fx*(xk7KR=5#ml7 z9Z9U?oZl9=8eb6T6X`aWJ|fQV+OU4u7BJCpxoFOJKU$&Wp@uB&E?~NDcNDC}Ea!Qm zf`~h=U$r8Ei0}I>G^v&U=F}tY;rnu6ZD3dr0Kuo_88ndsf14gq=;F2(LxuS3hj)TC z!fIy+{Ct4c(b0vrb!~%>MspTg0GvxH-SIDQ&UVzMa}2<_gUcg|yt~mlw)X_JtiW<1 zh(DkCyX6#w$58ROow&SW4Wqsjy}yvwITO(&^(p7|tS2 zl+){cODSfY$0q{J&)6+zwEuknen-*spmfOcXS5{1=dF%ka{)f>h@FDIK3wVi=hz?-RVBQ(A`L?e@<=Q3>PcniC8 z3MjA_7a9a%!c8l!I$}qmLO#`;T`ju9#>BXut1aDRr zgMe=%RJj^lUGl+1@YqASuK|8xW2h^1*$I;Y$pCghdX{7T{%t*p9Szf_y58PffBG`1 zy2QH$r7Mo|rpKf0d3a7TzBE4Evb*X$yZ~bYBu|UlhSF(O;Lq*_i@g$DKYAOT!=vl^ z>^$$%Zv(RcqL0`@PUlzL+&lB|x@@VjjDCt_R!A7HTe1Bvw+TAZWfy9a538l= zA#}!Xv555zia#yqWdI(JpF=VVr$=0pa18U0gh@keYuh?^UwlWyg%R*f!e{J8mL7*H zrn*nc$otVwa7Nl39^|uQBY<0u0ozYUdR$!D6_yvECR3r`Tl|snqKBiQ;L@dX7U^#o z#C;<4xrZ1HHwj4TtIv)r9objv?lvg0vh_$45?d}|?)Vf(0(?t1SakK*>{np!BN~I; z;#ie}C%t0E4C8&I%o`PB1Sr_=#BP~F9SJ&VWWBLt>l_rubl}|Pe`}p~Ah7lk#hxs7 z1r`@uTJkHy&*E6iv6UdQt`zQasLY~*E_dWmY-<1;_T0)Ty?bHDVVi@(-IwbKRTi-T zkWqFeI|s}7LEMiPpMik>6X}_Y4@pmHu2(KzNay8Uc;MTqnaZqr<);3Dor|pc1cU0l zPy1qc*K^DMZ63MK|EYO=<;Q%3o<1jCC?$H5j%!T`ItGejb0e6xNd^8qmf>?@az5hr zj8td!*WP;hE<1p$g_X8_YCg8$lLshZDd5on#d-e2oRzbHoCO}}FkBbHx^l+Y zA6)jDeweKEIZS?J&5q_NRWaQvlL9sU#}O@qq<2a&{DkGPU}avx0sHBiA*(HnqdUU) z@~BP0=(~h-ab~ID4Tn;*_{h()mm`?O!lI=U)bV{z%58=GuRw*BiRjvu^`7~i)ab1- z(Y4p9JpbI$S?+x6ccG3sVI}!20eCC%smZr^aa?;3WsW`^I}Xw=R6+HDTY39*C0CD& z29Satr`N2Ai*K9kg&lk4F}??Fw%7Fzs#-y##km!0+RoTmhsd#MQ$C}?2)V524~7JZ z00{E(!?(XRol^~!onl!JHoq_@%5Tjwd_UNx4jh7yX$??>E1k`z10^u|2S0hD8eDzB zdhnmyGv|5RrHSGHeE3yu#c;R(+u)R*z^eC$?0rrr(zi=YwOr$Dnz)@>{ zmZ%(MRLh@TO)8<1omLU?ZeP>gX2Suy4eA$N`0YqWLp)R6k_=`!nXJ(TeOchFu4S@h z_)oqqtraj$KfS|*eHF-t&diIET95j)U*kexUgX({&BuAqR-K35Oj{C2;+n9|DL z^;{5XIS5{?s6X7$+S&%kVZ^q|&(Kvbk2;#V^P^(=~eI8@<%ih|k8h>)z_W_X5( z{Z7+9pki)VB1h5hMlB*{>-GAaGFtIIzt4^*?4U8RS?L3B7~UiBL(L~4e>jo}O61&G z+kkXW3~cJgYu(hv+fF@~p1J%@S~4)oin4^^K^+2k4K;z85CJ=XzR4tQI^(Pv0vpc+Ru`~$aYcnHDj5y$ItDcB zR*s@kSfnk~OD&MusjXa8Q}FuYlwxMT(}K03RMnDh$x2k4F&9$w!4sG*fZMf=iKXZE z?6}$XDNfY%0kr6>yN@{Tc1Ei>BZR=%E$OERiSrsN?g>s9Tq5Owr)o94Vput z6Yt;if71z2zHsE@ABTP95bW4HDxMbgPwQOt*V<(ayut{58zHwO>ZAbPt!FMjwt|m>mHVr2qH+ zn50E|XSM)h2S^~m-2r@KurRyfY=Zw|{sDoXy*IYPg%iOK?!gHN%mMy6`2hmy4e(F- zZlnU^fBydu{;w@hs{u0(M2L=qH-^oP!AoMj>ZSHe^Akp854qv8k$!Ln5FzfsOeGs* zxgTxOM@Zg=vpe9&j4LWGf^zdGx;Sb;E{88D_GsknoWn>8qOAY6Kl4ShX=&08Cz z&z(&qqA;@d+r%l&-WC=X{k9{BP;4k|aW1&bKEYLL#>qu1u-kAMJ3GOiv$V3mU%e4M zt;vWe){K$jX$?2BLeg*$BO`~yr5U>+>IDJIWj`N>RIKl_+dSpiI&dghGplXjRbdD5 zvJ0&ZS;aTNveMAl7e*#tCXTRW(#)bS6Z68 zbgg`0qbKM&A7Rj87!-k*a|?4MS~2641x*_Fh0~8?+?iKrh;ui9B(I4~xXt z6kJ^XEWhNf?wOJ})lyq(kL8JAt?Rqxs&;Kg{1acW`rADXLmiHzqq9_z)pI?_%!Iq4 zp(q_FWzd-IrA7X#qCWGAog924WZ>1nKAU|lcb+@D&*EyErtPx!G_;|I_t|2Jd%tyW z{l9cQv~DAd;Fp`r@>VA8<=wW?^4rxr`QCE9I1_H=FMABd*KvO9^nozv9e>1L#$Oc9 zh4>eJyP10rRGl-p0fBTR@bl=mn+MXq4X=D-#&4~=LFy9x^XJ|FsT+lXm8W7h+}-J# zQXdQ{&|l9C9%wnl7+m-b=)M-*mRn3qOn_D}qZ5aRh`mOJpzE*xz>jC7_Z}WoofH%9 z{yoHAs7S(GZs9&=6Fdclf!)ylUGT)Z|HnpCYt+c#Wrb1@dh~tu>Xp@XeSN`)JaW<~ za$h!hcbHKkjPh2x?2in00?2)`avM>eQn^9bU(Ch`Hm+Walt#GVj3g)!IIni~ZzIfc zR@`IXYRuNIdzuB(D@&119;JGG-hw_1o@_l~9~DpX-iiv~lDZP{3}GM#Zw>JeO8xod zON_;o)-*Y64_?kr(afvnT-UOPn8{uDyiANa5KgSJ>3myG#e*p4Kn|!8I&mUy6r>wb zT1|8gpBq!OhE_FTXEv z>PIy)An*4J^i|zaXe4xpnw^ZY57)oJc8DDQL6*ov%0DJOlJ0$Mc2*k6emPbW5+yyc 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 diff --git a/hdk/docs/ppts/simulation/Slide3.PNG b/hdk/docs/ppts/simulation/Slide3.PNG deleted file mode 100644 index 4d91a41399255c724fde0a606b85140e2c45ca66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23966 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 bOSz}=WwLT+byz - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/sdk/linux_kernel_drivers/xocl/Makefile b/sdk/linux_kernel_drivers/xocl/Makefile deleted file mode 100644 index 9a334137..00000000 --- a/sdk/linux_kernel_drivers/xocl/Makefile +++ /dev/null @@ -1,70 +0,0 @@ -# Amazon FPGA Hardware Development Kit -# -# Copyright 2016-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Amazon Software License (the "License"). You may not use -# this file except in compliance with the License. A copy of the License is -# located at -# -# http://aws.amazon.com/asl/ -# -# or in the "license" file accompanying this file. This file is distributed on -# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or -# implied. See the License for the specific language governing permissions and -# limitations under the License. - -XOCL_DIR = $(shell pwd) - -obj-m += xocl.o -ccflags-y := -Iinclude/drm - -xocl-y := \ - xocl_sysfs.o \ - xocl_bo.o \ - xocl_drv.o \ - xocl_xdma.o \ - xocl_ioctl.o \ - xocl_test.o \ - xocl_ctx.o \ - xocl_xvc.o \ - xocl_exec.o \ - libxdma.o - -CONFIG_MODULE_SIG=n -KERNELDIR ?= /lib/modules/$(shell uname -r)/build - -PWD := $(shell pwd) -ROOT := $(dir $(M)) -XILINXINCLUDE := -I$(SDACCEL_DIR)/userspace/include -I$(XOCL_DIR) -XILINXINCLUDE += -I$(XOCL_DIR)/../xdma/ - -all: - echo "include: $(XILINXINCLUDE)" - echo "sdaccel_dir: $(SDACCEL_DIR)" - echo "ROOT: $(ROOT)" - echo "XOCL_DIR: $(XOCL_DIR)" - $(MAKE) -C $(KERNELDIR) M=$(PWD) modules - -install: all - $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install - depmod -a - install -m 644 10-xocl.rules /etc/udev/rules.d - -rmmod -s xocl || true - -rmmod -s xdma || true - -rmmod -s edma_drv || true - -modprobe xocl - -clean: - rm -rf *.o *.o.d *~ core .depend .*.cmd *.ko *.ko.unsigned *.mod.c .tmp_versions *.symvers .#* *.save *.bak Modules.* modules.order Module.markers *.bin - - -CFLAGS_xocl_xdma.o := $(XILINXINCLUDE) -CFLAGS_xocl_sysfs.o := $(XILINXINCLUDE) -CFLAGS_xocl_bo.o := $(XILINXINCLUDE) -CFLAGS_xocl_drv.o := $(XILINXINCLUDE) -CFLAGS_xocl_ioctl.o := $(XILINXINCLUDE) -CFLAGS_xocl_test.o := $(XILINXINCLUDE) -CFLAGS_xocl_ctx.o := $(XILINXINCLUDE) -CFLAGS_xocl_exec.o := $(XILINXINCLUDE) -CFLAGS_xocl_xvc.o := $(XILINXINCLUDE) -CFLAGS_libxdma.o := $(XILINXINCLUDE) diff --git a/sdk/linux_kernel_drivers/xocl/cdev_sgdma.h b/sdk/linux_kernel_drivers/xocl/cdev_sgdma.h deleted file mode 100644 index d3700260..00000000 --- a/sdk/linux_kernel_drivers/xocl/cdev_sgdma.h +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - * - * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - * - * The full GNU General Public License is included in this distribution in - * the file called "LICENSE". - * - * Karen Xie - * - ******************************************************************************/ -#ifndef _XDMA_IOCALLS_POSIX_H_ -#define _XDMA_IOCALLS_POSIX_H_ - -#include - - -#define IOCTL_XDMA_PERF_V1 (1) -#define XDMA_ADDRMODE_MEMORY (0) -#define XDMA_ADDRMODE_FIXED (1) - -/* - * S means "Set" through a ptr, - * T means "Tell" directly with the argument value - * G means "Get": reply by setting through a pointer - * Q means "Query": response is on the return value - * X means "eXchange": switch G and S atomically - * H means "sHift": switch T and Q atomically - * - * _IO(type,nr) no arguments - * _IOR(type,nr,datatype) read data from driver - * _IOW(type,nr.datatype) write data to driver - * _IORW(type,nr,datatype) read/write data - * - * _IOC_DIR(nr) returns direction - * _IOC_TYPE(nr) returns magic - * _IOC_NR(nr) returns number - * _IOC_SIZE(nr) returns size - */ - -struct xdma_performance_ioctl -{ - /* IOCTL_XDMA_IOCTL_Vx */ - uint32_t version; - uint32_t transfer_size; - /* measurement */ - uint32_t stopped; - uint32_t iterations; - uint64_t clock_cycle_count; - uint64_t data_cycle_count; - uint64_t pending_count; -}; - - - -/* IOCTL codes */ - -#define IOCTL_XDMA_PERF_START _IOW('q', 1, struct xdma_performance_ioctl *) -#define IOCTL_XDMA_PERF_STOP _IOW('q', 2, struct xdma_performance_ioctl *) -#define IOCTL_XDMA_PERF_GET _IOR('q', 3, struct xdma_performance_ioctl *) -#define IOCTL_XDMA_ADDRMODE_SET _IOW('q', 4, int) -#define IOCTL_XDMA_ADDRMODE_GET _IOR('q', 5, int) -#define IOCTL_XDMA_ALIGN_GET _IOR('q', 6, int) - -#endif /* _XDMA_IOCALLS_POSIX_H_ */ - -// 67d7842dbbe25473c3c32b93c0da8047785f30d78e8a024de1b57352245f9689 diff --git a/sdk/linux_kernel_drivers/xocl/ert.h b/sdk/linux_kernel_drivers/xocl/ert.h deleted file mode 100644 index 6b5c5bda..00000000 --- a/sdk/linux_kernel_drivers/xocl/ert.h +++ /dev/null @@ -1,310 +0,0 @@ -/** - * Copyright (C) 2018 Xilinx, Inc - * - * This file is dual licensed. It may be redistributed and/or modified - * under the terms of the Apache 2.0 License OR version 2 of the GNU - * General Public License. - * - * Apache License Verbiage - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * GPL license Verbiage: - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. This program is - * distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - * License for more details. You should have received a copy of the - * GNU General Public License along with this program; if not, write - * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA - * - */ - -/** - * Xilinx SDAccel Embedded Runtime definition - * Copyright (C) 2018, Xilinx Inc - All rights reserved - * - * This file is dual licensed. It may be redistributed and/or modified - * under the terms of the Apache 2.0 License OR version 2 of the GNU - * General Public License. - */ - -#ifndef _ERT_H_ -#define _ERT_H_ - -#if defined(__KERNEL__) -# include -#else -# include -#endif - -/** - * ERT generic packet format - * - * @state: [3-0] current state of a command - * @custom: [11-4] custom per specific commands - * @count: [22-12] number of words in payload (data) - * @opcode: [27-23] opcode identifying specific command - * @type: [31-27] type of command (currently 0) - * @data: count number of words representing packet payload - */ -struct ert_packet { - union { - struct { - uint32_t state:4; /* [3-0] */ - uint32_t custom:8; /* [11-4] */ - uint32_t count:11; /* [22-12] */ - uint32_t opcode:5; /* [27-23] */ - uint32_t type:4; /* [31-27] */ - }; - uint32_t header; - }; - uint32_t data[1]; /* count number of words */ -}; - -/** - * ERT start kernel command format - * - * @state: [3-0] current state of a command - * @extra_cu_masks: [11-10] extra CU masks in addition to mandatory mask - * @count: [22-12] number of words in payload (data) - * @opcode: [27-23] 0, opcode for start_kernel - * @type: [31-27] 0, type of start_kernel - * - * @cu_mask: first mandatory CU mask - * @data: count number of words representing command payload - * - * The packet payload is comprised of 1 mandatory CU mask plus - * extra_cu_masks per header field, followed a CU register map of size - * (count - (1 + extra_cu_masks)) uint32_t words. - */ -struct ert_start_kernel_cmd { - union { - struct { - uint32_t state:4; /* [3-0] */ - uint32_t unused:6; /* [9-4] */ - uint32_t extra_cu_masks:2; /* [11-10] */ - uint32_t count:11; /* [22-12] */ - uint32_t opcode:5; /* [27-23] */ - uint32_t type:4; /* [31-27] */ - }; - uint32_t header; - }; - - /* payload */ - uint32_t cu_mask; /* mandatory cu mask */ - uint32_t data[1]; /* count-1 number of words */ -}; - -/** - * ERT configure command format - * - * @state: [3-0] current state of a command - * @count: [22-12] 5, number of words in payload - * @opcode: [27-23] 1, opcode for configure - * @type: [31-27] 0, type of configure - * - * @slot_size: command queue slot size - * @num_cus: number of compute units in program - * @cu_shift: shift value to convert CU idx to CU addr - * @cu_base_addr: base address to add to CU addr for actual physical address - * - * @ert:1 enable embedded HW scheduler - * @polling:1 poll for command completion - * @cu_dma:1 enable CUDMA custom module for HW scheduler - * @cu_isr:1 enable CUISR custom module for HW scheduler - * @cq_int:1 enable interrupt from host to HW scheduler - */ -struct ert_configure_cmd { - union { - struct { - uint32_t state:4; /* [3-0] */ - uint32_t unused:8; /* [11-4] */ - uint32_t count:11; /* [22-12] */ - uint32_t opcode:5; /* [27-23] */ - uint32_t type:4; /* [31-27] */ - }; - uint32_t header; - }; - - /* payload */ - uint32_t slot_size; - uint32_t num_cus; - uint32_t cu_shift; - uint32_t cu_base_addr; - - /* features */ - uint32_t ert:1; - uint32_t polling:1; - uint32_t cu_dma:1; - uint32_t cu_isr:1; - uint32_t cq_int:1; - uint32_t unusedf:27; -}; - -/** - * ERT command state - * - * @ERT_CMD_STATE_NEW: Set by host before submitting a command to scheduler - * @ERT_CMD_STATE_QUEUED: Internal scheduler state - * @ERT_CMD_STATE_RUNNING: Internal scheduler state - * @ERT_CMD_STATE_COMPLETE: Set by scheduler when command completes - * @ERT_CMD_STATE_ERROR: Set by scheduler if command failed - * @ERT_CMD_STATE_ABORT: Set by scheduler if command abort - */ -enum ert_cmd_state { - ERT_CMD_STATE_NEW = 1, - ERT_CMD_STATE_QUEUED = 2, - ERT_CMD_STATE_RUNNING = 3, - ERT_CMD_STATE_COMPLETED = 4, - ERT_CMD_STATE_ERROR = 5, - ERT_CMD_STATE_ABORT = 6, -}; - -/** - * Opcode types for commands - * - * @ERT_START_CU: start a workgroup on a CU - * @ERT_START_KERNEL: currently aliased to ERT_START_CU - * @ERT_CONFIGURE: configure command scheduler - */ -enum ert_cmd_opcode { - ERT_START_CU = 0, - ERT_START_KERNEL = 0, - ERT_CONFIGURE = 1, -}; - -/** - * Address constants per spec - */ -#define ERT_WORD_SIZE 4 /* 4 bytes */ -#define ERT_CQ_SIZE 0x10000 /* 64K */ -#define ERT_CQ_BASE_ADDR 0x190000 -#define ERT_CSR_ADDR 0x180000 - -/** - * The STATUS REGISTER is for communicating completed CQ slot indices - * MicroBlaze write, host reads. MB(W) / HOST(COR) - */ -#define ERT_STATUS_REGISTER_ADDR (ERT_CSR_ADDR) -#define ERT_STATUS_REGISTER_ADDR0 (ERT_CSR_ADDR) -#define ERT_STATUS_REGISTER_ADDR1 (ERT_CSR_ADDR + 0x4) -#define ERT_STATUS_REGISTER_ADDR2 (ERT_CSR_ADDR + 0x8) -#define ERT_STATUS_REGISTER_ADDR3 (ERT_CSR_ADDR + 0xC) - -/** - * The CU DMA REGISTER is for communicating which CQ slot is to be started - * on a specific CU. MB selects a free CU on which the command can - * run, then writes the 1< - * Leon Woestenberg - * - ******************************************************************************/ -#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include - -#include "libxdma.h" -#include "libxdma_api.h" -#include "cdev_sgdma.h" - -/* SECTION: Module licensing */ - -#ifdef __LIBXDMA_MOD__ -#include "version.h" -#define DRV_MODULE_NAME "libxdma" -#define DRV_MODULE_DESC "Xilinx XDMA Base Driver" -#define DRV_MODULE_RELDATE "Feb. 2017" - -static char version[] = - DRV_MODULE_DESC " " DRV_MODULE_NAME " v" DRV_MODULE_VERSION "\n"; - -MODULE_AUTHOR("Xilinx, Inc."); -MODULE_DESCRIPTION(DRV_MODULE_DESC); -MODULE_VERSION(DRV_MODULE_VERSION); -MODULE_LICENSE("GPL v2"); -#endif - -/* Module Parameters */ -static unsigned int poll_mode; -module_param(poll_mode, uint, 0644); -MODULE_PARM_DESC(poll_mode, "Set 1 for hw polling, default is 0 (interrupts)"); - -static unsigned int interrupt_mode; -module_param(interrupt_mode, uint, 0644); -MODULE_PARM_DESC(interrupt_mode, "0 - MSI-x , 1 - MSI, 2 - Legacy"); - -static unsigned int enable_credit_mp; -module_param(enable_credit_mp, uint, 0644); -MODULE_PARM_DESC(enable_credit_mp, "Set 1 to enable creidt feature, default is 0 (no credit control)"); - -/* - * xdma device management - * maintains a list of the xdma devices - */ -static LIST_HEAD(xdev_list); -static DEFINE_MUTEX(xdev_mutex); - -static LIST_HEAD(xdev_rcu_list); -static DEFINE_SPINLOCK(xdev_rcu_lock); - -#ifndef list_last_entry -#define list_last_entry(ptr, type, member) \ - list_entry((ptr)->prev, type, member) -#endif - -static inline void xdev_list_add(struct xdma_dev *xdev) -{ - mutex_lock(&xdev_mutex); - if (list_empty(&xdev_list)) - xdev->idx = 0; - else { - struct xdma_dev *last; - - last = list_last_entry(&xdev_list, struct xdma_dev, list_head); - xdev->idx = last->idx + 1; - } - list_add_tail(&xdev->list_head, &xdev_list); - mutex_unlock(&xdev_mutex); - - dbg_init("dev %s, xdev 0x%p, xdma idx %d.\n", - dev_name(&xdev->pdev->dev), xdev, xdev->idx); - - spin_lock(&xdev_rcu_lock); - list_add_tail_rcu(&xdev->rcu_node, &xdev_rcu_list); - spin_unlock(&xdev_rcu_lock); -} - -#undef list_last_entry - -static inline void xdev_list_remove(struct xdma_dev *xdev) -{ - mutex_lock(&xdev_mutex); - list_del(&xdev->list_head); - mutex_unlock(&xdev_mutex); - - spin_lock(&xdev_rcu_lock); - list_del_rcu(&xdev->rcu_node); - spin_unlock(&xdev_rcu_lock); - synchronize_rcu(); -} - -struct xdma_dev *xdev_find_by_pdev(struct pci_dev *pdev) -{ - struct xdma_dev *xdev, *tmp; - - mutex_lock(&xdev_mutex); - list_for_each_entry_safe(xdev, tmp, &xdev_list, list_head) { - if (xdev->pdev == pdev) { - mutex_unlock(&xdev_mutex); - return xdev; - } - } - mutex_unlock(&xdev_mutex); - return NULL; -} -EXPORT_SYMBOL_GPL(xdev_find_by_pdev); - -static inline int debug_check_dev_hndl(const char *fname, struct pci_dev *pdev, - void *hndl) -{ - struct xdma_dev *xdev; - - if (!pdev) - return -EINVAL; - - xdev = xdev_find_by_pdev(pdev); - if (!xdev) { - pr_info("%s pdev 0x%p, hndl 0x%p, NO match found!\n", - fname, pdev, hndl); - return -EINVAL; - } - if (xdev != hndl) { - pr_err("%s pdev 0x%p, hndl 0x%p != 0x%p!\n", - fname, pdev, hndl, xdev); - return -EINVAL; - } - - return 0; -} - -#ifdef __LIBXDMA_DEBUG__ -/* SECTION: Function definitions */ -inline void __write_register(const char *fn, u32 value, void *iomem, unsigned long off) -{ - pr_err("%s: w reg 0x%lx(0x%p), 0x%x.\n", fn, off, iomem, value); - iowrite32(value, iomem); -} -#define write_register(v,mem,off) __write_register(__func__, v, mem, off) -#else -#define write_register(v,mem,off) iowrite32(v, mem) -#endif - -inline u32 read_register(void *iomem) -{ - return ioread32(iomem); -} - -static inline u32 build_u32(u32 hi, u32 lo) -{ - return ((hi & 0xFFFFUL) << 16) | (lo & 0xFFFFUL); -} - -static inline u64 build_u64(u64 hi, u64 lo) -{ - return ((hi & 0xFFFFFFFULL) << 32) | (lo & 0xFFFFFFFFULL); -} - -static void check_nonzero_interrupt_status(struct xdma_dev *xdev) -{ - struct interrupt_regs *reg = (struct interrupt_regs *) - (xdev->bar[xdev->config_bar_idx] + XDMA_OFS_INT_CTRL); - u32 w; - - w = read_register(®->user_int_enable); - if (w) - pr_info("%s xdma%d user_int_enable = 0x%08x\n", - dev_name(&xdev->pdev->dev), xdev->idx, w); - - w = read_register(®->channel_int_enable); - if (w) - pr_info("%s xdma%d channel_int_enable = 0x%08x\n", - dev_name(&xdev->pdev->dev), xdev->idx, w); - - w = read_register(®->user_int_request); - if (w) - pr_info("%s xdma%d user_int_request = 0x%08x\n", - dev_name(&xdev->pdev->dev), xdev->idx, w); - w = read_register(®->channel_int_request); - if (w) - pr_info("%s xdma%d channel_int_request = 0x%08x\n", - dev_name(&xdev->pdev->dev), xdev->idx, w); - - w = read_register(®->user_int_pending); - if (w) - pr_info("%s xdma%d user_int_pending = 0x%08x\n", - dev_name(&xdev->pdev->dev), xdev->idx, w); - w = read_register(®->channel_int_pending); - if (w) - pr_info("%s xdma%d channel_int_pending = 0x%08x\n", - dev_name(&xdev->pdev->dev), xdev->idx, w); -} - -/* channel_interrupts_enable -- Enable interrupts we are interested in */ -static void channel_interrupts_enable(struct xdma_dev *xdev, u32 mask) -{ - struct interrupt_regs *reg = (struct interrupt_regs *) - (xdev->bar[xdev->config_bar_idx] + XDMA_OFS_INT_CTRL); - - write_register(mask, ®->channel_int_enable_w1s, XDMA_OFS_INT_CTRL); -} - -/* channel_interrupts_disable -- Disable interrupts we not interested in */ -static void channel_interrupts_disable(struct xdma_dev *xdev, u32 mask) -{ - struct interrupt_regs *reg = (struct interrupt_regs *) - (xdev->bar[xdev->config_bar_idx] + XDMA_OFS_INT_CTRL); - - write_register(mask, ®->channel_int_enable_w1c, XDMA_OFS_INT_CTRL); -} - -/* user_interrupts_enable -- Enable interrupts we are interested in */ -static void user_interrupts_enable(struct xdma_dev *xdev, u32 mask) -{ - struct interrupt_regs *reg = (struct interrupt_regs *) - (xdev->bar[xdev->config_bar_idx] + XDMA_OFS_INT_CTRL); - - write_register(mask, ®->user_int_enable_w1s, XDMA_OFS_INT_CTRL); -} - -/* user_interrupts_disable -- Disable interrupts we not interested in */ -static void user_interrupts_disable(struct xdma_dev *xdev, u32 mask) -{ - struct interrupt_regs *reg = (struct interrupt_regs *) - (xdev->bar[xdev->config_bar_idx] + XDMA_OFS_INT_CTRL); - - write_register(mask, ®->user_int_enable_w1c, XDMA_OFS_INT_CTRL); -} - -/* read_interrupts -- Print the interrupt controller status */ -static u32 read_interrupts(struct xdma_dev *xdev) -{ - struct interrupt_regs *reg = (struct interrupt_regs *) - (xdev->bar[xdev->config_bar_idx] + XDMA_OFS_INT_CTRL); - u32 lo; - u32 hi; - - /* extra debugging; inspect complete engine set of registers */ - hi = read_register(®->user_int_request); - dbg_io("ioread32(0x%p) returned 0x%08x (user_int_request).\n", - ®->user_int_request, hi); - lo = read_register(®->channel_int_request); - dbg_io("ioread32(0x%p) returned 0x%08x (channel_int_request)\n", - ®->channel_int_request, lo); - - /* return interrupts: user in upper 16-bits, channel in lower 16-bits */ - return build_u32(hi, lo); -} - -void enable_perf(struct xdma_engine *engine) -{ - u32 w; - - w = XDMA_PERF_CLEAR; - write_register(w, &engine->regs->perf_ctrl, - (unsigned long)(&engine->regs->perf_ctrl) - - (unsigned long)(&engine->regs)); - read_register(&engine->regs->identifier); - w = XDMA_PERF_AUTO | XDMA_PERF_RUN; - write_register(w, &engine->regs->perf_ctrl, - (unsigned long)(&engine->regs->perf_ctrl) - - (unsigned long)(&engine->regs)); - read_register(&engine->regs->identifier); - - dbg_perf("IOCTL_XDMA_PERF_START\n"); - -} -EXPORT_SYMBOL_GPL(enable_perf); - -void get_perf_stats(struct xdma_engine *engine) -{ - u32 hi; - u32 lo; - - BUG_ON(!engine); - BUG_ON(!engine->xdma_perf); - - hi = 0; - lo = read_register(&engine->regs->completed_desc_count); - engine->xdma_perf->iterations = build_u64(hi, lo); - - hi = read_register(&engine->regs->perf_cyc_hi); - lo = read_register(&engine->regs->perf_cyc_lo); - - engine->xdma_perf->clock_cycle_count = build_u64(hi, lo); - - hi = read_register(&engine->regs->perf_dat_hi); - lo = read_register(&engine->regs->perf_dat_lo); - engine->xdma_perf->data_cycle_count = build_u64(hi, lo); - - hi = read_register(&engine->regs->perf_pnd_hi); - lo = read_register(&engine->regs->perf_pnd_lo); - engine->xdma_perf->pending_count = build_u64(hi, lo); -} -EXPORT_SYMBOL_GPL(get_perf_stats); - -static void engine_reg_dump(struct xdma_engine *engine) -{ - u32 w; - - BUG_ON(!engine); - - w = read_register(&engine->regs->identifier); - pr_info("%s: ioread32(0x%p) = 0x%08x (id).\n", - engine->name, &engine->regs->identifier, w); - w &= BLOCK_ID_MASK; - if (w != BLOCK_ID_HEAD) { - pr_info("%s: engine id missing, 0x%08x exp. & 0x%x = 0x%x\n", - engine->name, w, BLOCK_ID_MASK, BLOCK_ID_HEAD); - return; - } - /* extra debugging; inspect complete engine set of registers */ - w = read_register(&engine->regs->status); - pr_info("%s: ioread32(0x%p) = 0x%08x (status).\n", - engine->name, &engine->regs->status, w); - w = read_register(&engine->regs->control); - pr_info("%s: ioread32(0x%p) = 0x%08x (control)\n", - engine->name, &engine->regs->control, w); - w = read_register(&engine->sgdma_regs->first_desc_lo); - pr_info("%s: ioread32(0x%p) = 0x%08x (first_desc_lo)\n", - engine->name, &engine->sgdma_regs->first_desc_lo, w); - w = read_register(&engine->sgdma_regs->first_desc_hi); - pr_info("%s: ioread32(0x%p) = 0x%08x (first_desc_hi)\n", - engine->name, &engine->sgdma_regs->first_desc_hi, w); - w = read_register(&engine->sgdma_regs->first_desc_adjacent); - pr_info("%s: ioread32(0x%p) = 0x%08x (first_desc_adjacent).\n", - engine->name, &engine->sgdma_regs->first_desc_adjacent, w); - w = read_register(&engine->regs->completed_desc_count); - pr_info("%s: ioread32(0x%p) = 0x%08x (completed_desc_count).\n", - engine->name, &engine->regs->completed_desc_count, w); - w = read_register(&engine->regs->interrupt_enable_mask); - pr_info("%s: ioread32(0x%p) = 0x%08x (interrupt_enable_mask)\n", - engine->name, &engine->regs->interrupt_enable_mask, w); -} - -/** - * engine_status_read() - read status of SG DMA engine (optionally reset) - * - * Stores status in engine->status. - * - * @return -1 on failure, status register otherwise - */ -static void engine_status_dump(struct xdma_engine *engine) -{ - u32 v = engine->status; - char buffer[256]; - char *buf = buffer; - int len = 0; - - len = sprintf(buf, "SG engine %s status: 0x%08x: ", engine->name, v); - - if ((v & XDMA_STAT_BUSY)) - len += sprintf(buf + len, "BUSY,"); - if ((v & XDMA_STAT_DESC_STOPPED)) - len += sprintf(buf + len, "DESC_STOPPED,"); - if ((v & XDMA_STAT_DESC_COMPLETED)) - len += sprintf(buf + len, "DESC_COMPL,"); - - /* common H2C & C2H */ - if ((v & XDMA_STAT_COMMON_ERR_MASK)) { - if ((v & XDMA_STAT_ALIGN_MISMATCH)) - len += sprintf(buf + len, "ALIGN_MISMATCH "); - if ((v & XDMA_STAT_MAGIC_STOPPED)) - len += sprintf(buf + len, "MAGIC_STOPPED "); - if ((v & XDMA_STAT_INVALID_LEN)) - len += sprintf(buf + len, "INVLIAD_LEN "); - if ((v & XDMA_STAT_IDLE_STOPPED)) - len += sprintf(buf + len, "IDLE_STOPPED "); - buf[len - 1] = ','; - } - - if ((engine->dir == DMA_TO_DEVICE)) { - /* H2C only */ - if ((v & XDMA_STAT_H2C_R_ERR_MASK)) { - len += sprintf(buf + len, "R:"); - if ((v & XDMA_STAT_H2C_R_UNSUPP_REQ)) - len += sprintf(buf + len, "UNSUPP_REQ "); - if ((v & XDMA_STAT_H2C_R_COMPL_ABORT)) - len += sprintf(buf + len, "COMPL_ABORT "); - if ((v & XDMA_STAT_H2C_R_PARITY_ERR)) - len += sprintf(buf + len, "PARITY "); - if ((v & XDMA_STAT_H2C_R_HEADER_EP)) - len += sprintf(buf + len, "HEADER_EP "); - if ((v & XDMA_STAT_H2C_R_UNEXP_COMPL)) - len += sprintf(buf + len, "UNEXP_COMPL "); - buf[len - 1] = ','; - } - - if ((v & XDMA_STAT_H2C_W_ERR_MASK)) { - len += sprintf(buf + len, "W:"); - if ((v & XDMA_STAT_H2C_W_DECODE_ERR)) - len += sprintf(buf + len, "DECODE_ERR "); - if ((v & XDMA_STAT_H2C_W_SLAVE_ERR)) - len += sprintf(buf + len, "SLAVE_ERR "); - buf[len - 1] = ','; - } - - } else { - /* C2H only */ - if ((v & XDMA_STAT_C2H_R_ERR_MASK)) { - len += sprintf(buf + len, "R:"); - if ((v & XDMA_STAT_C2H_R_DECODE_ERR)) - len += sprintf(buf + len, "DECODE_ERR "); - if ((v & XDMA_STAT_C2H_R_SLAVE_ERR)) - len += sprintf(buf + len, "SLAVE_ERR "); - buf[len - 1] = ','; - } - } - - /* common H2C & C2H */ - if ((v & XDMA_STAT_DESC_ERR_MASK)) { - len += sprintf(buf + len, "DESC_ERR:"); - if ((v & XDMA_STAT_DESC_UNSUPP_REQ)) - len += sprintf(buf + len, "UNSUPP_REQ "); - if ((v & XDMA_STAT_DESC_COMPL_ABORT)) - len += sprintf(buf + len, "COMPL_ABORT "); - if ((v & XDMA_STAT_DESC_PARITY_ERR)) - len += sprintf(buf + len, "PARITY "); - if ((v & XDMA_STAT_DESC_HEADER_EP)) - len += sprintf(buf + len, "HEADER_EP "); - if ((v & XDMA_STAT_DESC_UNEXP_COMPL)) - len += sprintf(buf + len, "UNEXP_COMPL "); - buf[len - 1] = ','; - } - - buf[len - 1] = '\0'; - pr_info("%s\n", buffer); -} - -static u32 engine_status_read(struct xdma_engine *engine, bool clear, bool dump) -{ - u32 value; - - BUG_ON(!engine); - - if (dump) - engine_reg_dump(engine); - - /* read status register */ - if (clear) - value = engine->status = - read_register(&engine->regs->status_rc); - else - value = engine->status = read_register(&engine->regs->status); - - if (dump) - engine_status_dump(engine); - - return value; -} - -/** - * xdma_engine_stop() - stop an SG DMA engine - * - */ -static void xdma_engine_stop(struct xdma_engine *engine) -{ - u32 w; - - BUG_ON(!engine); - dbg_tfr("xdma_engine_stop(engine=%p)\n", engine); - - w = 0; - w |= (u32)XDMA_CTRL_IE_DESC_ALIGN_MISMATCH; - w |= (u32)XDMA_CTRL_IE_MAGIC_STOPPED; - w |= (u32)XDMA_CTRL_IE_READ_ERROR; - w |= (u32)XDMA_CTRL_IE_DESC_ERROR; - - if (poll_mode) { - w |= (u32) XDMA_CTRL_POLL_MODE_WB; - } else { - w |= (u32)XDMA_CTRL_IE_DESC_STOPPED; - w |= (u32)XDMA_CTRL_IE_DESC_COMPLETED; - - /* Disable IDLE STOPPED for MM */ - if ((engine->streaming && (engine->dir == DMA_FROM_DEVICE)) || - (engine->xdma_perf)) - w |= (u32)XDMA_CTRL_IE_IDLE_STOPPED; - } - - dbg_tfr("Stopping SG DMA %s engine; writing 0x%08x to 0x%p.\n", - engine->name, w, (u32 *)&engine->regs->control); - write_register(w, &engine->regs->control, - (unsigned long)(&engine->regs->control) - - (unsigned long)(&engine->regs)); - /* dummy read of status register to flush all previous writes */ - dbg_tfr("xdma_engine_stop(%s) done\n", engine->name); -} - -static void engine_start_mode_config(struct xdma_engine *engine) -{ - u32 w; - - BUG_ON(!engine); - - /* If a perf test is running, enable the engine interrupts */ - if (engine->xdma_perf) { - w = XDMA_CTRL_IE_DESC_STOPPED; - w |= XDMA_CTRL_IE_DESC_COMPLETED; - w |= XDMA_CTRL_IE_DESC_ALIGN_MISMATCH; - w |= XDMA_CTRL_IE_MAGIC_STOPPED; - w |= XDMA_CTRL_IE_IDLE_STOPPED; - w |= XDMA_CTRL_IE_READ_ERROR; - w |= XDMA_CTRL_IE_DESC_ERROR; - - write_register(w, &engine->regs->interrupt_enable_mask, - (unsigned long)(&engine->regs->interrupt_enable_mask) - - (unsigned long)(&engine->regs)); - } - - /* write control register of SG DMA engine */ - w = (u32)XDMA_CTRL_RUN_STOP; - w |= (u32)XDMA_CTRL_IE_READ_ERROR; - w |= (u32)XDMA_CTRL_IE_DESC_ERROR; - w |= (u32)XDMA_CTRL_IE_DESC_ALIGN_MISMATCH; - w |= (u32)XDMA_CTRL_IE_MAGIC_STOPPED; - - if (poll_mode) { - w |= (u32)XDMA_CTRL_POLL_MODE_WB; - } else { - w |= (u32)XDMA_CTRL_IE_DESC_STOPPED; - w |= (u32)XDMA_CTRL_IE_DESC_COMPLETED; - - if ((engine->streaming && (engine->dir == DMA_FROM_DEVICE)) || - (engine->xdma_perf)) - w |= (u32)XDMA_CTRL_IE_IDLE_STOPPED; - - /* set non-incremental addressing mode */ - if (engine->non_incr_addr) - w |= (u32)XDMA_CTRL_NON_INCR_ADDR; - } - - dbg_tfr("iowrite32(0x%08x to 0x%p) (control)\n", w, - (void *)&engine->regs->control); - /* start the engine */ - write_register(w, &engine->regs->control, - (unsigned long)(&engine->regs->control) - - (unsigned long)(&engine->regs)); - - /* dummy read of status register to flush all previous writes */ - w = read_register(&engine->regs->status); - dbg_tfr("ioread32(0x%p) = 0x%08x (dummy read flushes writes).\n", - &engine->regs->status, w); -} - -/** - * engine_start() - start an idle engine with its first transfer on queue - * - * The engine will run and process all transfers that are queued using - * transfer_queue() and thus have their descriptor lists chained. - * - * During the run, new transfers will be processed if transfer_queue() has - * chained the descriptors before the hardware fetches the last descriptor. - * A transfer that was chained too late will invoke a new run of the engine - * initiated from the engine_service() routine. - * - * The engine must be idle and at least one transfer must be queued. - * This function does not take locks; the engine spinlock must already be - * taken. - * - */ -static struct xdma_transfer *engine_start(struct xdma_engine *engine) -{ - struct xdma_transfer *transfer; - u32 w; - int extra_adj = 0; - - /* engine must be idle */ - BUG_ON(engine->running); - /* engine transfer queue must not be empty */ - BUG_ON(list_empty(&engine->transfer_list)); - /* inspect first transfer queued on the engine */ - transfer = list_entry(engine->transfer_list.next, struct xdma_transfer, - entry); - BUG_ON(!transfer); - - /* engine is no longer shutdown */ - engine->shutdown = ENGINE_SHUTDOWN_NONE; - - dbg_tfr("engine_start(%s): transfer=0x%p.\n", engine->name, transfer); - - /* initialize number of descriptors of dequeued transfers */ - engine->desc_dequeued = 0; - - /* write lower 32-bit of bus address of transfer first descriptor */ - w = cpu_to_le32(PCI_DMA_L(transfer->desc_bus)); - dbg_tfr("iowrite32(0x%08x to 0x%p) (first_desc_lo)\n", w, - (void *)&engine->sgdma_regs->first_desc_lo); - write_register(w, &engine->sgdma_regs->first_desc_lo, - (unsigned long)(&engine->sgdma_regs->first_desc_lo) - - (unsigned long)(&engine->sgdma_regs)); - /* write upper 32-bit of bus address of transfer first descriptor */ - w = cpu_to_le32(PCI_DMA_H(transfer->desc_bus)); - dbg_tfr("iowrite32(0x%08x to 0x%p) (first_desc_hi)\n", w, - (void *)&engine->sgdma_regs->first_desc_hi); - write_register(w, &engine->sgdma_regs->first_desc_hi, - (unsigned long)(&engine->sgdma_regs->first_desc_hi) - - (unsigned long)(&engine->sgdma_regs)); - - if (transfer->desc_adjacent > 0) { - extra_adj = transfer->desc_adjacent - 1; - if (extra_adj > MAX_EXTRA_ADJ) - extra_adj = MAX_EXTRA_ADJ; - } - dbg_tfr("iowrite32(0x%08x to 0x%p) (first_desc_adjacent)\n", - extra_adj, (void *)&engine->sgdma_regs->first_desc_adjacent); - write_register(extra_adj, &engine->sgdma_regs->first_desc_adjacent, - (unsigned long)(&engine->sgdma_regs->first_desc_adjacent) - - (unsigned long)(&engine->sgdma_regs)); - - dbg_tfr("ioread32(0x%p) (dummy read flushes writes).\n", - &engine->regs->status); - mmiowb(); - - engine_start_mode_config(engine); - - engine_status_read(engine, 0, 0); - - dbg_tfr("%s engine 0x%p now running\n", engine->name, engine); - /* remember the engine is running */ - engine->running = 1; - return transfer; -} - -/** - * engine_service() - service an SG DMA engine - * - * must be called with engine->lock already acquired - * - * @engine pointer to struct xdma_engine - * - */ -static void engine_service_shutdown(struct xdma_engine *engine) -{ - /* if the engine stopped with RUN still asserted, de-assert RUN now */ - dbg_tfr("engine just went idle, resetting RUN_STOP.\n"); - xdma_engine_stop(engine); - engine->running = 0; - - /* awake task on engine's shutdown wait queue */ - wake_up_interruptible(&engine->shutdown_wq); -} - -struct xdma_transfer *engine_transfer_completion(struct xdma_engine *engine, - struct xdma_transfer *transfer) -{ - BUG_ON(!engine); - BUG_ON(!transfer); - - /* synchronous I/O? */ - /* awake task on transfer's wait queue */ - wake_up_interruptible(&transfer->wq); - - return transfer; -} - -struct xdma_transfer *engine_service_transfer_list(struct xdma_engine *engine, - struct xdma_transfer *transfer, u32 *pdesc_completed) -{ - BUG_ON(!engine); - BUG_ON(!pdesc_completed); - - if (!transfer) { - pr_info("%s xfer empty, pdesc completed %u.\n", - engine->name, *pdesc_completed); - return NULL; - } - - /* - * iterate over all the transfers completed by the engine, - * except for the last (i.e. use > instead of >=). - */ - while (transfer && (!transfer->cyclic) && - (*pdesc_completed > transfer->desc_num)) { - /* remove this transfer from pdesc_completed */ - *pdesc_completed -= transfer->desc_num; - dbg_tfr("%s engine completed non-cyclic xfer 0x%p (%d desc)\n", - engine->name, transfer, transfer->desc_num); - /* remove completed transfer from list */ - list_del(engine->transfer_list.next); - /* add to dequeued number of descriptors during this run */ - engine->desc_dequeued += transfer->desc_num; - /* mark transfer as succesfully completed */ - transfer->state = TRANSFER_STATE_COMPLETED; - - /* Complete transfer - sets transfer to NULL if an async - * transfer has completed */ - transfer = engine_transfer_completion(engine, transfer); - - /* if exists, get the next transfer on the list */ - if (!list_empty(&engine->transfer_list)) { - transfer = list_entry(engine->transfer_list.next, - struct xdma_transfer, entry); - dbg_tfr("Non-completed transfer %p\n", transfer); - } else { - /* no further transfers? */ - transfer = NULL; - } - } - - return transfer; -} - -static void engine_err_handle(struct xdma_engine *engine, - struct xdma_transfer *transfer, u32 desc_completed) -{ - u32 value; - - /* - * The BUSY bit is expected to be clear now but older HW has a race - * condition which could cause it to be still set. If it's set, re-read - * and check again. If it's still set, log the issue. - */ - if (engine->status & XDMA_STAT_BUSY) { - value = read_register(&engine->regs->status); - if ((value & XDMA_STAT_BUSY) && printk_ratelimit()) - pr_info("%s has errors but is still BUSY\n", - engine->name); - } - - if (printk_ratelimit()) { - pr_info("%s, s 0x%x, aborted xfer 0x%p, cmpl %d/%d\n", - engine->name, engine->status, transfer, desc_completed, - transfer->desc_num); - } - - /* mark transfer as failed */ - transfer->state = TRANSFER_STATE_FAILED; - xdma_engine_stop(engine); -} - -struct xdma_transfer *engine_service_final_transfer(struct xdma_engine *engine, - struct xdma_transfer *transfer, u32 *pdesc_completed) -{ - BUG_ON(!engine); - BUG_ON(!transfer); - BUG_ON(!pdesc_completed); - - /* inspect the current transfer */ - if (transfer) { - if (((engine->dir == DMA_FROM_DEVICE) && - (engine->status & XDMA_STAT_C2H_ERR_MASK)) || - ((engine->dir == DMA_TO_DEVICE) && - (engine->status & XDMA_STAT_H2C_ERR_MASK))) { - pr_info("engine %s, status error 0x%x.\n", - engine->name, engine->status); - engine_status_dump(engine); - engine_err_handle(engine, transfer, *pdesc_completed); - goto transfer_del; - } - - if (engine->status & XDMA_STAT_BUSY) - dbg_tfr("Engine %s is unexpectedly busy - ignoring\n", - engine->name); - - /* the engine stopped on current transfer? */ - if (*pdesc_completed < transfer->desc_num) { - transfer->state = TRANSFER_STATE_FAILED; - pr_info("%s, xfer 0x%p, stopped half-way, %d/%d.\n", - engine->name, transfer, *pdesc_completed, - transfer->desc_num); - } else { - dbg_tfr("engine %s completed transfer\n", engine->name); - dbg_tfr("Completed transfer ID = 0x%p\n", transfer); - dbg_tfr("*pdesc_completed=%d, transfer->desc_num=%d", - *pdesc_completed, transfer->desc_num); - - if (!transfer->cyclic) { - /* - * if the engine stopped on this transfer, - * it should be the last - */ - WARN_ON(*pdesc_completed > transfer->desc_num); - } - /* mark transfer as succesfully completed */ - transfer->state = TRANSFER_STATE_COMPLETED; - } - -transfer_del: - /* remove completed transfer from list */ - list_del(engine->transfer_list.next); - /* add to dequeued number of descriptors during this run */ - engine->desc_dequeued += transfer->desc_num; - - /* - * Complete transfer - sets transfer to NULL if an asynchronous - * transfer has completed - */ - transfer = engine_transfer_completion(engine, transfer); - } - - return transfer; -} - -static void engine_service_perf(struct xdma_engine *engine, u32 desc_completed) -{ - BUG_ON(!engine); - - /* performance measurement is running? */ - if (engine->xdma_perf) { - /* a descriptor was completed? */ - if (engine->status & XDMA_STAT_DESC_COMPLETED) { - engine->xdma_perf->iterations = desc_completed; - dbg_perf("transfer->xdma_perf->iterations=%d\n", - engine->xdma_perf->iterations); - } - - /* a descriptor stopped the engine? */ - if (engine->status & XDMA_STAT_DESC_STOPPED) { - engine->xdma_perf->stopped = 1; - /* - * wake any XDMA_PERF_IOCTL_STOP waiting for - * the performance run to finish - */ - wake_up_interruptible(&engine->xdma_perf_wq); - dbg_perf("transfer->xdma_perf stopped\n"); - } - } -} - -static void engine_transfer_dequeue(struct xdma_engine *engine) -{ - struct xdma_transfer *transfer; - - BUG_ON(!engine); - - /* pick first transfer on the queue (was submitted to the engine) */ - transfer = list_entry(engine->transfer_list.next, struct xdma_transfer, - entry); - BUG_ON(!transfer); - BUG_ON(transfer != &engine->cyclic_req->xfer); - dbg_tfr("%s engine completed cyclic transfer 0x%p (%d desc).\n", - engine->name, transfer, transfer->desc_num); - /* remove completed transfer from list */ - list_del(engine->transfer_list.next); -} - -static int engine_ring_process(struct xdma_engine *engine) -{ - struct xdma_result *result; - int start; - int eop_count = 0; - - BUG_ON(!engine); - result = engine->cyclic_result; - BUG_ON(!result); - - /* where we start receiving in the ring buffer */ - start = engine->rx_tail; - - /* iterate through all newly received RX result descriptors */ - dbg_tfr("%s, result %d, 0x%x, len 0x%x.\n", - engine->name, engine->rx_tail, result[engine->rx_tail].status, - result[engine->rx_tail].length); - while (result[engine->rx_tail].status && !engine->rx_overrun) { - /* EOP bit set in result? */ - if (result[engine->rx_tail].status & RX_STATUS_EOP){ - eop_count++; - } - - /* increment tail pointer */ - engine->rx_tail = (engine->rx_tail + 1) % CYCLIC_RX_PAGES_MAX; - - dbg_tfr("%s, head %d, tail %d, 0x%x, len 0x%x.\n", - engine->name, engine->rx_head, engine->rx_tail, - result[engine->rx_tail].status, - result[engine->rx_tail].length); - - /* overrun? */ - if (engine->rx_tail == engine->rx_head) { - dbg_tfr("%s: overrun\n", engine->name); - /* flag to user space that overrun has occurred */ - engine->rx_overrun = 1; - } - } - - return eop_count; -} - -static int engine_service_cyclic_polled(struct xdma_engine *engine) -{ - int eop_count = 0; - int rc = 0; - struct xdma_poll_wb *writeback_data; - u32 sched_limit = 0; - - BUG_ON(!engine); - BUG_ON(engine->magic != MAGIC_ENGINE); - - writeback_data = (struct xdma_poll_wb *)engine->poll_mode_addr_virt; - - while (eop_count == 0) { - if (sched_limit != 0) { - if ((sched_limit % NUM_POLLS_PER_SCHED) == 0) - schedule(); - } - sched_limit++; - - /* Monitor descriptor writeback address for errors */ - if ((writeback_data->completed_desc_count) & WB_ERR_MASK) { - rc = -1; - break; - } - - eop_count = engine_ring_process(engine); - } - - if (eop_count == 0) { - engine_status_read(engine, 1, 0); - if ((engine->running) && !(engine->status & XDMA_STAT_BUSY)) { - /* transfers on queue? */ - if (!list_empty(&engine->transfer_list)) - engine_transfer_dequeue(engine); - - engine_service_shutdown(engine); - } - } - - return rc; -} - -static int engine_service_cyclic_interrupt(struct xdma_engine *engine) -{ - int eop_count = 0; - struct xdma_transfer *xfer; - - BUG_ON(!engine); - BUG_ON(engine->magic != MAGIC_ENGINE); - - engine_status_read(engine, 1, 0); - - eop_count = engine_ring_process(engine); - /* - * wake any reader on EOP, as one or more packets are now in - * the RX buffer - */ - xfer = &engine->cyclic_req->xfer; - if(enable_credit_mp){ - if (eop_count > 0) { - //engine->eop_found = 1; - } - wake_up_interruptible(&xfer->wq); - }else{ - if (eop_count > 0) { - /* awake task on transfer's wait queue */ - dbg_tfr("wake_up_interruptible() due to %d EOP's\n", eop_count); - engine->eop_found = 1; - wake_up_interruptible(&xfer->wq); - } - } - - /* engine was running but is no longer busy? */ - if ((engine->running) && !(engine->status & XDMA_STAT_BUSY)) { - /* transfers on queue? */ - if (!list_empty(&engine->transfer_list)) - engine_transfer_dequeue(engine); - - engine_service_shutdown(engine); - } - - return 0; -} - -/* must be called with engine->lock already acquired */ -static int engine_service_cyclic(struct xdma_engine *engine) -{ - int rc = 0; - - dbg_tfr("engine_service_cyclic()"); - - BUG_ON(!engine); - BUG_ON(engine->magic != MAGIC_ENGINE); - - if (poll_mode) - rc = engine_service_cyclic_polled(engine); - else - rc = engine_service_cyclic_interrupt(engine); - - return rc; -} - - -static void engine_service_resume(struct xdma_engine *engine) -{ - struct xdma_transfer *transfer_started; - - BUG_ON(!engine); - - /* engine stopped? */ - if (!engine->running) { - /* in the case of shutdown, let it finish what's in the Q */ - if (!list_empty(&engine->transfer_list)) { - /* (re)start engine */ - transfer_started = engine_start(engine); - dbg_tfr("re-started %s engine with pending xfer 0x%p\n", - engine->name, transfer_started); - /* engine was requested to be shutdown? */ - } else if (engine->shutdown & ENGINE_SHUTDOWN_REQUEST) { - engine->shutdown |= ENGINE_SHUTDOWN_IDLE; - /* awake task on engine's shutdown wait queue */ - wake_up_interruptible(&engine->shutdown_wq); - } else { - dbg_tfr("no pending transfers, %s engine stays idle.\n", - engine->name); - } - } else { - /* engine is still running? */ - if (list_empty(&engine->transfer_list)) { - pr_warn("no queued transfers but %s engine running!\n", - engine->name); - WARN_ON(1); - } - } -} - -/** - * engine_service() - service an SG DMA engine - * - * must be called with engine->lock already acquired - * - * @engine pointer to struct xdma_engine - * - */ -static int engine_service(struct xdma_engine *engine, int desc_writeback) -{ - struct xdma_transfer *transfer = NULL; - u32 desc_count = desc_writeback & WB_COUNT_MASK; - u32 err_flag = desc_writeback & WB_ERR_MASK; - int rv = 0; - struct xdma_poll_wb *wb_data; - - BUG_ON(!engine); - - /* If polling detected an error, signal to the caller */ - if (err_flag) - rv = -1; - - /* Service the engine */ - if (!engine->running) { - dbg_tfr("Engine was not running!!! Clearing status\n"); - engine_status_read(engine, 1, 0); - return 0; - } - - /* - * If called by the ISR or polling detected an error, read and clear - * engine status. For polled mode descriptor completion, this read is - * unnecessary and is skipped to reduce latency - */ - if ((desc_count == 0) || (err_flag != 0)) - engine_status_read(engine, 1, 0); - - /* - * engine was running but is no longer busy, or writeback occurred, - * shut down - */ - if ((engine->running && !(engine->status & XDMA_STAT_BUSY)) || - (desc_count != 0)) - engine_service_shutdown(engine); - - /* - * If called from the ISR, or if an error occurred, the descriptor - * count will be zero. In this scenario, read the descriptor count - * from HW. In polled mode descriptor completion, this read is - * unnecessary and is skipped to reduce latency - */ - if (!desc_count) - desc_count = read_register(&engine->regs->completed_desc_count); - dbg_tfr("desc_count = %d\n", desc_count); - - /* transfers on queue? */ - if (!list_empty(&engine->transfer_list)) { - /* pick first transfer on queue (was submitted to the engine) */ - transfer = list_entry(engine->transfer_list.next, - struct xdma_transfer, entry); - - dbg_tfr("head of queue transfer 0x%p has %d descriptors\n", - transfer, (int)transfer->desc_num); - - dbg_tfr("Engine completed %d desc, %d not yet dequeued\n", - (int)desc_count, - (int)desc_count - engine->desc_dequeued); - - engine_service_perf(engine, desc_count); - } - - /* account for already dequeued transfers during this engine run */ - desc_count -= engine->desc_dequeued; - - /* Process all but the last transfer */ - transfer = engine_service_transfer_list(engine, transfer, &desc_count); - - /* - * Process final transfer - includes checks of number of descriptors to - * detect faulty completion - */ - transfer = engine_service_final_transfer(engine, transfer, &desc_count); - - /* Before starting engine again, clear the writeback data */ - if (poll_mode) { - wb_data = (struct xdma_poll_wb *)engine->poll_mode_addr_virt; - wb_data->completed_desc_count = 0; - } - - /* Restart the engine following the servicing */ - engine_service_resume(engine); - - return 0; -} - -/* engine_service_work */ -static void engine_service_work(struct work_struct *work) -{ - struct xdma_engine *engine; - unsigned long flags; - - engine = container_of(work, struct xdma_engine, work); - BUG_ON(engine->magic != MAGIC_ENGINE); - - /* lock the engine */ - spin_lock_irqsave(&engine->lock, flags); - - dbg_tfr("engine_service() for %s engine %p\n", - engine->name, engine); - if (engine->cyclic_req) - engine_service_cyclic(engine); - else - engine_service(engine, 0); - - /* re-enable interrupts for this engine */ - if (engine->xdev->msix_enabled){ - write_register(engine->interrupt_enable_mask_value, - &engine->regs->interrupt_enable_mask_w1s, - (unsigned long)(&engine->regs->interrupt_enable_mask_w1s) - - (unsigned long)(&engine->regs)); - } else - channel_interrupts_enable(engine->xdev, engine->irq_bitmask); - - /* unlock the engine */ - spin_unlock_irqrestore(&engine->lock, flags); -} - -static u32 engine_service_wb_monitor(struct xdma_engine *engine, - u32 expected_wb) -{ - struct xdma_poll_wb *wb_data; - u32 desc_wb = 0; - u32 sched_limit = 0; - unsigned long timeout; - - BUG_ON(!engine); - wb_data = (struct xdma_poll_wb *)engine->poll_mode_addr_virt; - - /* - * Poll the writeback location for the expected number of - * descriptors / error events This loop is skipped for cyclic mode, - * where the expected_desc_count passed in is zero, since it cannot be - * determined before the function is called - */ - - timeout = jiffies + (POLL_TIMEOUT_SECONDS * HZ); - while (expected_wb != 0) { - desc_wb = wb_data->completed_desc_count; - - if (desc_wb & WB_ERR_MASK) - break; - else if (desc_wb == expected_wb) - break; - - /* RTO - prevent system from hanging in polled mode */ - if (time_after(jiffies, timeout)) { - dbg_tfr("Polling timeout occurred"); - dbg_tfr("desc_wb = 0x%08x, expected 0x%08x\n", desc_wb, - expected_wb); - if ((desc_wb & WB_COUNT_MASK) > expected_wb) - desc_wb = expected_wb | WB_ERR_MASK; - - break; - } - - /* - * Define NUM_POLLS_PER_SCHED to limit how much time is spent - * in the scheduler - */ - - if (sched_limit != 0) { - if ((sched_limit % NUM_POLLS_PER_SCHED) == 0) - schedule(); - } - sched_limit++; - } - - return desc_wb; -} - -static int engine_service_poll(struct xdma_engine *engine, - u32 expected_desc_count) -{ - struct xdma_poll_wb *writeback_data; - u32 desc_wb = 0; - unsigned long flags; - int rv = 0; - - BUG_ON(!engine); - BUG_ON(engine->magic != MAGIC_ENGINE); - - writeback_data = (struct xdma_poll_wb *)engine->poll_mode_addr_virt; - - if ((expected_desc_count & WB_COUNT_MASK) != expected_desc_count) { - dbg_tfr("Queued descriptor count is larger than supported\n"); - return -1; - } - - /* - * Poll the writeback location for the expected number of - * descriptors / error events This loop is skipped for cyclic mode, - * where the expected_desc_count passed in is zero, since it cannot be - * determined before the function is called - */ - - desc_wb = engine_service_wb_monitor(engine, expected_desc_count); - - spin_lock_irqsave(&engine->lock, flags); - dbg_tfr("%s service.\n", engine->name); - if (engine->cyclic_req) { - rv = engine_service_cyclic(engine); - } else { - rv = engine_service(engine, desc_wb); - } - spin_unlock_irqrestore(&engine->lock, flags); - - return rv; -} - -static irqreturn_t user_irq_service(int irq, struct xdma_user_irq *user_irq) -{ - unsigned long flags; - - BUG_ON(!user_irq); - - if (user_irq->handler) - return user_irq->handler(user_irq->user_idx, user_irq->dev); - - spin_lock_irqsave(&(user_irq->events_lock), flags); - if (!user_irq->events_irq) { - user_irq->events_irq = 1; - wake_up_interruptible(&(user_irq->events_wq)); - } - spin_unlock_irqrestore(&(user_irq->events_lock), flags); - - return IRQ_HANDLED; -} - -/* - * xdma_isr() - Interrupt handler - * - * @dev_id pointer to xdma_dev - */ -static irqreturn_t xdma_isr(int irq, void *dev_id) -{ - u32 ch_irq; - u32 user_irq; - u32 mask; - struct xdma_dev *xdev; - struct interrupt_regs *irq_regs; - - dbg_irq("(irq=%d, dev 0x%p) <<<< ISR.\n", irq, dev_id); - BUG_ON(!dev_id); - xdev = (struct xdma_dev *)dev_id; - - if (!xdev) { - WARN_ON(!xdev); - dbg_irq("xdma_isr(irq=%d) xdev=%p ??\n", irq, xdev); - return IRQ_NONE; - } - - irq_regs = (struct interrupt_regs *)(xdev->bar[xdev->config_bar_idx] + - XDMA_OFS_INT_CTRL); - - /* read channel interrupt requests */ - ch_irq = read_register(&irq_regs->channel_int_request); - dbg_irq("ch_irq = 0x%08x\n", ch_irq); - - /* - * disable all interrupts that fired; these are re-enabled individually - * after the causing module has been fully serviced. - */ - if (ch_irq) - channel_interrupts_disable(xdev, ch_irq); - - /* read user interrupts - this read also flushes the above write */ - user_irq = read_register(&irq_regs->user_int_request); - dbg_irq("user_irq = 0x%08x\n", user_irq); - - if (user_irq) { - int user = 0; - u32 mask = 1; - int max = xdev->h2c_channel_max; - - for (; user < max && user_irq; user++, mask <<= 1) { - if (user_irq & mask) { - user_irq &= ~mask; - user_irq_service(irq, &xdev->user_irq[user]); - } - } - } - - mask = ch_irq & xdev->mask_irq_h2c; - if (mask) { - int channel = 0; - int max = xdev->h2c_channel_max; - - /* iterate over H2C (PCIe read) */ - for (channel = 0; channel < max && mask; channel++) { - struct xdma_engine *engine = &xdev->engine_h2c[channel]; - - /* engine present and its interrupt fired? */ - if((engine->irq_bitmask & mask) && - (engine->magic == MAGIC_ENGINE)) { - mask &= ~engine->irq_bitmask; - dbg_tfr("schedule_work, %s.\n", engine->name); - schedule_work(&engine->work); - } - } - } - - mask = ch_irq & xdev->mask_irq_c2h; - if (mask) { - int channel = 0; - int max = xdev->c2h_channel_max; - - /* iterate over C2H (PCIe write) */ - for (channel = 0; channel < max && mask; channel++) { - struct xdma_engine *engine = &xdev->engine_c2h[channel]; - - /* engine present and its interrupt fired? */ - if((engine->irq_bitmask & mask) && - (engine->magic == MAGIC_ENGINE)) { - mask &= ~engine->irq_bitmask; - dbg_tfr("schedule_work, %s.\n", engine->name); - schedule_work(&engine->work); - } - } - } - - xdev->irq_count++; - return IRQ_HANDLED; -} - -/* - * xdma_user_irq() - Interrupt handler for user interrupts in MSI-X mode - * - * @dev_id pointer to xdma_dev - */ -static irqreturn_t xdma_user_irq(int irq, void *dev_id) -{ - struct xdma_user_irq *user_irq; - - dbg_irq("(irq=%d) <<<< INTERRUPT SERVICE ROUTINE\n", irq); - - BUG_ON(!dev_id); - user_irq = (struct xdma_user_irq *)dev_id; - - return user_irq_service(irq, user_irq); -} - -/* - * xdma_channel_irq() - Interrupt handler for channel interrupts in MSI-X mode - * - * @dev_id pointer to xdma_dev - */ -static irqreturn_t xdma_channel_irq(int irq, void *dev_id) -{ - struct xdma_dev *xdev; - struct xdma_engine *engine; - struct interrupt_regs *irq_regs; - - dbg_irq("(irq=%d) <<<< INTERRUPT service ROUTINE\n", irq); - BUG_ON(!dev_id); - - engine = (struct xdma_engine *)dev_id; - xdev = engine->xdev; - - if (!xdev) { - WARN_ON(!xdev); - dbg_irq("xdma_channel_irq(irq=%d) xdev=%p ??\n", irq, xdev); - return IRQ_NONE; - } - - irq_regs = (struct interrupt_regs *)(xdev->bar[xdev->config_bar_idx] + - XDMA_OFS_INT_CTRL); - - /* Disable the interrupt for this engine */ - write_register(engine->interrupt_enable_mask_value, - &engine->regs->interrupt_enable_mask_w1c, - (unsigned long) - (&engine->regs->interrupt_enable_mask_w1c) - - (unsigned long)(&engine->regs)); - /* Dummy read to flush the above write */ - read_register(&irq_regs->channel_int_pending); - /* Schedule the bottom half */ - schedule_work(&engine->work); - - /* - * RTO - need to protect access here if multiple MSI-X are used for - * user interrupts - */ - xdev->irq_count++; - return IRQ_HANDLED; -} - -/* - * Unmap the BAR regions that had been mapped earlier using map_bars() - */ -static void unmap_bars(struct xdma_dev *xdev, struct pci_dev *dev) -{ - int i; - - for (i = 0; i < XDMA_BAR_NUM; i++) { - /* is this BAR mapped? */ - if (xdev->bar[i]) { - /* unmap BAR */ - pci_iounmap(dev, xdev->bar[i]); - /* mark as unmapped */ - xdev->bar[i] = NULL; - } - } -} - -static int map_single_bar(struct xdma_dev *xdev, struct pci_dev *dev, int idx) -{ - resource_size_t bar_start; - resource_size_t bar_len; - resource_size_t map_len; - - bar_start = pci_resource_start(dev, idx); - bar_len = pci_resource_len(dev, idx); - map_len = bar_len; - - xdev->bar[idx] = NULL; - - /* do not map BARs with length 0. Note that start MAY be 0! */ - if (!bar_len) { - //pr_info("BAR #%d is not present - skipping\n", idx); - return 0; - } - - /* BAR size exceeds maximum desired mapping? */ - if (bar_len > INT_MAX) { - pr_info("Limit BAR %d mapping from %llu to %d bytes\n", idx, - (u64)bar_len, INT_MAX); - map_len = (resource_size_t)INT_MAX; - } - /* - * map the full device memory or IO region into kernel virtual - * address space - */ - dbg_init("BAR%d: %llu bytes to be mapped.\n", idx, (u64)map_len); - xdev->bar[idx] = pci_iomap(dev, idx, map_len); - - if (!xdev->bar[idx]) { - pr_info("Could not map BAR %d.\n", idx); - return -1; - } - - pr_info("BAR%d at 0x%llx mapped at 0x%p, length=%llu(/%llu)\n", idx, - (u64)bar_start, xdev->bar[idx], (u64)map_len, (u64)bar_len); - - return (int)map_len; -} - -static int is_config_bar(struct xdma_dev *xdev, int idx) -{ - u32 irq_id = 0; - u32 cfg_id = 0; - int flag = 0; - u32 mask = 0xffff0000; /* Compare only XDMA ID's not Version number */ - struct interrupt_regs *irq_regs = - (struct interrupt_regs *) (xdev->bar[idx] + XDMA_OFS_INT_CTRL); - struct config_regs *cfg_regs = - (struct config_regs *)(xdev->bar[idx] + XDMA_OFS_CONFIG); - - irq_id = read_register(&irq_regs->identifier); - cfg_id = read_register(&cfg_regs->identifier); - - if (((irq_id & mask)== IRQ_BLOCK_ID) && - ((cfg_id & mask)== CONFIG_BLOCK_ID)) { - dbg_init("BAR %d is the XDMA config BAR\n", idx); - flag = 1; - } else { - dbg_init("BAR %d is NOT the XDMA config BAR: 0x%x, 0x%x.\n", - idx, irq_id, cfg_id); - flag = 0; - } - - return flag; -} - -static void identify_bars(struct xdma_dev *xdev, int *bar_id_list, int num_bars, - int config_bar_pos) -{ - /* - * The following logic identifies which BARs contain what functionality - * based on the position of the XDMA config BAR and the number of BARs - * detected. The rules are that the user logic and bypass logic BARs - * are optional. When both are present, the XDMA config BAR will be the - * 2nd BAR detected (config_bar_pos = 1), with the user logic being - * detected first and the bypass being detected last. When one is - * omitted, the type of BAR present can be identified by whether the - * XDMA config BAR is detected first or last. When both are omitted, - * only the XDMA config BAR is present. This somewhat convoluted - * approach is used instead of relying on BAR numbers in order to work - * correctly with both 32-bit and 64-bit BARs. - */ - - BUG_ON(!xdev); - BUG_ON(!bar_id_list); - - dbg_init("xdev 0x%p, bars %d, config at %d.\n", - xdev, num_bars, config_bar_pos); - - switch (num_bars) { - case 1: - /* Only one BAR present - no extra work necessary */ - break; - - case 2: - if (config_bar_pos == 0) { - xdev->bypass_bar_idx = bar_id_list[1]; - } else if (config_bar_pos == 1) { - xdev->user_bar_idx = bar_id_list[0]; - } else { - pr_info("2, XDMA config BAR unexpected %d.\n", - config_bar_pos); - } - break; - - case 3: - case 4: - if ((config_bar_pos == 1) || (config_bar_pos == 2)) { - /* user bar at bar #0 */ - xdev->user_bar_idx = bar_id_list[0]; - /* bypass bar at the last bar */ - xdev->bypass_bar_idx = bar_id_list[num_bars - 1]; - } else { - pr_info("3/4, XDMA config BAR unexpected %d.\n", - config_bar_pos); - } - break; - - default: - /* Should not occur - warn user but safe to continue */ - pr_info("Unexpected # BARs (%d), XDMA config BAR only.\n", - num_bars); - break; - - } - pr_info("%d BARs: config %d, user %d, bypass %d.\n", - num_bars, config_bar_pos, xdev->user_bar_idx, - xdev->bypass_bar_idx); -} - -/* map_bars() -- map device regions into kernel virtual address space - * - * Map the device memory regions into kernel virtual address space after - * verifying their sizes respect the minimum sizes needed - */ -static int map_bars(struct xdma_dev *xdev, struct pci_dev *dev) -{ - int rv; - int i; - int bar_id_list[XDMA_BAR_NUM]; - int bar_id_idx = 0; - int config_bar_pos = 0; - - /* iterate through all the BARs */ - for (i = 0; i < XDMA_BAR_NUM; i++) { - int bar_len; - - bar_len = map_single_bar(xdev, dev, i); - if (bar_len == 0) { - continue; - } else if (bar_len < 0) { - rv = -EINVAL; - goto fail; - } - - /* Try to identify BAR as XDMA control BAR */ - if ((bar_len >= XDMA_BAR_SIZE) && (xdev->config_bar_idx < 0)) { - - if (is_config_bar(xdev, i)) { - xdev->config_bar_idx = i; - config_bar_pos = bar_id_idx; - pr_info("config bar %d, pos %d.\n", - xdev->config_bar_idx, config_bar_pos); - } - } - - bar_id_list[bar_id_idx] = i; - bar_id_idx++; - } - - /* The XDMA config BAR must always be present */ - if (xdev->config_bar_idx < 0) { - pr_info("Failed to detect XDMA config BAR\n"); - rv = -EINVAL; - goto fail; - } - - identify_bars(xdev, bar_id_list, bar_id_idx, config_bar_pos); - - /* successfully mapped all required BAR regions */ - return 0; - -fail: - /* unwind; unmap any BARs that we did map */ - unmap_bars(xdev, dev); - return rv; -} - -/* - * MSI-X interrupt: - * vectors, followed by vectors - */ - -/* - * RTO - code to detect if MSI/MSI-X capability exists is derived - * from linux/pci/msi.c - pci_msi_check_device - */ - -#ifndef arch_msi_check_device -int arch_msi_check_device(struct pci_dev *dev, int nvec, int type) -{ - return 0; -} -#endif - -/* type = PCI_CAP_ID_MSI or PCI_CAP_ID_MSIX */ -static int msi_msix_capable(struct pci_dev *dev, int type) -{ - struct pci_bus *bus; - int ret; - - if (!dev || dev->no_msi) - return 0; - - for (bus = dev->bus; bus; bus = bus->parent) - if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) - return 0; - - ret = arch_msi_check_device(dev, 1, type); - if (ret) - return 0; - - if (!pci_find_capability(dev, type)) - return 0; - - return 1; -} - -static void disable_msi_msix(struct xdma_dev *xdev, struct pci_dev *pdev) -{ - if (xdev->msix_enabled) { - pci_disable_msix(pdev); - xdev->msix_enabled = 0; - } else if (xdev->msi_enabled) { - pci_disable_msi(pdev); - xdev->msi_enabled = 0; - } -} - -static int enable_msi_msix(struct xdma_dev *xdev, struct pci_dev *pdev) -{ - int rv = 0; - - BUG_ON(!xdev); - BUG_ON(!pdev); - - if (!interrupt_mode && msi_msix_capable(pdev, PCI_CAP_ID_MSIX)) { - int req_nvec = xdev->c2h_channel_max + xdev->h2c_channel_max + - xdev->user_max; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) - dbg_init("Enabling MSI-X\n"); - rv = pci_alloc_irq_vectors(pdev, req_nvec, req_nvec, - PCI_IRQ_MSIX); -#else - int i; - - dbg_init("Enabling MSI-X\n"); - for (i = 0; i < req_nvec; i++) - xdev->entry[i].entry = i; - - rv = pci_enable_msix(pdev, xdev->entry, req_nvec); -#endif - if (rv < 0) - dbg_init("Couldn't enable MSI-X mode: %d\n", rv); - - xdev->msix_enabled = 1; - - } else if (interrupt_mode == 1 && - msi_msix_capable(pdev, PCI_CAP_ID_MSI)) { - /* enable message signalled interrupts */ - dbg_init("pci_enable_msi()\n"); - rv = pci_enable_msi(pdev); - if (rv < 0) - dbg_init("Couldn't enable MSI mode: %d\n", rv); - xdev->msi_enabled = 1; - - } else { - dbg_init("MSI/MSI-X not detected - using legacy interrupts\n"); - } - - return rv; -} - -static void pci_check_intr_pend(struct pci_dev *pdev) -{ - u16 v; - - pci_read_config_word(pdev, PCI_STATUS, &v); - if (v & PCI_STATUS_INTERRUPT) { - pr_info("%s PCI STATUS Interrupt pending 0x%x.\n", - dev_name(&pdev->dev), v); - pci_write_config_word(pdev, PCI_STATUS, PCI_STATUS_INTERRUPT); - } -} - -static void pci_keep_intx_enabled(struct pci_dev *pdev) -{ - /* workaround to a h/w bug: - * when msix/msi become unavaile, default to legacy. - * However the legacy enable was not checked. - * If the legacy was disabled, no ack then everything stuck - */ - u16 pcmd, pcmd_new; - - pci_read_config_word(pdev, PCI_COMMAND, &pcmd); - pcmd_new = pcmd & ~PCI_COMMAND_INTX_DISABLE; - if (pcmd_new != pcmd) { - pr_info("%s: clear INTX_DISABLE, 0x%x -> 0x%x.\n", - dev_name(&pdev->dev), pcmd, pcmd_new); - pci_write_config_word(pdev, PCI_COMMAND, pcmd_new); - } -} - -static void prog_irq_msix_user(struct xdma_dev *xdev, bool clear) -{ - /* user */ - struct interrupt_regs *int_regs = (struct interrupt_regs *) - (xdev->bar[xdev->config_bar_idx] + - XDMA_OFS_INT_CTRL); - u32 i = xdev->c2h_channel_max + xdev->h2c_channel_max; - u32 max = i + xdev->user_max; - int j; - - for (j = 0; i < max; j++) { - u32 val = 0; - int k; - int shift = 0; - - if (clear) - i += 4; - else - for (k = 0; k < 4 && i < max; i++, k++, shift += 8) - val |= (i & 0x1f) << shift; - - write_register(val, &int_regs->user_msi_vector[j], - XDMA_OFS_INT_CTRL + - ((unsigned long)&int_regs->user_msi_vector[j] - - (unsigned long)int_regs)); - - dbg_init("vector %d, 0x%x.\n", j, val); - } -} - -static void prog_irq_msix_channel(struct xdma_dev *xdev, bool clear) -{ - struct interrupt_regs *int_regs = (struct interrupt_regs *) - (xdev->bar[xdev->config_bar_idx] + - XDMA_OFS_INT_CTRL); - u32 max = xdev->c2h_channel_max + xdev->h2c_channel_max; - u32 i; - int j; - - /* engine */ - for (i = 0, j = 0; i < max; j++) { - u32 val = 0; - int k; - int shift = 0; - - if (clear) - i += 4; - else - for (k = 0; k < 4 && i < max; i++, k++, shift += 8) - val |= (i & 0x1f) << shift; - - write_register(val, &int_regs->channel_msi_vector[j], - XDMA_OFS_INT_CTRL + - ((unsigned long)&int_regs->channel_msi_vector[j] - - (unsigned long)int_regs)); - dbg_init("vector %d, 0x%x.\n", j, val); - } -} - -static void irq_msix_channel_teardown(struct xdma_dev *xdev) -{ - struct xdma_engine *engine; - int j = 0; - int i = 0; - - if (!xdev->msix_enabled) - return; - - prog_irq_msix_channel(xdev, 1); - - engine = xdev->engine_h2c; - for (i = 0; i < xdev->h2c_channel_max; i++, j++, engine++) { - if (!engine->msix_irq_line) - break; - dbg_sg("Release IRQ#%d for engine %p\n", engine->msix_irq_line, - engine); - free_irq(engine->msix_irq_line, engine); - } - - engine = xdev->engine_c2h; - for (i = 0; i < xdev->c2h_channel_max; i++, j++, engine++) { - if (!engine->msix_irq_line) - break; - dbg_sg("Release IRQ#%d for engine %p\n", engine->msix_irq_line, - engine); - free_irq(engine->msix_irq_line, engine); - } -} - -static int irq_msix_channel_setup(struct xdma_dev *xdev) -{ - int i; - int j = xdev->h2c_channel_max; - int rv = 0; - u32 vector; - struct xdma_engine *engine; - - BUG_ON(!xdev); - if (!xdev->msix_enabled) - return 0; - - engine = xdev->engine_h2c; - for (i = 0; i < xdev->h2c_channel_max; i++, engine++) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) - vector = pci_irq_vector(xdev->pdev, i); -#else - vector = xdev->entry[i].vector; -#endif - rv = request_irq(vector, xdma_channel_irq, 0, xdev->mod_name, - engine); - if (rv) { - pr_info("requesti irq#%d failed %d, engine %s.\n", - vector, rv, engine->name); - return rv; - } - pr_info("engine %s, irq#%d.\n", engine->name, vector); - engine->msix_irq_line = vector; - } - - engine = xdev->engine_c2h; - for (i = 0; i < xdev->c2h_channel_max; i++, j++, engine++) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) - vector = pci_irq_vector(xdev->pdev, j); -#else - vector = xdev->entry[j].vector; -#endif - rv = request_irq(vector, xdma_channel_irq, 0, xdev->mod_name, - engine); - if (rv) { - pr_info("requesti irq#%d failed %d, engine %s.\n", - vector, rv, engine->name); - return rv; - } - pr_info("engine %s, irq#%d.\n", engine->name, vector); - engine->msix_irq_line = vector; - } - - return 0; -} - -static void irq_msix_user_teardown(struct xdma_dev *xdev) -{ - int i; - int j = xdev->h2c_channel_max + xdev->c2h_channel_max; - - BUG_ON(!xdev); - - if (!xdev->msix_enabled) - return; - - prog_irq_msix_user(xdev, 1); - - for (i = 0; i < xdev->user_max; i++, j++) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) - u32 vector = pci_irq_vector(xdev->pdev, j); -#else - u32 vector = xdev->entry[j].vector; -#endif - dbg_init("user %d, releasing IRQ#%d\n", i, vector); - free_irq(vector, &xdev->user_irq[i]); - } -} - -static int irq_msix_user_setup(struct xdma_dev *xdev) -{ - int i; - int j = xdev->h2c_channel_max + xdev->c2h_channel_max; - int rv = 0; - - /* vectors set in probe_scan_for_msi() */ - for (i = 0; i < xdev->user_max; i++, j++) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) - u32 vector = pci_irq_vector(xdev->pdev, j); -#else - u32 vector = xdev->entry[j].vector; -#endif - rv = request_irq(vector, xdma_user_irq, 0, xdev->mod_name, - &xdev->user_irq[i]); - if (rv) { - pr_info("user %d couldn't use IRQ#%d, %d\n", - i, vector, rv); - break; - } - pr_info("%d-USR-%d, IRQ#%d with 0x%p\n", xdev->idx, i, vector, - &xdev->user_irq[i]); - } - - /* If any errors occur, free IRQs that were successfully requested */ - if (rv) { - for (i--, j--; i >= 0; i--, j--) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) - u32 vector = pci_irq_vector(xdev->pdev, j); -#else - u32 vector = xdev->entry[j].vector; -#endif - free_irq(vector, &xdev->user_irq[i]); - } - } - - return rv; -} - -static int irq_msi_setup(struct xdma_dev *xdev, struct pci_dev *pdev) -{ - int rv; - - xdev->irq_line = (int)pdev->irq; - rv = request_irq(pdev->irq, xdma_isr, 0, xdev->mod_name, xdev); - if (rv) - dbg_init("Couldn't use IRQ#%d, %d\n", pdev->irq, rv); - else - dbg_init("Using IRQ#%d with 0x%p\n", pdev->irq, xdev); - - return rv; -} - -static int irq_legacy_setup(struct xdma_dev *xdev, struct pci_dev *pdev) -{ - u32 w; - u8 val; - void *reg; - int rv; - - pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &val); - dbg_init("Legacy Interrupt register value = %d\n", val); - if (val > 1) { - val--; - w = (val<<24) | (val<<16) | (val<<8)| val; - /* Program IRQ Block Channel vactor and IRQ Block User vector - * with Legacy interrupt value */ - reg = xdev->bar[xdev->config_bar_idx] + 0x2080; // IRQ user - write_register(w, reg, 0x2080); - write_register(w, reg+0x4, 0x2084); - write_register(w, reg+0x8, 0x2088); - write_register(w, reg+0xC, 0x208C); - reg = xdev->bar[xdev->config_bar_idx] + 0x20A0; // IRQ Block - write_register(w, reg, 0x20A0); - write_register(w, reg+0x4, 0x20A4); - } - - xdev->irq_line = (int)pdev->irq; - rv = request_irq(pdev->irq, xdma_isr, IRQF_SHARED, xdev->mod_name, - xdev); - if (rv) - dbg_init("Couldn't use IRQ#%d, %d\n", pdev->irq, rv); - else - dbg_init("Using IRQ#%d with 0x%p\n", pdev->irq, xdev); - - return rv; -} - -static void irq_teardown(struct xdma_dev *xdev) -{ - if (xdev->msix_enabled) { - irq_msix_channel_teardown(xdev); - irq_msix_user_teardown(xdev); - } else if (xdev->irq_line != -1) { - dbg_init("Releasing IRQ#%d\n", xdev->irq_line); - free_irq(xdev->irq_line, xdev); - } -} - -static int irq_setup(struct xdma_dev *xdev, struct pci_dev *pdev) -{ - pci_keep_intx_enabled(pdev); - - if (xdev->msix_enabled) { - int rv = irq_msix_channel_setup(xdev); - if (rv) - return rv; - rv = irq_msix_user_setup(xdev); - if (rv) - return rv; - prog_irq_msix_channel(xdev, 0); - prog_irq_msix_user(xdev, 0); - - return 0; - } else if (xdev->msi_enabled) - return irq_msi_setup(xdev, pdev); - - return irq_legacy_setup(xdev, pdev); -} - -#ifdef __LIBXDMA_DEBUG__ -static void dump_desc(struct xdma_desc *desc_virt) -{ - int j; - u32 *p = (u32 *)desc_virt; - static char * const field_name[] = { - "magic|extra_adjacent|control", "bytes", "src_addr_lo", - "src_addr_hi", "dst_addr_lo", "dst_addr_hi", "next_addr", - "next_addr_pad"}; - char *dummy; - - /* remove warning about unused variable when debug printing is off */ - dummy = field_name[0]; - - for (j = 0; j < 8; j += 1) { - pr_info("0x%08lx/0x%02lx: 0x%08x 0x%08x %s\n", - (uintptr_t)p, (uintptr_t)p & 15, (int)*p, - le32_to_cpu(*p), field_name[j]); - p++; - } - pr_info("\n"); -} - -static void transfer_dump(struct xdma_transfer *transfer) -{ - int i; - struct xdma_desc *desc_virt = transfer->desc_virt; - - pr_info("xfer 0x%p, state 0x%x, f 0x%x, dir %d, len %u, last %d.\n", - transfer, transfer->state, transfer->flags, transfer->dir, - transfer->len, transfer->last_in_request); - - pr_info("transfer 0x%p, desc %d, bus 0x%llx, adj %d.\n", - transfer, transfer->desc_num, (u64)transfer->desc_bus, - transfer->desc_adjacent); - for (i = 0; i < transfer->desc_num; i += 1) - dump_desc(desc_virt + i); -} -#endif /* __LIBXDMA_DEBUG__ */ - -/* xdma_desc_alloc() - Allocate cache-coherent array of N descriptors. - * - * Allocates an array of 'number' descriptors in contiguous PCI bus addressable - * memory. Chains the descriptors as a singly-linked list; the descriptor's - * next * pointer specifies the bus address of the next descriptor. - * - * - * @dev Pointer to pci_dev - * @number Number of descriptors to be allocated - * @desc_bus_p Pointer where to store the first descriptor bus address - * - * @return Virtual address of the first descriptor - * - */ -static void transfer_desc_init(struct xdma_transfer *transfer, int count) -{ - struct xdma_desc *desc_virt = transfer->desc_virt; - dma_addr_t desc_bus = transfer->desc_bus; - int i; - int adj = count - 1; - int extra_adj; - u32 temp_control; - - BUG_ON(count > XDMA_TRANSFER_MAX_DESC); - - /* create singly-linked list for SG DMA controller */ - for (i = 0; i < count - 1; i++) { - /* increment bus address to next in array */ - desc_bus += sizeof(struct xdma_desc); - - /* singly-linked list uses bus addresses */ - desc_virt[i].next_lo = cpu_to_le32(PCI_DMA_L(desc_bus)); - desc_virt[i].next_hi = cpu_to_le32(PCI_DMA_H(desc_bus)); - desc_virt[i].bytes = cpu_to_le32(0); - - /* any adjacent descriptors? */ - if (adj > 0) { - extra_adj = adj - 1; - if (extra_adj > MAX_EXTRA_ADJ) - extra_adj = MAX_EXTRA_ADJ; - - adj--; - } else { - extra_adj = 0; - } - - temp_control = DESC_MAGIC | (extra_adj << 8); - - desc_virt[i].control = cpu_to_le32(temp_control); - } - /* { i = number - 1 } */ - /* zero the last descriptor next pointer */ - desc_virt[i].next_lo = cpu_to_le32(0); - desc_virt[i].next_hi = cpu_to_le32(0); - desc_virt[i].bytes = cpu_to_le32(0); - - temp_control = DESC_MAGIC; - - desc_virt[i].control = cpu_to_le32(temp_control); -} - -/* xdma_desc_link() - Link two descriptors - * - * Link the first descriptor to a second descriptor, or terminate the first. - * - * @first first descriptor - * @second second descriptor, or NULL if first descriptor must be set as last. - * @second_bus bus address of second descriptor - */ -static void xdma_desc_link(struct xdma_desc *first, struct xdma_desc *second, - dma_addr_t second_bus) -{ - /* - * remember reserved control in first descriptor, but zero - * extra_adjacent! - */ - /* RTO - what's this about? Shouldn't it be 0x0000c0ffUL? */ - u32 control = le32_to_cpu(first->control) & 0x0000f0ffUL; - /* second descriptor given? */ - if (second) { - /* - * link last descriptor of 1st array to first descriptor of - * 2nd array - */ - first->next_lo = cpu_to_le32(PCI_DMA_L(second_bus)); - first->next_hi = cpu_to_le32(PCI_DMA_H(second_bus)); - WARN_ON(first->next_hi); - /* no second descriptor given */ - } else { - /* first descriptor is the last */ - first->next_lo = 0; - first->next_hi = 0; - } - /* merge magic, extra_adjacent and control field */ - control |= DESC_MAGIC; - - /* write bytes and next_num */ - first->control = cpu_to_le32(control); -} - -/* xdma_desc_adjacent -- Set how many descriptors are adjacent to this one */ -static void xdma_desc_adjacent(struct xdma_desc *desc, int next_adjacent) -{ - int extra_adj = 0; - /* remember reserved and control bits */ - u32 control = le32_to_cpu(desc->control) & 0x0000f0ffUL; - u32 max_adj_4k = 0; - - if (next_adjacent > 0) { - extra_adj = next_adjacent - 1; - if (extra_adj > MAX_EXTRA_ADJ){ - extra_adj = MAX_EXTRA_ADJ; - } - max_adj_4k = (0x1000 - ((le32_to_cpu(desc->next_lo))&0xFFF))/32 - 1; - if (extra_adj>max_adj_4k) { - extra_adj = max_adj_4k; - } - if(extra_adj<0){ - printk("Warning: extra_adj<0, converting it to 0\n"); - extra_adj = 0; - } - } - /* merge adjacent and control field */ - control |= 0xAD4B0000UL | (extra_adj << 8); - /* write control and next_adjacent */ - desc->control = cpu_to_le32(control); -} - -/* xdma_desc_control -- Set complete control field of a descriptor. */ -static void xdma_desc_control_set(struct xdma_desc *first, u32 control_field) -{ - /* remember magic and adjacent number */ - u32 control = le32_to_cpu(first->control) & ~(LS_BYTE_MASK); - - BUG_ON(control_field & ~(LS_BYTE_MASK)); - /* merge adjacent and control field */ - control |= control_field; - /* write control and next_adjacent */ - first->control = cpu_to_le32(control); -} - -/* xdma_desc_clear -- Clear bits in control field of a descriptor. */ -static void xdma_desc_control_clear(struct xdma_desc *first, u32 clear_mask) -{ - /* remember magic and adjacent number */ - u32 control = le32_to_cpu(first->control); - - BUG_ON(clear_mask & ~(LS_BYTE_MASK)); - - /* merge adjacent and control field */ - control &= (~clear_mask); - /* write control and next_adjacent */ - first->control = cpu_to_le32(control); -} - -/* xdma_desc_done - recycle cache-coherent linked list of descriptors. - * - * @dev Pointer to pci_dev - * @number Number of descriptors to be allocated - * @desc_virt Pointer to (i.e. virtual address of) first descriptor in list - * @desc_bus Bus address of first descriptor in list - */ -static inline void xdma_desc_done(struct xdma_desc *desc_virt) -{ - memset(desc_virt, 0, XDMA_TRANSFER_MAX_DESC * sizeof(struct xdma_desc)); -} - -/* xdma_desc() - Fill a descriptor with the transfer details - * - * @desc pointer to descriptor to be filled - * @addr root complex address - * @ep_addr end point address - * @len number of bytes, must be a (non-negative) multiple of 4. - * @dir, dma direction - * is the end point address. If zero, vice versa. - * - * Does not modify the next pointer - */ -static void xdma_desc_set(struct xdma_desc *desc, dma_addr_t rc_bus_addr, - u64 ep_addr, int len, int dir) -{ - /* transfer length */ - desc->bytes = cpu_to_le32(len); - if (dir == DMA_TO_DEVICE) { - /* read from root complex memory (source address) */ - desc->src_addr_lo = cpu_to_le32(PCI_DMA_L(rc_bus_addr)); - desc->src_addr_hi = cpu_to_le32(PCI_DMA_H(rc_bus_addr)); - /* write to end point address (destination address) */ - desc->dst_addr_lo = cpu_to_le32(PCI_DMA_L(ep_addr)); - desc->dst_addr_hi = cpu_to_le32(PCI_DMA_H(ep_addr)); - } else { - /* read from end point address (source address) */ - desc->src_addr_lo = cpu_to_le32(PCI_DMA_L(ep_addr)); - desc->src_addr_hi = cpu_to_le32(PCI_DMA_H(ep_addr)); - /* write to root complex memory (destination address) */ - desc->dst_addr_lo = cpu_to_le32(PCI_DMA_L(rc_bus_addr)); - desc->dst_addr_hi = cpu_to_le32(PCI_DMA_H(rc_bus_addr)); - } -} - -/* - * should hold the engine->lock; - */ -static void transfer_abort(struct xdma_engine *engine, - struct xdma_transfer *transfer) -{ - struct xdma_transfer *head; - - BUG_ON(!engine); - BUG_ON(!transfer); - BUG_ON(transfer->desc_num == 0); - - pr_info("abort transfer 0x%p, desc %d, engine desc queued %d.\n", - transfer, transfer->desc_num, engine->desc_dequeued); - - head = list_entry(engine->transfer_list.next, struct xdma_transfer, - entry); - if (head == transfer) - list_del(engine->transfer_list.next); - else - pr_info("engine %s, transfer 0x%p NOT found, 0x%p.\n", - engine->name, transfer, head); - - if (transfer->state == TRANSFER_STATE_SUBMITTED) - transfer->state = TRANSFER_STATE_ABORTED; -} - -/* transfer_queue() - Queue a DMA transfer on the engine - * - * @engine DMA engine doing the transfer - * @transfer DMA transfer submitted to the engine - * - * Takes and releases the engine spinlock - */ -static int transfer_queue(struct xdma_engine *engine, - struct xdma_transfer *transfer) -{ - int rv = 0; - struct xdma_transfer *transfer_started; - struct xdma_dev *xdev; - unsigned long flags; - - BUG_ON(!engine); - BUG_ON(!engine->xdev); - BUG_ON(!transfer); - BUG_ON(transfer->desc_num == 0); - dbg_tfr("transfer_queue(transfer=0x%p).\n", transfer); - - xdev = engine->xdev; - if (xdma_device_flag_check(xdev, XDEV_FLAG_OFFLINE)) { - pr_info("dev 0x%p offline, transfer 0x%p not queued.\n", - xdev, transfer); - return -EBUSY; - } - - /* lock the engine state */ - spin_lock_irqsave(&engine->lock, flags); - - engine->prev_cpu = get_cpu(); - put_cpu(); - - /* engine is being shutdown; do not accept new transfers */ - if (engine->shutdown & ENGINE_SHUTDOWN_REQUEST) { - pr_info("engine %s offline, transfer 0x%p not queued.\n", - engine->name, transfer); - rv = -EBUSY; - goto shutdown; - } - - /* mark the transfer as submitted */ - transfer->state = TRANSFER_STATE_SUBMITTED; - /* add transfer to the tail of the engine transfer queue */ - list_add_tail(&transfer->entry, &engine->transfer_list); - - /* engine is idle? */ - if (!engine->running) { - /* start engine */ - dbg_tfr("transfer_queue(): starting %s engine.\n", - engine->name); - transfer_started = engine_start(engine); - dbg_tfr("transfer=0x%p started %s engine with transfer 0x%p.\n", - transfer, engine->name, transfer_started); - } else { - dbg_tfr("transfer=0x%p queued, with %s engine running.\n", - transfer, engine->name); - } - -shutdown: - /* unlock the engine state */ - dbg_tfr("engine->running = %d\n", engine->running); - spin_unlock_irqrestore(&engine->lock, flags); - return rv; -} - -static void engine_alignments(struct xdma_engine *engine) -{ - u32 w; - u32 align_bytes; - u32 granularity_bytes; - u32 address_bits; - - w = read_register(&engine->regs->alignments); - dbg_init("engine %p name %s alignments=0x%08x\n", engine, - engine->name, (int)w); - - /* RTO - add some macros to extract these fields */ - align_bytes = (w & 0x00ff0000U) >> 16; - granularity_bytes = (w & 0x0000ff00U) >> 8; - address_bits = (w & 0x000000ffU); - - dbg_init("align_bytes = %d\n", align_bytes); - dbg_init("granularity_bytes = %d\n", granularity_bytes); - dbg_init("address_bits = %d\n", address_bits); - - if (w) { - engine->addr_align = align_bytes; - engine->len_granularity = granularity_bytes; - engine->addr_bits = address_bits; - } else { - /* Some default values if alignments are unspecified */ - engine->addr_align = 1; - engine->len_granularity = 1; - engine->addr_bits = 64; - } -} - -static void engine_free_resource(struct xdma_engine *engine) -{ - struct xdma_dev *xdev = engine->xdev; - - /* Release memory use for descriptor writebacks */ - if (engine->poll_mode_addr_virt) { - dbg_sg("Releasing memory for descriptor writeback\n"); - dma_free_coherent(&xdev->pdev->dev, - sizeof(struct xdma_poll_wb), - engine->poll_mode_addr_virt, - engine->poll_mode_bus); - dbg_sg("Released memory for descriptor writeback\n"); - engine->poll_mode_addr_virt = NULL; - } - - if (engine->desc) { - dbg_init("device %s, engine %s pre-alloc desc 0x%p,0x%llx.\n", - dev_name(&xdev->pdev->dev), engine->name, - engine->desc, engine->desc_bus); - dma_free_coherent(&xdev->pdev->dev, - XDMA_TRANSFER_MAX_DESC * sizeof(struct xdma_desc), - engine->desc, engine->desc_bus); - engine->desc = NULL; - } - - if (engine->cyclic_result) { - dma_free_coherent(&xdev->pdev->dev, - CYCLIC_RX_PAGES_MAX * sizeof(struct xdma_result), - engine->cyclic_result, engine->cyclic_result_bus); - engine->cyclic_result = NULL; - } -} - -static void engine_destroy(struct xdma_dev *xdev, struct xdma_engine *engine) -{ - BUG_ON(!xdev); - BUG_ON(!engine); - - dbg_sg("Shutting down engine %s%d", engine->name, engine->channel); - - /* Disable interrupts to stop processing new events during shutdown */ - write_register(0x0, &engine->regs->interrupt_enable_mask, - (unsigned long)(&engine->regs->interrupt_enable_mask) - - (unsigned long)(&engine->regs)); - - if (enable_credit_mp && engine->streaming && - engine->dir == DMA_FROM_DEVICE) { - u32 reg_value = (0x1 << engine->channel) << 16; - struct sgdma_common_regs *reg = (struct sgdma_common_regs *) - (xdev->bar[xdev->config_bar_idx] + - (0x6*TARGET_SPACING)); - write_register(reg_value, ®->credit_mode_enable_w1c, 0); - } - - /* Release memory use for descriptor writebacks */ - engine_free_resource(engine); - - memset(engine, 0, sizeof(struct xdma_engine)); - /* Decrement the number of engines available */ - xdev->engines_num--; -} - -/** - *engine_cyclic_stop() - stop a cyclic transfer running on an SG DMA engine - * - *engine->lock must be taken - */ -struct xdma_transfer *engine_cyclic_stop(struct xdma_engine *engine) -{ - struct xdma_transfer *transfer = 0; - - /* transfers on queue? */ - if (!list_empty(&engine->transfer_list)) { - /* pick first transfer on the queue (was submitted to engine) */ - transfer = list_entry(engine->transfer_list.next, - struct xdma_transfer, entry); - BUG_ON(!transfer); - - xdma_engine_stop(engine); - - if (transfer->cyclic) { - if (engine->xdma_perf) - dbg_perf("Stopping perf transfer on %s\n", - engine->name); - else - dbg_perf("Stopping cyclic transfer on %s\n", - engine->name); - /* make sure the handler sees correct transfer state */ - transfer->cyclic = 1; - /* - * set STOP flag and interrupt on completion, on the - * last descriptor - */ - xdma_desc_control_set( - transfer->desc_virt + transfer->desc_num - 1, - XDMA_DESC_COMPLETED | XDMA_DESC_STOPPED); - } else { - dbg_sg("(engine=%p) running transfer is not cyclic\n", - engine); - } - } else { - dbg_sg("(engine=%p) found not running transfer.\n", engine); - } - return transfer; -} -EXPORT_SYMBOL_GPL(engine_cyclic_stop); - -static int engine_writeback_setup(struct xdma_engine *engine) -{ - u32 w; - struct xdma_dev *xdev; - struct xdma_poll_wb *writeback; - - BUG_ON(!engine); - xdev = engine->xdev; - BUG_ON(!xdev); - - /* - * RTO - doing the allocation per engine is wasteful since a full page - * is allocated each time - better to allocate one page for the whole - * device during probe() and set per-engine offsets here - */ - writeback = (struct xdma_poll_wb *)engine->poll_mode_addr_virt; - writeback->completed_desc_count = 0; - - dbg_init("Setting writeback location to 0x%llx for engine %p", - engine->poll_mode_bus, engine); - w = cpu_to_le32(PCI_DMA_L(engine->poll_mode_bus)); - write_register(w, &engine->regs->poll_mode_wb_lo, - (unsigned long)(&engine->regs->poll_mode_wb_lo) - - (unsigned long)(&engine->regs)); - w = cpu_to_le32(PCI_DMA_H(engine->poll_mode_bus)); - write_register(w, &engine->regs->poll_mode_wb_hi, - (unsigned long)(&engine->regs->poll_mode_wb_hi) - - (unsigned long)(&engine->regs)); - - return 0; -} - - -/* engine_create() - Create an SG DMA engine bookkeeping data structure - * - * An SG DMA engine consists of the resources for a single-direction transfer - * queue; the SG DMA hardware, the software queue and interrupt handling. - * - * @dev Pointer to pci_dev - * @offset byte address offset in BAR[xdev->config_bar_idx] resource for the - * SG DMA * controller registers. - * @dir: DMA_TO/FROM_DEVICE - * @streaming Whether the engine is attached to AXI ST (rather than MM) - */ -static int engine_init_regs(struct xdma_engine *engine) -{ - u32 reg_value; - int rv = 0; - - write_register(XDMA_CTRL_NON_INCR_ADDR, &engine->regs->control_w1c, - (unsigned long)(&engine->regs->control_w1c) - - (unsigned long)(&engine->regs)); - - engine_alignments(engine); - - /* Configure error interrupts by default */ - reg_value = XDMA_CTRL_IE_DESC_ALIGN_MISMATCH; - reg_value |= XDMA_CTRL_IE_MAGIC_STOPPED; - reg_value |= XDMA_CTRL_IE_MAGIC_STOPPED; - reg_value |= XDMA_CTRL_IE_READ_ERROR; - reg_value |= XDMA_CTRL_IE_DESC_ERROR; - - /* if using polled mode, configure writeback address */ - if (poll_mode) { - rv = engine_writeback_setup(engine); - if (rv) { - dbg_init("%s descr writeback setup failed.\n", - engine->name); - goto fail_wb; - } - } else { - /* enable the relevant completion interrupts */ - reg_value |= XDMA_CTRL_IE_DESC_STOPPED; - reg_value |= XDMA_CTRL_IE_DESC_COMPLETED; - - if (engine->streaming && engine->dir == DMA_FROM_DEVICE) - reg_value |= XDMA_CTRL_IE_IDLE_STOPPED; - } - - /* Apply engine configurations */ - write_register(reg_value, &engine->regs->interrupt_enable_mask, - (unsigned long)(&engine->regs->interrupt_enable_mask) - - (unsigned long)(&engine->regs)); - - engine->interrupt_enable_mask_value = reg_value; - - /* only enable credit mode for AXI-ST C2H */ - if (enable_credit_mp && engine->streaming && - engine->dir == DMA_FROM_DEVICE) { - - struct xdma_dev *xdev = engine->xdev; - u32 reg_value = (0x1 << engine->channel) << 16; - struct sgdma_common_regs *reg = (struct sgdma_common_regs *) - (xdev->bar[xdev->config_bar_idx] + - (0x6*TARGET_SPACING)); - - write_register(reg_value, ®->credit_mode_enable_w1s, 0); - } - - return 0; - -fail_wb: - return rv; -} - -static int engine_alloc_resource(struct xdma_engine *engine) -{ - struct xdma_dev *xdev = engine->xdev; - - engine->desc = dma_alloc_coherent(&xdev->pdev->dev, - XDMA_TRANSFER_MAX_DESC * sizeof(struct xdma_desc), - &engine->desc_bus, GFP_KERNEL); - if (!engine->desc) { - pr_warn("dev %s, %s pre-alloc desc OOM.\n", - dev_name(&xdev->pdev->dev), engine->name); - goto err_out; - } - - if (poll_mode) { - engine->poll_mode_addr_virt = dma_alloc_coherent( - &xdev->pdev->dev, - sizeof(struct xdma_poll_wb), - &engine->poll_mode_bus, GFP_KERNEL); - if (!engine->poll_mode_addr_virt) { - pr_warn("%s, %s poll pre-alloc writeback OOM.\n", - dev_name(&xdev->pdev->dev), engine->name); - goto err_out; - } - } - - if (engine->streaming && engine->dir == DMA_FROM_DEVICE) { - engine->cyclic_result = dma_alloc_coherent(&xdev->pdev->dev, - CYCLIC_RX_PAGES_MAX * sizeof(struct xdma_result), - &engine->cyclic_result_bus, GFP_KERNEL); - - if (!engine->cyclic_result) { - pr_warn("%s, %s pre-alloc result OOM.\n", - dev_name(&xdev->pdev->dev), engine->name); - goto err_out; - } - } - - return 0; - -err_out: - engine_free_resource(engine); - return -ENOMEM; -} - -static int engine_init(struct xdma_engine *engine, struct xdma_dev *xdev, - int offset, enum dma_data_direction dir, int channel) -{ - int rv; - u32 val; - - dbg_init("channel %d, offset 0x%x, dir %d.\n", channel, offset, dir); - - /* set magic */ - engine->magic = MAGIC_ENGINE; - - engine->channel = channel; - - /* engine interrupt request bit */ - engine->irq_bitmask = (1 << XDMA_ENG_IRQ_NUM) - 1; - engine->irq_bitmask <<= (xdev->engines_num * XDMA_ENG_IRQ_NUM); - engine->bypass_offset = xdev->engines_num * BYPASS_MODE_SPACING; - - /* parent */ - engine->xdev = xdev; - /* register address */ - engine->regs = (xdev->bar[xdev->config_bar_idx] + offset); - engine->sgdma_regs = xdev->bar[xdev->config_bar_idx] + offset + - SGDMA_OFFSET_FROM_CHANNEL; - val = read_register(&engine->regs->identifier); - if (val & 0x8000U) - engine->streaming = 1; - - /* remember SG DMA direction */ - engine->dir = dir; - sprintf(engine->name, "%d-%s%d-%s", xdev->idx, - (dir == DMA_TO_DEVICE) ? "H2C" : "C2H", channel, - engine->streaming ? "ST" : "MM"); - - dbg_init("engine %p name %s irq_bitmask=0x%08x\n", engine, engine->name, - (int)engine->irq_bitmask); - - /* initialize the deferred work for transfer completion */ - INIT_WORK(&engine->work, engine_service_work); - - if (dir == DMA_TO_DEVICE) - xdev->mask_irq_h2c |= engine->irq_bitmask; - else - xdev->mask_irq_c2h |= engine->irq_bitmask; - xdev->engines_num++; - - rv = engine_alloc_resource(engine); - if (rv) - return rv; - - rv = engine_init_regs(engine); - if (rv) - return rv; - - return 0; -} - -/* transfer_destroy() - free transfer */ -static void transfer_destroy(struct xdma_dev *xdev, struct xdma_transfer *xfer) -{ - /* free descriptors */ - xdma_desc_done(xfer->desc_virt); - - if (xfer->last_in_request && (xfer->flags & XFER_FLAG_NEED_UNMAP)) { - struct sg_table *sgt = xfer->sgt; - - if (sgt->nents) { - pci_unmap_sg(xdev->pdev, sgt->sgl, sgt->nents, - xfer->dir); - sgt->nents = 0; - } - } -} - -static int transfer_build(struct xdma_engine *engine, - struct xdma_request_cb *req, unsigned int desc_max) -{ - struct xdma_transfer *xfer = &req->xfer; - struct sw_desc *sdesc = &(req->sdesc[req->sw_desc_idx]); - int i = 0; - int j = 0; - - for (; i < desc_max; i++, j++, sdesc++) { - dbg_desc("sw desc %d/%u: 0x%llx, 0x%x, ep 0x%llx.\n", - i + req->sw_desc_idx, req->sw_desc_cnt, - sdesc->addr, sdesc->len, req->ep_addr); - - /* fill in descriptor entry j with transfer details */ - xdma_desc_set(xfer->desc_virt + j, sdesc->addr, req->ep_addr, - sdesc->len, xfer->dir); - xfer->len += sdesc->len; - - /* for non-inc-add mode don't increment ep_addr */ - if (!engine->non_incr_addr) - req->ep_addr += sdesc->len; - } - req->sw_desc_idx += desc_max; - return 0; -} - -static int transfer_init(struct xdma_engine *engine, struct xdma_request_cb *req) -{ - struct xdma_transfer *xfer = &req->xfer; - unsigned int desc_max = min_t(unsigned int, - req->sw_desc_cnt - req->sw_desc_idx, - XDMA_TRANSFER_MAX_DESC); - int i = 0; - int last = 0; - u32 control; - - memset(xfer, 0, sizeof(*xfer)); - - /* initialize wait queue */ - init_waitqueue_head(&xfer->wq); - - /* remember direction of transfer */ - xfer->dir = engine->dir; - - xfer->desc_virt = engine->desc; - xfer->desc_bus = engine->desc_bus; - - transfer_desc_init(xfer, desc_max); - - dbg_sg("transfer->desc_bus = 0x%llx.\n", (u64)xfer->desc_bus); - - transfer_build(engine, req, desc_max); - - /* terminate last descriptor */ - last = desc_max - 1; - xdma_desc_link(xfer->desc_virt + last, 0, 0); - /* stop engine, EOP for AXI ST, req IRQ on last descriptor */ - control = XDMA_DESC_STOPPED; - control |= XDMA_DESC_EOP; - control |= XDMA_DESC_COMPLETED; - xdma_desc_control_set(xfer->desc_virt + last, control); - - xfer->desc_num = xfer->desc_adjacent = desc_max; - - dbg_sg("transfer 0x%p has %d descriptors\n", xfer, xfer->desc_num); - /* fill in adjacent numbers */ - for (i = 0; i < xfer->desc_num; i++) - xdma_desc_adjacent(xfer->desc_virt + i, xfer->desc_num - i - 1); - - return 0; -} - -#ifdef __LIBXDMA_DEBUG__ -static void sgt_dump(struct sg_table *sgt) -{ - int i; - struct scatterlist *sg = sgt->sgl; - - pr_info("sgt 0x%p, sgl 0x%p, nents %u/%u.\n", - sgt, sgt->sgl, sgt->nents, sgt->orig_nents); - - for (i = 0; i < sgt->orig_nents; i++, sg = sg_next(sg)) - pr_info("%d, 0x%p, pg 0x%p,%u+%u, dma 0x%llx,%u.\n", - i, sg, sg_page(sg), sg->offset, sg->length, - sg_dma_address(sg), sg_dma_len(sg)); -} - -static void xdma_request_cb_dump(struct xdma_request_cb *req) -{ - int i; - - pr_info("request 0x%p, total %u, ep 0x%llx, sw_desc %u, sgt 0x%p.\n", - req, req->total_len, req->ep_addr, req->sw_desc_cnt, req->sgt); - sgt_dump(req->sgt); - for (i = 0; i < req->sw_desc_cnt; i++) - pr_info("%d/%u, 0x%llx, %u.\n", - i, req->sw_desc_cnt, req->sdesc[i].addr, - req->sdesc[i].len); -} -#endif - -static void xdma_request_free(struct xdma_request_cb *req) -{ - if (((unsigned long)req) >= VMALLOC_START && - ((unsigned long)req) < VMALLOC_END) - vfree(req); - else - kfree(req); -} - -static struct xdma_request_cb * xdma_request_alloc(unsigned int sdesc_nr) -{ - struct xdma_request_cb *req; - unsigned int size = sizeof(struct xdma_request_cb) + - sdesc_nr * sizeof(struct sw_desc); - - req = kzalloc(size, GFP_KERNEL); - if (!req) { - req = vmalloc(size); - if (req) - memset(req, 0, size); - } - if (!req) { - pr_info("OOM, %u sw_desc, %u.\n", sdesc_nr, size); - return NULL; - } - - return req; -} - -static struct xdma_request_cb * xdma_init_request(struct sg_table *sgt, - u64 ep_addr) -{ - struct xdma_request_cb *req; - struct scatterlist *sg = sgt->sgl; - int max = sgt->nents; - int extra = 0; - int i, j = 0; - - for (i = 0; i < max; i++, sg = sg_next(sg)) { - unsigned int len = sg_dma_len(sg); - - if (unlikely(len > XDMA_DESC_BLEN_MAX)) - extra += len >> XDMA_DESC_BLEN_BITS; - } - -//pr_info("ep 0x%llx, desc %u+%u.\n", ep_addr, max, extra); - - max += extra; - req = xdma_request_alloc(max); - if (!req) - return NULL; - - req->sgt = sgt; - req->ep_addr = ep_addr; - - for (i = 0, sg = sgt->sgl; i < sgt->nents; i++, sg = sg_next(sg)) { - unsigned int tlen = sg_dma_len(sg); - dma_addr_t addr = sg_dma_address(sg); - - req->total_len += tlen; - while (tlen) { - req->sdesc[j].addr = addr; - if (tlen > XDMA_DESC_BLEN_MAX) { - req->sdesc[j].len = XDMA_DESC_BLEN_MAX; - addr += XDMA_DESC_BLEN_MAX; - tlen -= XDMA_DESC_BLEN_MAX; - } else { - req->sdesc[j].len = tlen; - tlen = 0; - } - j++; - } - } - BUG_ON(j > max); - - req->sw_desc_cnt = j; -#ifdef __LIBXDMA_DEBUG__ - xdma_request_cb_dump(req); -#endif - return req; -} - -ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr, - struct sg_table *sgt, bool dma_mapped, int timeout_ms) -{ - struct xdma_dev *xdev = (struct xdma_dev *)dev_hndl; - struct xdma_engine *engine; - int rv = 0; - ssize_t done = 0; - struct scatterlist *sg = sgt->sgl; - int nents; - enum dma_data_direction dir = write ? DMA_TO_DEVICE : DMA_FROM_DEVICE; - struct xdma_request_cb *req = NULL; - - if (!dev_hndl) - return -EINVAL; - - if (debug_check_dev_hndl(__func__, xdev->pdev, dev_hndl) < 0) - return -EINVAL; - - if (write == 1) { - if (channel >= xdev->h2c_channel_max) { - pr_warn("H2C channel %d >= %d.\n", - channel, xdev->h2c_channel_max); - return -EINVAL; - } - engine = &xdev->engine_h2c[channel]; - } else if (write == 0) { - if (channel >= xdev->c2h_channel_max) { - pr_warn("C2H channel %d >= %d.\n", - channel, xdev->c2h_channel_max); - return -EINVAL; - } - engine = &xdev->engine_c2h[channel]; - } else { - pr_warn("write %d, exp. 0|1.\n", write); - return -EINVAL; - } - - BUG_ON(!engine); - BUG_ON(engine->magic != MAGIC_ENGINE); - - xdev = engine->xdev; - if (xdma_device_flag_check(xdev, XDEV_FLAG_OFFLINE)) { - pr_info("xdev 0x%p, offline.\n", xdev); - return -EBUSY; - } - - /* check the direction */ - if (engine->dir != dir) { - pr_info("0x%p, %s, %d, W %d, 0x%x/0x%x mismatch.\n", - engine, engine->name, channel, write, engine->dir, dir); - return -EINVAL; - } - - if (!dma_mapped) { - nents = pci_map_sg(xdev->pdev, sg, sgt->orig_nents, dir); - if (!nents) { - pr_info("map sgl failed, sgt 0x%p.\n", sgt); - return -EIO; - } - sgt->nents = nents; - } else { - BUG_ON(!sgt->nents); - } - - req = xdma_init_request(sgt, ep_addr); - if (!req) { - rv = -ENOMEM; - goto unmap_sgl; - } - - dbg_tfr("%s, len %u sg cnt %u.\n", - engine->name, req->total_len, req->sw_desc_cnt); - - sg = sgt->sgl; - nents = req->sw_desc_cnt; - while (nents) { - unsigned long flags; - struct xdma_transfer *xfer; - - /* one transfer at a time */ - spin_lock(&engine->desc_lock); - - /* build transfer */ - rv = transfer_init(engine, req); - if (rv < 0) { - spin_unlock(&engine->desc_lock); - goto unmap_sgl; - } - xfer = &req->xfer; - - if (!dma_mapped) - xfer->flags = XFER_FLAG_NEED_UNMAP; - - /* last transfer for the given request? */ - nents -= xfer->desc_num; - if (!nents) { - xfer->last_in_request = 1; - xfer->sgt = sgt; - } - - dbg_tfr("xfer, %u, ep 0x%llx, done %lu, sg %u/%u.\n", - xfer->len, req->ep_addr, done, req->sw_desc_idx, - req->sw_desc_cnt); - -#ifdef __LIBXDMA_DEBUG__ - transfer_dump(xfer); -#endif - - rv = transfer_queue(engine, xfer); - if (rv < 0) { - spin_unlock(&engine->desc_lock); - pr_info("unable to submit %s, %d.\n", engine->name, rv); - goto unmap_sgl; - } - - /* - * When polling, determine how many descriptors have been queued * on the engine to determine the writeback value expected - */ - if (poll_mode) { - unsigned int desc_count; - - spin_lock_irqsave(&engine->lock, flags); - desc_count = xfer->desc_num; - spin_unlock_irqrestore(&engine->lock, flags); - - dbg_tfr("%s poll desc_count=%d\n", - engine->name, desc_count); - rv = engine_service_poll(engine, desc_count); - - } else { - rv = wait_event_interruptible_timeout(xfer->wq, - (xfer->state != TRANSFER_STATE_SUBMITTED), - msecs_to_jiffies(timeout_ms)); - } - - spin_lock_irqsave(&engine->lock, flags); - - switch(xfer->state) { - case TRANSFER_STATE_COMPLETED: - spin_unlock_irqrestore(&engine->lock, flags); - - dbg_tfr("transfer %p, %u, ep 0x%llx compl, +%lu.\n", - xfer, xfer->len, req->ep_addr - xfer->len, done); - done += xfer->len; - rv = 0; - break; - case TRANSFER_STATE_FAILED: - pr_info("xfer 0x%p,%u, failed, ep 0x%llx.\n", - xfer, xfer->len, req->ep_addr - xfer->len); - spin_unlock_irqrestore(&engine->lock, flags); - -#ifdef __LIBXDMA_DEBUG__ - transfer_dump(xfer); - sgt_dump(sgt); -#endif - rv = -EIO; - break; - default: - /* transfer can still be in-flight */ - pr_info("xfer 0x%p,%u, s 0x%x timed out, ep 0x%llx.\n", - xfer, xfer->len, xfer->state, req->ep_addr); - engine_status_read(engine, 0, 1); - //engine_status_dump(engine); - transfer_abort(engine, xfer); - - xdma_engine_stop(engine); - spin_unlock_irqrestore(&engine->lock, flags); - -#ifdef __LIBXDMA_DEBUG__ - transfer_dump(xfer); - sgt_dump(sgt); -#endif - rv = -ERESTARTSYS; - break; - } - transfer_destroy(xdev, xfer); - spin_unlock(&engine->desc_lock); - - if (rv < 0) - goto unmap_sgl; - } /* while (sg) */ - -unmap_sgl: - if (!dma_mapped && sgt->nents) { - pci_unmap_sg(xdev->pdev, sgt->sgl, sgt->orig_nents, dir); - sgt->nents = 0; - } - - if (req) - xdma_request_free(req); - - if (rv < 0) - return rv; - - return done; -} -EXPORT_SYMBOL_GPL(xdma_xfer_submit); - -int xdma_performance_submit(struct xdma_dev *xdev, struct xdma_engine *engine) -{ - u8 *buffer_virt; - u32 max_consistent_size = 128 * 32 * 1024; /* 1024 pages, 4MB */ - dma_addr_t buffer_bus; /* bus address */ - struct xdma_transfer *transfer; - u64 ep_addr = 0; - int num_desc_in_a_loop = 128; - int size_in_desc = engine->xdma_perf->transfer_size; - int size = size_in_desc * num_desc_in_a_loop; - int i; - - BUG_ON(size_in_desc > max_consistent_size); - - if (size > max_consistent_size) { - size = max_consistent_size; - num_desc_in_a_loop = size / size_in_desc; - } - - buffer_virt = dma_alloc_coherent(&xdev->pdev->dev, size, - &buffer_bus, GFP_KERNEL); - - /* allocate transfer data structure */ - transfer = kzalloc(sizeof(struct xdma_transfer), GFP_KERNEL); - BUG_ON(!transfer); - - /* 0 = write engine (to_dev=0) , 1 = read engine (to_dev=1) */ - transfer->dir = engine->dir; - /* set number of descriptors */ - transfer->desc_num = num_desc_in_a_loop; - - /* allocate descriptor list */ - if (!engine->desc) { - engine->desc = dma_alloc_coherent(&xdev->pdev->dev, - num_desc_in_a_loop * sizeof(struct xdma_desc), - &engine->desc_bus, GFP_KERNEL); - BUG_ON(!engine->desc); - dbg_init("device %s, engine %s pre-alloc desc 0x%p,0x%llx.\n", - dev_name(&xdev->pdev->dev), engine->name, - engine->desc, engine->desc_bus); - } - transfer->desc_virt = engine->desc; - transfer->desc_bus = engine->desc_bus; - - transfer_desc_init(transfer, transfer->desc_num); - - dbg_sg("transfer->desc_bus = 0x%llx.\n", (u64)transfer->desc_bus); - - for (i = 0; i < transfer->desc_num; i++) { - struct xdma_desc *desc = transfer->desc_virt + i; - dma_addr_t rc_bus_addr = buffer_bus + size_in_desc * i; - - /* fill in descriptor entry with transfer details */ - xdma_desc_set(desc, rc_bus_addr, ep_addr, size_in_desc, - engine->dir); - } - - /* stop engine and request interrupt on last descriptor */ - xdma_desc_control_set(transfer->desc_virt, 0); - /* create a linked loop */ - xdma_desc_link(transfer->desc_virt + transfer->desc_num - 1, - transfer->desc_virt, transfer->desc_bus); - - transfer->cyclic = 1; - - /* initialize wait queue */ - init_waitqueue_head(&transfer->wq); - - //printk("=== Descriptor print for PERF \n"); - //transfer_dump(transfer); - - dbg_perf("Queueing XDMA I/O %s request for performance measurement.\n", - engine->dir ? "write (to dev)" : "read (from dev)"); - transfer_queue(engine, transfer); - return 0; - -} -EXPORT_SYMBOL_GPL(xdma_performance_submit); - -static struct xdma_dev *alloc_dev_instance(struct pci_dev *pdev) -{ - int i; - struct xdma_dev *xdev; - struct xdma_engine *engine; - - BUG_ON(!pdev); - - /* allocate zeroed device book keeping structure */ - xdev = kzalloc(sizeof(struct xdma_dev), GFP_KERNEL); - if (!xdev) { - pr_info("OOM, xdma_dev.\n"); - return NULL; - } - spin_lock_init(&xdev->lock); - - xdev->magic = MAGIC_DEVICE; - xdev->config_bar_idx = -1; - xdev->user_bar_idx = -1; - xdev->bypass_bar_idx = -1; - xdev->irq_line = -1; - - /* create a driver to device reference */ - xdev->pdev = pdev; - dbg_init("xdev = 0x%p\n", xdev); - - /* Set up data user IRQ data structures */ - for (i = 0; i < 16; i++) { - xdev->user_irq[i].xdev = xdev; - spin_lock_init(&xdev->user_irq[i].events_lock); - init_waitqueue_head(&xdev->user_irq[i].events_wq); - xdev->user_irq[i].handler = NULL; - xdev->user_irq[i].user_idx = i; /* 0 based */ - } - - engine = xdev->engine_h2c; - for (i = 0; i < XDMA_CHANNEL_NUM_MAX; i++, engine++) { - spin_lock_init(&engine->lock); - spin_lock_init(&engine->desc_lock); - INIT_LIST_HEAD(&engine->transfer_list); - init_waitqueue_head(&engine->shutdown_wq); - init_waitqueue_head(&engine->xdma_perf_wq); - } - - engine = xdev->engine_c2h; - for (i = 0; i < XDMA_CHANNEL_NUM_MAX; i++, engine++) { - spin_lock_init(&engine->lock); - spin_lock_init(&engine->desc_lock); - INIT_LIST_HEAD(&engine->transfer_list); - init_waitqueue_head(&engine->shutdown_wq); - init_waitqueue_head(&engine->xdma_perf_wq); - } - - return xdev; -} - -static int request_regions(struct xdma_dev *xdev, struct pci_dev *pdev) -{ - int rv; - - BUG_ON(!xdev); - BUG_ON(!pdev); - - dbg_init("pci_request_regions()\n"); - rv = pci_request_regions(pdev, xdev->mod_name); - /* could not request all regions? */ - if (rv) { - dbg_init("pci_request_regions() = %d, device in use?\n", rv); - /* assume device is in use so do not disable it later */ - xdev->regions_in_use = 1; - } else { - xdev->got_regions = 1; - } - - return rv; -} - -static int set_dma_mask(struct pci_dev *pdev) -{ - BUG_ON(!pdev); - - dbg_init("sizeof(dma_addr_t) == %ld\n", sizeof(dma_addr_t)); - /* 64-bit addressing capability for XDMA? */ - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - /* query for DMA transfer */ - /* @see Documentation/DMA-mapping.txt */ - dbg_init("pci_set_dma_mask()\n"); - /* use 64-bit DMA */ - dbg_init("Using a 64-bit DMA mask.\n"); - /* use 32-bit DMA for descriptors */ - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - /* use 64-bit DMA, 32-bit for consistent */ - } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - dbg_init("Could not set 64-bit DMA mask.\n"); - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - /* use 32-bit DMA */ - dbg_init("Using a 32-bit DMA mask.\n"); - } else { - dbg_init("No suitable DMA possible.\n"); - return -EINVAL; - } - - return 0; -} - -static u32 get_engine_channel_id(struct engine_regs *regs) -{ - u32 value; - - BUG_ON(!regs); - - value = read_register(®s->identifier); - - return (value & 0x00000f00U) >> 8; -} - -static u32 get_engine_id(struct engine_regs *regs) -{ - u32 value; - - BUG_ON(!regs); - - value = read_register(®s->identifier); - return (value & 0xffff0000U) >> 16; -} - -static void remove_engines(struct xdma_dev *xdev) -{ - struct xdma_engine *engine; - int i; - - BUG_ON(!xdev); - - /* iterate over channels */ - for (i = 0; i < xdev->h2c_channel_max; i++) { - engine = &xdev->engine_h2c[i]; - if (engine->magic == MAGIC_ENGINE) { - dbg_sg("Remove %s, %d", engine->name, i); - engine_destroy(xdev, engine); - dbg_sg("%s, %d removed", engine->name, i); - } - } - - for (i = 0; i < xdev->c2h_channel_max; i++) { - engine = &xdev->engine_c2h[i]; - if (engine->magic == MAGIC_ENGINE) { - dbg_sg("Remove %s, %d", engine->name, i); - engine_destroy(xdev, engine); - dbg_sg("%s, %d removed", engine->name, i); - } - } -} - -static int probe_for_engine(struct xdma_dev *xdev, enum dma_data_direction dir, - int channel) -{ - struct engine_regs *regs; - int offset = channel * CHANNEL_SPACING; - u32 engine_id; - u32 engine_id_expected; - u32 channel_id; - struct xdma_engine *engine; - int rv; - - /* register offset for the engine */ - /* read channels at 0x0000, write channels at 0x1000, - * channels at 0x100 interval */ - if (dir == DMA_TO_DEVICE) { - engine_id_expected = XDMA_ID_H2C; - engine = &xdev->engine_h2c[channel]; - } else { - offset += H2C_CHANNEL_OFFSET; - engine_id_expected = XDMA_ID_C2H; - engine = &xdev->engine_c2h[channel]; - } - - regs = xdev->bar[xdev->config_bar_idx] + offset; - engine_id = get_engine_id(regs); - channel_id = get_engine_channel_id(regs); - - if ((engine_id != engine_id_expected) || (channel_id != channel)) { - dbg_init("%s %d engine, reg off 0x%x, id mismatch 0x%x,0x%x," - "exp 0x%x,0x%x, SKIP.\n", - dir == DMA_TO_DEVICE ? "H2C" : "C2H", - channel, offset, engine_id, channel_id, - engine_id_expected, channel_id != channel); - return -EINVAL; - } - - dbg_init("found AXI %s %d engine, reg. off 0x%x, id 0x%x,0x%x.\n", - dir == DMA_TO_DEVICE ? "H2C" : "C2H", channel, - offset, engine_id, channel_id); - - /* allocate and initialize engine */ - rv = engine_init(engine, xdev, offset, dir, channel); - if (rv != 0) { - pr_info("failed to create AXI %s %d engine.\n", - dir == DMA_TO_DEVICE ? "H2C" : "C2H", - channel); - return rv; - } - - return 0; -} - -static int probe_engines(struct xdma_dev *xdev) -{ - int i; - int rv = 0; - - BUG_ON(!xdev); - - /* iterate over channels */ - for (i = 0; i < xdev->h2c_channel_max; i++) { - rv = probe_for_engine(xdev, DMA_TO_DEVICE, i); - if (rv) - break; - } - xdev->h2c_channel_max = i; - - for (i = 0; i < xdev->c2h_channel_max; i++) { - rv = probe_for_engine(xdev, DMA_FROM_DEVICE, i); - if (rv) - break; - } - xdev->c2h_channel_max = i; - - return 0; -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) -static void pci_enable_relaxed_ordering(struct pci_dev *pdev) -{ - pcie_capability_set_word(pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN); -} -#else -static void pci_enable_relaxed_ordering(struct pci_dev *pdev) -{ - u16 v; - int pos; - - pos = pci_pcie_cap(pdev); - if (pos > 0) { - pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &v); - v |= PCI_EXP_DEVCTL_RELAX_EN; - pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, v); - } -} -#endif - -static void pci_check_extended_tag(struct xdma_dev *xdev, struct pci_dev *pdev) -{ - u16 cap; - u32 v; - void *__iomem reg; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) - pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &cap); -#else - int pos; - - pos = pci_pcie_cap(pdev); - if (pos > 0) - pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &cap); - else { - pr_info("pdev 0x%p, unable to access pcie cap.\n", pdev); - return; - } -#endif - - if ((cap & PCI_EXP_DEVCTL_EXT_TAG)) - return; - - /* extended tag not enabled */ - pr_info("0x%p EXT_TAG disabled.\n", pdev); - - if (xdev->config_bar_idx < 0) { - pr_info("pdev 0x%p, xdev 0x%p, config bar UNKNOWN.\n", - pdev, xdev); - return; - } - - reg = xdev->bar[xdev->config_bar_idx] + XDMA_OFS_CONFIG + 0x4C; - v = read_register(reg); - v = (v & 0xFF) | (((u32)32) << 8); - write_register(v, reg, XDMA_OFS_CONFIG + 0x4C); -} - -void *xdma_device_open(const char *mname, struct pci_dev *pdev, int *user_max, - int *h2c_channel_max, int *c2h_channel_max) -{ - struct xdma_dev *xdev = NULL; - int rv = 0; - - pr_info("%s device %s, 0x%p.\n", mname, dev_name(&pdev->dev), pdev); - - /* allocate zeroed device book keeping structure */ - xdev = alloc_dev_instance(pdev); - if (!xdev) - return NULL; - xdev->mod_name = mname; - xdev->user_max = *user_max; - xdev->h2c_channel_max = *h2c_channel_max; - xdev->c2h_channel_max = *c2h_channel_max; - - xdma_device_flag_set(xdev, XDEV_FLAG_OFFLINE); - xdev_list_add(xdev); - - if (xdev->user_max == 0 || xdev->user_max > MAX_USER_IRQ) - xdev->user_max = MAX_USER_IRQ; - if (xdev->h2c_channel_max == 0 || - xdev->h2c_channel_max > XDMA_CHANNEL_NUM_MAX) - xdev->h2c_channel_max = XDMA_CHANNEL_NUM_MAX; - if (xdev->c2h_channel_max == 0 || - xdev->c2h_channel_max > XDMA_CHANNEL_NUM_MAX) - xdev->c2h_channel_max = XDMA_CHANNEL_NUM_MAX; - - rv = pci_enable_device(pdev); - if (rv) { - dbg_init("pci_enable_device() failed, %d.\n", rv); - goto err_enable; - } - - /* keep INTx enabled */ - pci_check_intr_pend(pdev); - - /* enable relaxed ordering */ - pci_enable_relaxed_ordering(pdev); - - pci_check_extended_tag(xdev, pdev); - - /* force MRRS to be 512 */ - rv = pcie_set_readrq(pdev, 512); - if (rv) - pr_info("device %s, error set PCI_EXP_DEVCTL_READRQ: %d.\n", - dev_name(&pdev->dev), rv); - - /* enable bus master capability */ - pci_set_master(pdev); - - rv = request_regions(xdev, pdev); - if (rv) - goto err_regions; - - rv = map_bars(xdev, pdev); - if (rv) - goto err_map; - - rv = set_dma_mask(pdev); - if (rv) - goto err_mask; - - check_nonzero_interrupt_status(xdev); - /* explicitely zero all interrupt enable masks */ - channel_interrupts_disable(xdev, ~0); - user_interrupts_disable(xdev, ~0); - read_interrupts(xdev); - - rv = probe_engines(xdev); - if (rv) - goto err_engines; - - rv = enable_msi_msix(xdev, pdev); - if (rv < 0) - goto err_enable_msix; - - rv = irq_setup(xdev, pdev); - if (rv < 0) - goto err_interrupts; - - if (!poll_mode) - channel_interrupts_enable(xdev, ~0); - - /* Flush writes */ - read_interrupts(xdev); - - *user_max = xdev->user_max; - *h2c_channel_max = xdev->h2c_channel_max; - *c2h_channel_max = xdev->c2h_channel_max; - - xdma_device_flag_clear(xdev, XDEV_FLAG_OFFLINE); - return (void *)xdev; - -err_interrupts: - irq_teardown(xdev); -err_enable_msix: - disable_msi_msix(xdev, pdev); -err_engines: - remove_engines(xdev); -err_mask: - unmap_bars(xdev, pdev); -err_map: - if (xdev->got_regions) - pci_release_regions(pdev); -err_regions: - if (!xdev->regions_in_use) - pci_disable_device(pdev); -err_enable: - xdev_list_remove(xdev); - kfree(xdev); - return NULL; -} -EXPORT_SYMBOL_GPL(xdma_device_open); - -void xdma_device_close(struct pci_dev *pdev, void *dev_hndl) -{ - struct xdma_dev *xdev = (struct xdma_dev *)dev_hndl; - - dbg_init("pdev 0x%p, xdev 0x%p.\n", pdev, dev_hndl); - - if (!dev_hndl) - return; - - if (debug_check_dev_hndl(__func__, pdev, dev_hndl) < 0) - return; - - dbg_sg("remove(dev = 0x%p) where pdev->dev.driver_data = 0x%p\n", - pdev, xdev); - if (xdev->pdev != pdev) { - dbg_sg("pci_dev(0x%lx) != pdev(0x%lx)\n", - (unsigned long)xdev->pdev, (unsigned long)pdev); - } - - channel_interrupts_disable(xdev, ~0); - user_interrupts_disable(xdev, ~0); - read_interrupts(xdev); - - irq_teardown(xdev); - disable_msi_msix(xdev, pdev); - - remove_engines(xdev); - unmap_bars(xdev, pdev); - - if (xdev->got_regions) { - dbg_init("pci_release_regions 0x%p.\n", pdev); - pci_release_regions(pdev); - } - - if (!xdev->regions_in_use) { - dbg_init("pci_disable_device 0x%p.\n", pdev); - pci_disable_device(pdev); - } - - xdev_list_remove(xdev); - - kfree(xdev); -} -EXPORT_SYMBOL_GPL(xdma_device_close); - -void xdma_device_offline(struct pci_dev *pdev, void *dev_hndl) -{ - struct xdma_dev *xdev = (struct xdma_dev *)dev_hndl; - struct xdma_engine *engine; - int i; - - if (!dev_hndl) - return; - - if (debug_check_dev_hndl(__func__, pdev, dev_hndl) < 0) - return; - -pr_info("pdev 0x%p, xdev 0x%p.\n", pdev, xdev); - xdma_device_flag_set(xdev, XDEV_FLAG_OFFLINE); - - /* wait for all engines to be idle */ - for (i = 0; i < xdev->h2c_channel_max; i++) { - unsigned long flags; - - engine = &xdev->engine_h2c[i]; - - if (engine->magic == MAGIC_ENGINE) { - spin_lock_irqsave(&engine->lock, flags); - engine->shutdown |= ENGINE_SHUTDOWN_REQUEST; - - xdma_engine_stop(engine); - engine->running = 0; - spin_unlock_irqrestore(&engine->lock, flags); - } - } - - for (i = 0; i < xdev->c2h_channel_max; i++) { - unsigned long flags; - - engine = &xdev->engine_c2h[i]; - if (engine->magic == MAGIC_ENGINE) { - spin_lock_irqsave(&engine->lock, flags); - engine->shutdown |= ENGINE_SHUTDOWN_REQUEST; - - xdma_engine_stop(engine); - engine->running = 0; - spin_unlock_irqrestore(&engine->lock, flags); - } - } - - /* turn off interrupts */ - channel_interrupts_disable(xdev, ~0); - user_interrupts_disable(xdev, ~0); - read_interrupts(xdev); - irq_teardown(xdev); - - pr_info("xdev 0x%p, done.\n", xdev); -} -EXPORT_SYMBOL_GPL(xdma_device_offline); - -void xdma_device_online(struct pci_dev *pdev, void *dev_hndl) -{ - struct xdma_dev *xdev = (struct xdma_dev *)dev_hndl; - struct xdma_engine *engine; - unsigned long flags; - int i; - - if (!dev_hndl) - return; - - if (debug_check_dev_hndl(__func__, pdev, dev_hndl) < 0) - return; - -pr_info("pdev 0x%p, xdev 0x%p.\n", pdev, xdev); - - for (i = 0; i < xdev->h2c_channel_max; i++) { - engine = &xdev->engine_h2c[i]; - if (engine->magic == MAGIC_ENGINE) { - engine_init_regs(engine); - spin_lock_irqsave(&engine->lock, flags); - engine->shutdown &= ~ENGINE_SHUTDOWN_REQUEST; - spin_unlock_irqrestore(&engine->lock, flags); - } - } - - for (i = 0; i < xdev->c2h_channel_max; i++) { - engine = &xdev->engine_c2h[i]; - if (engine->magic == MAGIC_ENGINE) { - engine_init_regs(engine); - spin_lock_irqsave(&engine->lock, flags); - engine->shutdown &= ~ENGINE_SHUTDOWN_REQUEST; - spin_unlock_irqrestore(&engine->lock, flags); - } - } - - /* re-write the interrupt table */ - if (!poll_mode) { - irq_setup(xdev, pdev); - - channel_interrupts_enable(xdev, ~0); - user_interrupts_enable(xdev, xdev->mask_irq_user); - read_interrupts(xdev); - } - - xdma_device_flag_clear(xdev, XDEV_FLAG_OFFLINE); -pr_info("xdev 0x%p, done.\n", xdev); -} -EXPORT_SYMBOL_GPL(xdma_device_online); - -int xdma_device_restart(struct pci_dev *pdev, void *dev_hndl) -{ - struct xdma_dev *xdev = (struct xdma_dev *)dev_hndl; - - if (!dev_hndl) - return -EINVAL; - - if (debug_check_dev_hndl(__func__, pdev, dev_hndl) < 0) - return -EINVAL; - - pr_info("NOT implemented, 0x%p.\n", xdev); - return -EINVAL; -} -EXPORT_SYMBOL_GPL(xdma_device_restart); - -int xdma_user_isr_register(void *dev_hndl, unsigned int mask, - irq_handler_t handler, void *dev) -{ - struct xdma_dev *xdev = (struct xdma_dev *)dev_hndl; - int i; - - if (!dev_hndl) - return -EINVAL; - - if (debug_check_dev_hndl(__func__, xdev->pdev, dev_hndl) < 0) - return -EINVAL; - - for (i = 0; i < xdev->user_max && mask; i++) { - unsigned int bit = (1 << i); - - if ((bit & mask) == 0) - continue; - - mask &= ~bit; - xdev->user_irq[i].handler = handler; - xdev->user_irq[i].dev = dev; - } - - return 0; -} -EXPORT_SYMBOL_GPL(xdma_user_isr_register); - -int xdma_user_isr_enable(void *dev_hndl, unsigned int mask) -{ - struct xdma_dev *xdev = (struct xdma_dev *)dev_hndl; - - if (!dev_hndl) - return -EINVAL; - - if (debug_check_dev_hndl(__func__, xdev->pdev, dev_hndl) < 0) - return -EINVAL; - - xdev->mask_irq_user |= mask; - /* enable user interrupts */ - user_interrupts_enable(xdev, mask); - read_interrupts(xdev); - - return 0; -} -EXPORT_SYMBOL_GPL(xdma_user_isr_enable); - -int xdma_user_isr_disable(void *dev_hndl, unsigned int mask) -{ - struct xdma_dev *xdev = (struct xdma_dev *)dev_hndl; - - if (!dev_hndl) - return -EINVAL; - - if (debug_check_dev_hndl(__func__, xdev->pdev, dev_hndl) < 0) - return -EINVAL; - - xdev->mask_irq_user &= ~mask; - user_interrupts_disable(xdev, mask); - read_interrupts(xdev); - - return 0; -} -EXPORT_SYMBOL_GPL(xdma_user_isr_disable); - -#ifdef __LIBXDMA_MOD__ -static int __init xdma_base_init(void) -{ - printk(KERN_INFO "%s", version); - return 0; -} - -static void __exit xdma_base_exit(void) -{ - return; -} - -module_init(xdma_base_init); -module_exit(xdma_base_exit); -#endif -/* makes an existing transfer cyclic */ -static void xdma_transfer_cyclic(struct xdma_transfer *transfer) -{ - /* link last descriptor to first descriptor */ - xdma_desc_link(transfer->desc_virt + transfer->desc_num - 1, - transfer->desc_virt, transfer->desc_bus); - /* remember transfer is cyclic */ - transfer->cyclic = 1; -} - -static int transfer_monitor_cyclic(struct xdma_engine *engine, - struct xdma_transfer *transfer, int timeout_ms) -{ - struct xdma_result *result; - int rc = 0; - - BUG_ON(!engine); - BUG_ON(!transfer); - - result = engine->cyclic_result; - BUG_ON(!result); - - if (poll_mode) { - int i ; - for (i = 0; i < 5; i++) { - rc = engine_service_poll(engine, 0); - if (rc) { - pr_info("%s service_poll failed %d.\n", - engine->name, rc); - rc = -ERESTARTSYS; - } - if (result[engine->rx_head].status) - return 0; - } - } else { - if (enable_credit_mp){ - dbg_tfr("%s: rx_head=%d,rx_tail=%d, wait ...\n", - engine->name, engine->rx_head, engine->rx_tail); - rc = wait_event_interruptible_timeout( transfer->wq, - (engine->rx_head!=engine->rx_tail || - engine->rx_overrun), - msecs_to_jiffies(timeout_ms)); - dbg_tfr("%s: wait returns %d, rx %d/%d, overrun %d.\n", - engine->name, rc, engine->rx_head, - engine->rx_tail, engine->rx_overrun); - } else { - rc = wait_event_interruptible_timeout( transfer->wq, - engine->eop_found, - msecs_to_jiffies(timeout_ms)); - dbg_tfr("%s: wait returns %d, eop_found %d.\n", - engine->name, rc, engine->eop_found); - } - } - - return 0; -} - -struct scatterlist *sglist_index(struct sg_table *sgt, unsigned int idx) -{ - struct scatterlist *sg = sgt->sgl; - int i; - - if (idx >= sgt->orig_nents) - return NULL; - - if (!idx) - return sg; - - for (i = 0; i < idx; i++, sg = sg_next(sg)) - ; - - return sg; -} - -static int copy_cyclic_to_user(struct xdma_engine *engine, int pkt_length, - int head, char __user *buf, size_t count) -{ - struct scatterlist *sg; - int more = pkt_length; - - BUG_ON(!engine); - BUG_ON(!buf); - - dbg_tfr("%s, pkt_len %d, head %d, user buf idx %u.\n", - engine->name, pkt_length, head, engine->user_buffer_index); - - sg = sglist_index(&engine->cyclic_sgt, head); - if (!sg) { - pr_info("%s, head %d OOR, sgl %u.\n", - engine->name, head, engine->cyclic_sgt.orig_nents); - return -EIO; - } - - /* EOP found? Transfer anything from head to EOP */ - while (more) { - unsigned int copy = more > PAGE_SIZE ? PAGE_SIZE : more; - unsigned int blen = count - engine->user_buffer_index; - int rv; - - if (copy > blen) - copy = blen; - - dbg_tfr("%s sg %d, 0x%p, copy %u to user %u.\n", - engine->name, head, sg, copy, - engine->user_buffer_index); - - rv = copy_to_user(&buf[engine->user_buffer_index], - page_address(sg_page(sg)), copy); - if (rv) { - pr_info("%s copy_to_user %u failed %d\n", - engine->name, copy, rv); - return -EIO; - } - - more -= copy; - engine->user_buffer_index += copy; - - if (engine->user_buffer_index == count) { - /* user buffer used up */ - break; - } - - head++; - if (head >= CYCLIC_RX_PAGES_MAX) { - head = 0; - sg = engine->cyclic_sgt.sgl; - } else - sg = sg_next(sg); - } - - return pkt_length; -} - -static int complete_cyclic(struct xdma_engine *engine, char __user *buf, - size_t count) -{ - struct xdma_result *result; - int pkt_length = 0; - int fault = 0; - int eop = 0; - int head; - int rc = 0; - int num_credit = 0; - unsigned long flags; - - BUG_ON(!engine); - result = engine->cyclic_result; - BUG_ON(!result); - - spin_lock_irqsave(&engine->lock, flags); - - /* where the host currently is in the ring buffer */ - head = engine->rx_head; - - /* iterate over newly received results */ - while (engine->rx_head != engine->rx_tail||engine->rx_overrun) { - - WARN_ON(result[engine->rx_head].status==0); - - dbg_tfr("%s, result[%d].status = 0x%x length = 0x%x.\n", - engine->name, engine->rx_head, - result[engine->rx_head].status, - result[engine->rx_head].length); - - if ((result[engine->rx_head].status >> 16) != C2H_WB) { - pr_info("%s, result[%d].status 0x%x, no magic.\n", - engine->name, engine->rx_head, - result[engine->rx_head].status); - fault = 1; - } else if (result[engine->rx_head].length > PAGE_SIZE) { - pr_info("%s, result[%d].len 0x%x, > PAGE_SIZE 0x%lx.\n", - engine->name, engine->rx_head, - result[engine->rx_head].length, PAGE_SIZE); - fault = 1; - } else if (result[engine->rx_head].length == 0) { - pr_info("%s, result[%d].length 0x%x.\n", - engine->name, engine->rx_head, - result[engine->rx_head].length); - fault = 1; - /* valid result */ - } else { - pkt_length += result[engine->rx_head].length; - num_credit++; - /* seen eop? */ - //if (result[engine->rx_head].status & RX_STATUS_EOP) - if (result[engine->rx_head].status & RX_STATUS_EOP){ - eop = 1; - engine->eop_found = 1; - } - - dbg_tfr("%s, pkt_length=%d (%s)\n", - engine->name, pkt_length, - eop ? "with EOP" : "no EOP yet"); - } - /* clear result */ - result[engine->rx_head].status = 0; - result[engine->rx_head].length = 0; - /* proceed head pointer so we make progress, even when fault */ - engine->rx_head = (engine->rx_head + 1) % CYCLIC_RX_PAGES_MAX; - - /* stop processing if a fault/eop was detected */ - if (fault || eop){ - break; - } - } - - spin_unlock_irqrestore(&engine->lock, flags); - - if (fault) - return -EIO; - - rc = copy_cyclic_to_user(engine, pkt_length, head, buf, count); - engine->rx_overrun = 0; - /* if copy is successful, release credits */ - if(rc > 0) - write_register(num_credit,&engine->sgdma_regs->credits, 0); - - return rc; -} - -ssize_t xdma_engine_read_cyclic(struct xdma_engine *engine, char __user *buf, - size_t count, int timeout_ms) -{ - int i = 0; - int rc = 0; - int rc_len = 0; - struct xdma_transfer *transfer; - - BUG_ON(!engine); - BUG_ON(engine->magic != MAGIC_ENGINE); - - transfer = &engine->cyclic_req->xfer; - BUG_ON(!transfer); - - engine->user_buffer_index = 0; - - do { - rc = transfer_monitor_cyclic(engine, transfer, timeout_ms); - if (rc < 0) - return rc; - rc = complete_cyclic(engine, buf, count); - if (rc < 0) - return rc; - rc_len += rc; - - i++; - if (i > 10) - break; - } while (!engine->eop_found); - - if(enable_credit_mp) - engine->eop_found = 0; - - return rc_len; -} - -static void sgt_free_with_pages(struct sg_table *sgt, int dir, - struct pci_dev *pdev) -{ - struct scatterlist *sg = sgt->sgl; - int npages = sgt->orig_nents; - int i; - - for (i = 0; i < npages; i++, sg = sg_next(sg)) { - struct page *pg = sg_page(sg); - dma_addr_t bus = sg_dma_address(sg); - - if (pg) { - if (pdev) - pci_unmap_page(pdev, bus, PAGE_SIZE, dir); - __free_page(pg); - } else - break; - } - sg_free_table(sgt); - memset(sgt, 0, sizeof(struct sg_table)); -} - -static int sgt_alloc_with_pages(struct sg_table *sgt, unsigned int npages, - int dir, struct pci_dev *pdev) -{ - struct scatterlist *sg; - int i; - - if (sg_alloc_table(sgt, npages, GFP_KERNEL)) { - pr_info("sgt OOM.\n"); - return -ENOMEM; - } - - sg = sgt->sgl; - for (i = 0; i < npages; i++, sg = sg_next(sg)) { - struct page *pg = alloc_page(GFP_KERNEL); - - if (!pg) { - pr_info("%d/%u, page OOM.\n", i, npages); - goto err_out; - } - - if (pdev) { - dma_addr_t bus = pci_map_page(pdev, pg, 0, PAGE_SIZE, - dir); - if (unlikely(pci_dma_mapping_error(pdev, bus))) { - pr_info("%d/%u, page 0x%p map err.\n", - i, npages, pg); - __free_page(pg); - goto err_out; - } - sg_dma_address(sg) = bus; - sg_dma_len(sg) = PAGE_SIZE; - } - sg_set_page(sg, pg, PAGE_SIZE, 0); - } - - sgt->orig_nents = sgt->nents = npages; - - return 0; - -err_out: - sgt_free_with_pages(sgt, dir, pdev); - return -ENOMEM; -} - -int xdma_cyclic_transfer_setup(struct xdma_engine *engine) -{ - struct xdma_dev *xdev; - struct xdma_transfer *xfer; - dma_addr_t bus; - unsigned long flags; - int i; - int rc; - - BUG_ON(!engine); - xdev = engine->xdev; - BUG_ON(!xdev); - - if (engine->cyclic_req) { - pr_info("%s: exclusive access already taken.\n", - engine->name); - return -EBUSY; - } - - spin_lock_irqsave(&engine->lock, flags); - - engine->rx_tail = 0; - engine->rx_head = 0; - engine->rx_overrun = 0; - engine->eop_found = 0; - - rc = sgt_alloc_with_pages(&engine->cyclic_sgt, CYCLIC_RX_PAGES_MAX, - engine->dir, xdev->pdev); - if (rc < 0) { - pr_info("%s cyclic pages %u OOM.\n", - engine->name, CYCLIC_RX_PAGES_MAX); - goto err_out; - } - - engine->cyclic_req = xdma_init_request(&engine->cyclic_sgt, 0); - if (!engine->cyclic_req) { - pr_info("%s cyclic request OOM.\n", engine->name); - rc = -ENOMEM; - goto err_out; - } - -#ifdef __LIBXDMA_DEBUG__ - xdma_request_cb_dump(engine->cyclic_req); -#endif - - rc = transfer_init(engine, engine->cyclic_req); - if (rc < 0) - goto err_out; - - xfer = &engine->cyclic_req->xfer; - - /* replace source addresses with result write-back addresses */ - memset(engine->cyclic_result, 0, - CYCLIC_RX_PAGES_MAX * sizeof(struct xdma_result)); - bus = engine->cyclic_result_bus; - for (i = 0; i < xfer->desc_num; i++) { - xfer->desc_virt[i].src_addr_lo = cpu_to_le32(PCI_DMA_L(bus)); - xfer->desc_virt[i].src_addr_hi = cpu_to_le32(PCI_DMA_H(bus)); - bus += sizeof(struct xdma_result); - } - /* set control of all descriptors */ - for (i = 0; i < xfer->desc_num; i++) { - xdma_desc_control_clear(xfer->desc_virt + i, LS_BYTE_MASK); - xdma_desc_control_set(xfer->desc_virt + i, - XDMA_DESC_EOP | XDMA_DESC_COMPLETED); - } - - /* make this a cyclic transfer */ - xdma_transfer_cyclic(xfer); - -#ifdef __LIBXDMA_DEBUG__ - transfer_dump(xfer); -#endif - - if(enable_credit_mp){ - //write_register(RX_BUF_PAGES,&engine->sgdma_regs->credits); - write_register(128, &engine->sgdma_regs->credits, 0); - } - - spin_unlock_irqrestore(&engine->lock, flags); - - /* start cyclic transfer */ - transfer_queue(engine, xfer); - - return 0; - - /* unwind on errors */ -err_out: - if (engine->cyclic_req) { - xdma_request_free(engine->cyclic_req); - engine->cyclic_req = NULL; - } - - if (engine->cyclic_sgt.orig_nents) { - sgt_free_with_pages(&engine->cyclic_sgt, engine->dir, - xdev->pdev); - engine->cyclic_sgt.orig_nents = 0; - engine->cyclic_sgt.nents = 0; - engine->cyclic_sgt.sgl = NULL; - } - - spin_unlock_irqrestore(&engine->lock, flags); - - return rc; -} - - -static int cyclic_shutdown_polled(struct xdma_engine *engine) -{ - BUG_ON(!engine); - - spin_lock(&engine->lock); - - dbg_tfr("Polling for shutdown completion\n"); - do { - engine_status_read(engine, 1, 0); - schedule(); - } while (engine->status & XDMA_STAT_BUSY); - - if ((engine->running) && !(engine->status & XDMA_STAT_BUSY)) { - dbg_tfr("Engine has stopped\n"); - - if (!list_empty(&engine->transfer_list)) - engine_transfer_dequeue(engine); - - engine_service_shutdown(engine); - } - - dbg_tfr("Shutdown completion polling done\n"); - spin_unlock(&engine->lock); - - return 0; -} - -static int cyclic_shutdown_interrupt(struct xdma_engine *engine) -{ - int rc; - - BUG_ON(!engine); - - rc = wait_event_interruptible_timeout(engine->shutdown_wq, - !engine->running, msecs_to_jiffies(10000)); - -#if 0 - if (rc) { - dbg_tfr("wait_event_interruptible=%d\n", rc); - return rc; - } -#endif - - if (engine->running) { - pr_info("%s still running?!, %d\n", engine->name, rc); - return -EINVAL; - } - - return rc; -} - -int xdma_cyclic_transfer_teardown(struct xdma_engine *engine) -{ - int rc; - struct xdma_dev *xdev = engine->xdev; - struct xdma_transfer *transfer; - unsigned long flags; - - transfer = engine_cyclic_stop(engine); - - spin_lock_irqsave(&engine->lock, flags); - if (transfer) { - dbg_tfr("%s: stop transfer 0x%p.\n", engine->name, transfer); - if (transfer != &engine->cyclic_req->xfer) { - pr_info("%s unexpected transfer 0x%p/0x%p\n", - engine->name, transfer, - &engine->cyclic_req->xfer); - } - } - /* allow engine to be serviced after stop request */ - spin_unlock_irqrestore(&engine->lock, flags); - - /* wait for engine to be no longer running */ - if (poll_mode) - rc = cyclic_shutdown_polled(engine); - else - rc = cyclic_shutdown_interrupt(engine); - - /* obtain spin lock to atomically remove resources */ - spin_lock_irqsave(&engine->lock, flags); - - if (engine->cyclic_req) { - xdma_request_free(engine->cyclic_req); - engine->cyclic_req = NULL; - } - - if (engine->cyclic_sgt.orig_nents) { - sgt_free_with_pages(&engine->cyclic_sgt, engine->dir, - xdev->pdev); - engine->cyclic_sgt.orig_nents = 0; - engine->cyclic_sgt.nents = 0; - engine->cyclic_sgt.sgl = NULL; - } - - spin_unlock_irqrestore(&engine->lock, flags); - - return 0; -} - -// 67d7842dbbe25473c3c32b93c0da8047785f30d78e8a024de1b57352245f9689 diff --git a/sdk/linux_kernel_drivers/xocl/libxdma.h b/sdk/linux_kernel_drivers/xocl/libxdma.h deleted file mode 100644 index d7620827..00000000 --- a/sdk/linux_kernel_drivers/xocl/libxdma.h +++ /dev/null @@ -1,612 +0,0 @@ -/******************************************************************************* - * - * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - * - * The full GNU General Public License is included in this distribution in - * the file called "LICENSE". - * - * Karen Xie - * - ******************************************************************************/ -#ifndef XDMA_LIB_H -#define XDMA_LIB_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Switch debug printing on/off */ -#define XDMA_DEBUG 0 - -/* SECTION: Preprocessor macros/constants */ -#define XDMA_BAR_NUM (6) - -/* maximum amount of register space to map */ -#define XDMA_BAR_SIZE (0x8000UL) - -/* Use this definition to poll several times between calls to schedule */ -#define NUM_POLLS_PER_SCHED 100 - -#define XDMA_CHANNEL_NUM_MAX (4) -/* - * interrupts per engine, rad2_vul.sv:237 - * .REG_IRQ_OUT (reg_irq_from_ch[(channel*2) +: 2]), - */ -#define XDMA_ENG_IRQ_NUM (1) -#define MAX_EXTRA_ADJ (15) -#define RX_STATUS_EOP (1) - -/* Target internal components on XDMA control BAR */ -#define XDMA_OFS_INT_CTRL (0x2000UL) -#define XDMA_OFS_CONFIG (0x3000UL) - -/* maximum number of desc per transfer request */ -#define XDMA_TRANSFER_MAX_DESC (2048) - -/* maximum size of a single DMA transfer descriptor */ -#define XDMA_DESC_BLEN_BITS 28 -#define XDMA_DESC_BLEN_MAX ((1 << (XDMA_DESC_BLEN_BITS)) - 1) - -/* bits of the SG DMA control register */ -#define XDMA_CTRL_RUN_STOP (1UL << 0) -#define XDMA_CTRL_IE_DESC_STOPPED (1UL << 1) -#define XDMA_CTRL_IE_DESC_COMPLETED (1UL << 2) -#define XDMA_CTRL_IE_DESC_ALIGN_MISMATCH (1UL << 3) -#define XDMA_CTRL_IE_MAGIC_STOPPED (1UL << 4) -#define XDMA_CTRL_IE_IDLE_STOPPED (1UL << 6) -#define XDMA_CTRL_IE_READ_ERROR (0x1FUL << 9) -#define XDMA_CTRL_IE_DESC_ERROR (0x1FUL << 19) -#define XDMA_CTRL_NON_INCR_ADDR (1UL << 25) -#define XDMA_CTRL_POLL_MODE_WB (1UL << 26) - -/* bits of the SG DMA status register */ -#define XDMA_STAT_BUSY (1UL << 0) -#define XDMA_STAT_DESC_STOPPED (1UL << 1) -#define XDMA_STAT_DESC_COMPLETED (1UL << 2) -#define XDMA_STAT_ALIGN_MISMATCH (1UL << 3) -#define XDMA_STAT_MAGIC_STOPPED (1UL << 4) -#define XDMA_STAT_INVALID_LEN (1UL << 5) -#define XDMA_STAT_IDLE_STOPPED (1UL << 6) - -#define XDMA_STAT_COMMON_ERR_MASK \ - (XDMA_STAT_ALIGN_MISMATCH | XDMA_STAT_MAGIC_STOPPED | \ - XDMA_STAT_INVALID_LEN) - -/* desc_error, C2H & H2C */ -#define XDMA_STAT_DESC_UNSUPP_REQ (1UL << 19) -#define XDMA_STAT_DESC_COMPL_ABORT (1UL << 20) -#define XDMA_STAT_DESC_PARITY_ERR (1UL << 21) -#define XDMA_STAT_DESC_HEADER_EP (1UL << 22) -#define XDMA_STAT_DESC_UNEXP_COMPL (1UL << 23) - -#define XDMA_STAT_DESC_ERR_MASK \ - (XDMA_STAT_DESC_UNSUPP_REQ | XDMA_STAT_DESC_COMPL_ABORT | \ - XDMA_STAT_DESC_PARITY_ERR | XDMA_STAT_DESC_HEADER_EP | \ - XDMA_STAT_DESC_UNEXP_COMPL) - -/* read error: H2C */ -#define XDMA_STAT_H2C_R_UNSUPP_REQ (1UL << 9) -#define XDMA_STAT_H2C_R_COMPL_ABORT (1UL << 10) -#define XDMA_STAT_H2C_R_PARITY_ERR (1UL << 11) -#define XDMA_STAT_H2C_R_HEADER_EP (1UL << 12) -#define XDMA_STAT_H2C_R_UNEXP_COMPL (1UL << 13) - -#define XDMA_STAT_H2C_R_ERR_MASK \ - (XDMA_STAT_H2C_R_UNSUPP_REQ | XDMA_STAT_H2C_R_COMPL_ABORT | \ - XDMA_STAT_H2C_R_PARITY_ERR | XDMA_STAT_H2C_R_HEADER_EP | \ - XDMA_STAT_H2C_R_UNEXP_COMPL) - -/* write error, H2C only */ -#define XDMA_STAT_H2C_W_DECODE_ERR (1UL << 14) -#define XDMA_STAT_H2C_W_SLAVE_ERR (1UL << 15) - -#define XDMA_STAT_H2C_W_ERR_MASK \ - (XDMA_STAT_H2C_W_DECODE_ERR | XDMA_STAT_H2C_W_SLAVE_ERR) - -/* read error: C2H */ -#define XDMA_STAT_C2H_R_DECODE_ERR (1UL << 9) -#define XDMA_STAT_C2H_R_SLAVE_ERR (1UL << 10) - -#define XDMA_STAT_C2H_R_ERR_MASK \ - (XDMA_STAT_C2H_R_DECODE_ERR | XDMA_STAT_C2H_R_SLAVE_ERR) - -/* all combined */ -#define XDMA_STAT_H2C_ERR_MASK \ - (XDMA_STAT_COMMON_ERR_MASK | XDMA_STAT_DESC_ERR_MASK | \ - XDMA_STAT_H2C_R_ERR_MASK | XDMA_STAT_H2C_W_ERR_MASK) - -#define XDMA_STAT_C2H_ERR_MASK \ - (XDMA_STAT_COMMON_ERR_MASK | XDMA_STAT_DESC_ERR_MASK | \ - XDMA_STAT_C2H_R_ERR_MASK) - -/* bits of the SGDMA descriptor control field */ -#define XDMA_DESC_STOPPED (1UL << 0) -#define XDMA_DESC_COMPLETED (1UL << 1) -#define XDMA_DESC_EOP (1UL << 4) - -#define XDMA_PERF_RUN (1UL << 0) -#define XDMA_PERF_CLEAR (1UL << 1) -#define XDMA_PERF_AUTO (1UL << 2) - -#define MAGIC_ENGINE 0xEEEEEEEEUL -#define MAGIC_DEVICE 0xDDDDDDDDUL - -/* upper 16-bits of engine identifier register */ -#define XDMA_ID_H2C 0x1fc0U -#define XDMA_ID_C2H 0x1fc1U - -/* for C2H AXI-ST mode */ -#define CYCLIC_RX_PAGES_MAX 256 - -#define LS_BYTE_MASK 0x000000FFUL - -#define BLOCK_ID_MASK 0xFFF00000 -#define BLOCK_ID_HEAD 0x1FC00000 - -#define IRQ_BLOCK_ID 0x1fc20000UL -#define CONFIG_BLOCK_ID 0x1fc30000UL - -#define WB_COUNT_MASK 0x00ffffffUL -#define WB_ERR_MASK (1UL << 31) -#define POLL_TIMEOUT_SECONDS 10 - -#define MAX_USER_IRQ 16 - -#define MAX_DESC_BUS_ADDR (0xffffffffULL) - -#define DESC_MAGIC 0xAD4B0000UL - -#define C2H_WB 0x52B4UL - -#define MAX_NUM_ENGINES (XDMA_CHANNEL_NUM_MAX * 2) -#define H2C_CHANNEL_OFFSET 0x1000 -#define SGDMA_OFFSET_FROM_CHANNEL 0x4000 -#define CHANNEL_SPACING 0x100 -#define TARGET_SPACING 0x1000 - -#define BYPASS_MODE_SPACING 0x0100 - -/* obtain the 32 most significant (high) bits of a 32-bit or 64-bit address */ -#define PCI_DMA_H(addr) ((addr >> 16) >> 16) -/* obtain the 32 least significant (low) bits of a 32-bit or 64-bit address */ -#define PCI_DMA_L(addr) (addr & 0xffffffffUL) - -#ifndef VM_RESERVED - #define VMEM_FLAGS (VM_IO | VM_DONTEXPAND | VM_DONTDUMP) -#else - #define VMEM_FLAGS (VM_IO | VM_RESERVED) -#endif - -#ifdef __LIBXDMA_DEBUG__ -#define dbg_io pr_err -#define dbg_fops pr_err -#define dbg_perf pr_err -#define dbg_sg pr_err -#define dbg_tfr pr_err -#define dbg_irq pr_err -#define dbg_init pr_err -#define dbg_desc pr_err -#else -/* disable debugging */ -#define dbg_io(...) -#define dbg_fops(...) -#define dbg_perf(...) -#define dbg_sg(...) -#define dbg_tfr(...) -#define dbg_irq(...) -#define dbg_init(...) -#define dbg_desc(...) -#endif - -/* SECTION: Enum definitions */ -enum transfer_state { - TRANSFER_STATE_NEW = 0, - TRANSFER_STATE_SUBMITTED, - TRANSFER_STATE_COMPLETED, - TRANSFER_STATE_FAILED, - TRANSFER_STATE_ABORTED -}; - -enum shutdown_state { - ENGINE_SHUTDOWN_NONE = 0, /* No shutdown in progress */ - ENGINE_SHUTDOWN_REQUEST = 1, /* engine requested to shutdown */ - ENGINE_SHUTDOWN_IDLE = 2 /* engine has shutdown and is idle */ -}; - -enum dev_capabilities { - CAP_64BIT_DMA = 2, - CAP_64BIT_DESC = 4, - CAP_ENGINE_WRITE = 8, - CAP_ENGINE_READ = 16 -}; - -/* SECTION: Structure definitions */ - -struct config_regs { - u32 identifier; - u32 reserved_1[4]; - u32 msi_enable; -}; - -/** - * SG DMA Controller status and control registers - * - * These registers make the control interface for DMA transfers. - * - * It sits in End Point (FPGA) memory BAR[0] for 32-bit or BAR[0:1] for 64-bit. - * It references the first descriptor which exists in Root Complex (PC) memory. - * - * @note The registers must be accessed using 32-bit (PCI DWORD) read/writes, - * and their values are in little-endian byte ordering. - */ -struct engine_regs { - u32 identifier; - u32 control; - u32 control_w1s; - u32 control_w1c; - u32 reserved_1[12]; /* padding */ - - u32 status; - u32 status_rc; - u32 completed_desc_count; - u32 alignments; - u32 reserved_2[14]; /* padding */ - - u32 poll_mode_wb_lo; - u32 poll_mode_wb_hi; - u32 interrupt_enable_mask; - u32 interrupt_enable_mask_w1s; - u32 interrupt_enable_mask_w1c; - u32 reserved_3[9]; /* padding */ - - u32 perf_ctrl; - u32 perf_cyc_lo; - u32 perf_cyc_hi; - u32 perf_dat_lo; - u32 perf_dat_hi; - u32 perf_pnd_lo; - u32 perf_pnd_hi; -} __packed; - -struct engine_sgdma_regs { - u32 identifier; - u32 reserved_1[31]; /* padding */ - - /* bus address to first descriptor in Root Complex Memory */ - u32 first_desc_lo; - u32 first_desc_hi; - /* number of adjacent descriptors at first_desc */ - u32 first_desc_adjacent; - u32 credits; -} __packed; - -struct msix_vec_table_entry { - u32 msi_vec_addr_lo; - u32 msi_vec_addr_hi; - u32 msi_vec_data_lo; - u32 msi_vec_data_hi; -} __packed; - -struct msix_vec_table { - struct msix_vec_table_entry entry_list[32]; -} __packed; - -struct interrupt_regs { - u32 identifier; - u32 user_int_enable; - u32 user_int_enable_w1s; - u32 user_int_enable_w1c; - u32 channel_int_enable; - u32 channel_int_enable_w1s; - u32 channel_int_enable_w1c; - u32 reserved_1[9]; /* padding */ - - u32 user_int_request; - u32 channel_int_request; - u32 user_int_pending; - u32 channel_int_pending; - u32 reserved_2[12]; /* padding */ - - u32 user_msi_vector[8]; - u32 channel_msi_vector[8]; -} __packed; - -struct sgdma_common_regs { - u32 padding[8]; - u32 credit_mode_enable; - u32 credit_mode_enable_w1s; - u32 credit_mode_enable_w1c; -} __packed; - - -/* Structure for polled mode descriptor writeback */ -struct xdma_poll_wb { - u32 completed_desc_count; - u32 reserved_1[7]; -} __packed; - - -/** - * Descriptor for a single contiguous memory block transfer. - * - * Multiple descriptors are linked by means of the next pointer. An additional - * extra adjacent number gives the amount of extra contiguous descriptors. - * - * The descriptors are in root complex memory, and the bytes in the 32-bit - * words must be in little-endian byte ordering. - */ -struct xdma_desc { - u32 control; - u32 bytes; /* transfer length in bytes */ - u32 src_addr_lo; /* source address (low 32-bit) */ - u32 src_addr_hi; /* source address (high 32-bit) */ - u32 dst_addr_lo; /* destination address (low 32-bit) */ - u32 dst_addr_hi; /* destination address (high 32-bit) */ - /* - * next descriptor in the single-linked list of descriptors; - * this is the PCIe (bus) address of the next descriptor in the - * root complex memory - */ - u32 next_lo; /* next desc address (low 32-bit) */ - u32 next_hi; /* next desc address (high 32-bit) */ -} __packed; - -/* 32 bytes (four 32-bit words) or 64 bytes (eight 32-bit words) */ -struct xdma_result { - u32 status; - u32 length; - u32 reserved_1[6]; /* padding */ -} __packed; - -struct sw_desc { - dma_addr_t addr; - unsigned int len; -}; - -/* Describes a (SG DMA) single transfer for the engine */ -struct xdma_transfer { - struct list_head entry; /* queue of non-completed transfers */ - struct xdma_desc *desc_virt; /* virt addr of the 1st descriptor */ - dma_addr_t desc_bus; /* bus addr of the first descriptor */ - int desc_adjacent; /* adjacent descriptors at desc_bus */ - int desc_num; /* number of descriptors in transfer */ - enum dma_data_direction dir; - wait_queue_head_t wq; /* wait queue for transfer completion */ - - enum transfer_state state; /* state of the transfer */ - unsigned int flags; -#define XFER_FLAG_NEED_UNMAP 0x1 - int cyclic; /* flag if transfer is cyclic */ - int last_in_request; /* flag if last within request */ - unsigned int len; - struct sg_table *sgt; -}; - -struct xdma_request_cb { - struct sg_table *sgt; - unsigned int total_len; - u64 ep_addr; - - struct xdma_transfer xfer; - - unsigned int sw_desc_idx; - unsigned int sw_desc_cnt; - struct sw_desc sdesc[0]; -}; - -struct xdma_engine { - unsigned long magic; /* structure ID for sanity checks */ - struct xdma_dev *xdev; /* parent device */ - char name[5]; /* name of this engine */ - int version; /* version of this engine */ - //dev_t cdevno; /* character device major:minor */ - //struct cdev cdev; /* character device (embedded struct) */ - - /* HW register address offsets */ - struct engine_regs *regs; /* Control reg BAR offset */ - struct engine_sgdma_regs *sgdma_regs; /* SGDAM reg BAR offset */ - u32 bypass_offset; /* Bypass mode BAR offset */ - - /* Engine state, configuration and flags */ - enum shutdown_state shutdown; /* engine shutdown mode */ - enum dma_data_direction dir; - int running; /* flag if the driver started engine */ - int non_incr_addr; /* flag if non-incremental addressing used */ - int streaming; - int addr_align; /* source/dest alignment in bytes */ - int len_granularity; /* transfer length multiple */ - int addr_bits; /* HW datapath address width */ - int channel; /* engine indices */ - int max_extra_adj; /* descriptor prefetch capability */ - int desc_dequeued; /* num descriptors of completed transfers */ - u32 status; /* last known status of device */ - u32 interrupt_enable_mask_value;/* only used for MSIX mode to store per-engine interrupt mask value */ - - /* Transfer list management */ - struct list_head transfer_list; /* queue of transfers */ - - /* Members applicable to AXI-ST C2H (cyclic) transfers */ - struct xdma_result *cyclic_result; - dma_addr_t cyclic_result_bus; /* bus addr for transfer */ - struct xdma_request_cb *cyclic_req; - struct sg_table cyclic_sgt; - u8 eop_found; /* used only for cyclic(rx:c2h) */ - - int rx_tail; /* follows the HW */ - int rx_head; /* where the SW reads from */ - int rx_overrun; /* flag if overrun occured */ - - /* for copy from cyclic buffer to user buffer */ - unsigned int user_buffer_index; - - /* Members associated with polled mode support */ - u8 *poll_mode_addr_virt; /* virt addr for descriptor writeback */ - dma_addr_t poll_mode_bus; /* bus addr for descriptor writeback */ - - /* Members associated with interrupt mode support */ - wait_queue_head_t shutdown_wq; /* wait queue for shutdown sync */ - spinlock_t lock; /* protects concurrent access */ - int prev_cpu; /* remember CPU# of (last) locker */ - int msix_irq_line; /* MSI-X vector for this engine */ - u32 irq_bitmask; /* IRQ bit mask for this engine */ - struct work_struct work; /* Work queue for interrupt handling */ - - spinlock_t desc_lock; /* protects concurrent access */ - dma_addr_t desc_bus; - struct xdma_desc *desc; - - /* for performance test support */ - struct xdma_performance_ioctl *xdma_perf; /* perf test control */ - wait_queue_head_t xdma_perf_wq; /* Perf test sync */ -}; - -struct xdma_user_irq { - struct xdma_dev *xdev; /* parent device */ - u8 user_idx; /* 0 ~ 15 */ - u8 events_irq; /* accumulated IRQs */ - spinlock_t events_lock; /* lock to safely update events_irq */ - wait_queue_head_t events_wq; /* wait queue to sync waiting threads */ - irq_handler_t handler; - - void *dev; -}; - -/* XDMA PCIe device specific book-keeping */ -#define XDEV_FLAG_OFFLINE 0x1 -struct xdma_dev { - struct list_head list_head; - struct list_head rcu_node; - - unsigned long magic; /* structure ID for sanity checks */ - struct pci_dev *pdev; /* pci device struct from probe() */ - int idx; /* dev index */ - - const char *mod_name; /* name of module owning the dev */ - - spinlock_t lock; /* protects concurrent access */ - unsigned int flags; - - /* PCIe BAR management */ - void *__iomem bar[XDMA_BAR_NUM]; /* addresses for mapped BARs */ - int user_bar_idx; /* BAR index of user logic */ - int config_bar_idx; /* BAR index of XDMA config logic */ - int bypass_bar_idx; /* BAR index of XDMA bypass logic */ - int regions_in_use; /* flag if dev was in use during probe() */ - int got_regions; /* flag if probe() obtained the regions */ - - int user_max; - int c2h_channel_max; - int h2c_channel_max; - - /* Interrupt management */ - int irq_count; /* interrupt counter */ - int irq_line; /* flag if irq allocated successfully */ - int msi_enabled; /* flag if msi was enabled for the device */ - int msix_enabled; /* flag if msi-x was enabled for the device */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0) - struct msix_entry entry[32]; /* msi-x vector/entry table */ -#endif - struct xdma_user_irq user_irq[16]; /* user IRQ management */ - unsigned int mask_irq_user; - - /* XDMA engine management */ - int engines_num; /* Total engine count */ - u32 mask_irq_h2c; - u32 mask_irq_c2h; - struct xdma_engine engine_h2c[XDMA_CHANNEL_NUM_MAX]; - struct xdma_engine engine_c2h[XDMA_CHANNEL_NUM_MAX]; - - /* SD_Accel specific */ - enum dev_capabilities capabilities; - u64 feature_id; -}; - -static inline int xdma_device_flag_check(struct xdma_dev *xdev, unsigned int f) -{ - unsigned long flags; - - spin_lock_irqsave(&xdev->lock, flags); - if (xdev->flags & f) { - spin_unlock_irqrestore(&xdev->lock, flags); - return 1; - } - spin_unlock_irqrestore(&xdev->lock, flags); - return 0; -} - -static inline int xdma_device_flag_test_n_set(struct xdma_dev *xdev, - unsigned int f) -{ - unsigned long flags; - int rv = 0; - - spin_lock_irqsave(&xdev->lock, flags); - if (xdev->flags & f) { - spin_unlock_irqrestore(&xdev->lock, flags); - rv = 1; - } else - xdev->flags |= f; - spin_unlock_irqrestore(&xdev->lock, flags); - return rv; -} - -static inline void xdma_device_flag_set(struct xdma_dev *xdev, unsigned int f) -{ - unsigned long flags; - - spin_lock_irqsave(&xdev->lock, flags); - xdev->flags |= f; - spin_unlock_irqrestore(&xdev->lock, flags); -} - -static inline void xdma_device_flag_clear(struct xdma_dev *xdev, unsigned int f) -{ - unsigned long flags; - - spin_lock_irqsave(&xdev->lock, flags); - xdev->flags &= ~f; - spin_unlock_irqrestore(&xdev->lock, flags); -} - -void write_register(u32 value, void *iomem); -u32 read_register(void *iomem); - -struct xdma_dev *xdev_find_by_pdev(struct pci_dev *pdev); - -void xdma_device_offline(struct pci_dev *pdev, void *dev_handle); -void xdma_device_online(struct pci_dev *pdev, void *dev_handle); - -int xdma_performance_submit(struct xdma_dev *xdev, struct xdma_engine *engine); -struct xdma_transfer *engine_cyclic_stop(struct xdma_engine *engine); -void enable_perf(struct xdma_engine *engine); -void get_perf_stats(struct xdma_engine *engine); - -int xdma_cyclic_transfer_setup(struct xdma_engine *engine); -int xdma_cyclic_transfer_teardown(struct xdma_engine *engine); -ssize_t xdma_engine_read_cyclic(struct xdma_engine *, char __user *, size_t, - int); - -#endif /* XDMA_LIB_H */ - -// 67d7842dbbe25473c3c32b93c0da8047785f30d78e8a024de1b57352245f9689 diff --git a/sdk/linux_kernel_drivers/xocl/libxdma_api.h b/sdk/linux_kernel_drivers/xocl/libxdma_api.h deleted file mode 100644 index bf043eb1..00000000 --- a/sdk/linux_kernel_drivers/xocl/libxdma_api.h +++ /dev/null @@ -1,135 +0,0 @@ -/******************************************************************************* - * - * Xilinx XDMA IP Core Linux Driver - * - * Copyright(c) Sidebranch. - * Copyright(c) Xilinx, Inc. - * - * Karen Xie - * Leon Woestenberg - * - ******************************************************************************/ - -#ifndef __XDMA_BASE_API_H__ -#define __XDMA_BASE_API_H__ - -#include -#include -#include - -/* - * functions exported by the xdma driver - */ - -typedef struct { - u64 write_submitted; - u64 write_completed; - u64 read_requested; - u64 read_completed; - u64 restart; - u64 open; - u64 close; - u64 msix_trigger; -} xdma_statistics; - -/* - * This struct should be constantly updated by XMDA using u64_stats_* APIs - * The front end will read the structure without locking (That's why updating atomically is a must) - * every time it prints the statistics. - */ -//static XDMA_Statistics stats; - -/* - * xdma_device_open - read the pci bars and configure the fpga - * should be called from probe() - * NOTE: - * user interrupt will not enabled until xdma_user_isr_enable() - * is called - * @pdev: ptr to pci_dev - * @mod_name: the module name to be used for request_irq - * @user_max: max # of user/event (interrupts) to be configured - * @channel_max: max # of c2h and h2c channels to be configured - * NOTE: if the user/channel provisioned is less than the max specified, - * libxdma will update the user_max/channel_max - * returns - * a opaque handle (for libxdma to identify the device) - * NULL, in case of error - */ -void *xdma_device_open(const char *mod_name, struct pci_dev *pdev, - int *user_max, int *h2c_channel_max, int *c2h_channel_max); - -/* - * xdma_device_close - prepare fpga for removal: disable all interrupts (users - * and xdma) and release all resources - * should called from remove() - * @pdev: ptr to struct pci_dev - * @tuples: from xdma_device_open() - */ -void xdma_device_close(struct pci_dev *pdev, void *dev_handle); - -/* - * xdma_device_restart - restart the fpga - * @pdev: ptr to struct pci_dev - * TODO: - * may need more refining on the parameter list - * return < 0 in case of error - * TODO: exact error code will be defined later - */ -int xdma_device_restart(struct pci_dev *pdev, void *dev_handle); - -/* - * xdma_user_isr_register - register a user ISR handler - * It is expected that the xdma will register the ISR, and for the user - * interrupt, it will call the corresponding handle if it is registered and - * enabled. - * - * @pdev: ptr to the the pci_dev struct - * @mask: bitmask of user interrupts (0 ~ 15)to be registered - * bit 0: user interrupt 0 - * ... - * bit 15: user interrupt 15 - * any bit above bit 15 will be ignored. - * @handler: the correspoinding handler - * a NULL handler will be treated as de-registeration - * @name: to be passed to the handler, ignored if handler is NULL` - * @dev: to be passed to the handler, ignored if handler is NULL` - * return < 0 in case of error - * TODO: exact error code will be defined later - */ -int xdma_user_isr_register(void *dev_hndl, unsigned int mask, - irq_handler_t handler, void *dev); - -/* - * xdma_user_isr_enable/disable - enable or disable user interrupt - * @pdev: ptr to the the pci_dev struct - * @mask: bitmask of user interrupts (0 ~ 15)to be registered - * return < 0 in case of error - * TODO: exact error code will be defined later - */ -int xdma_user_isr_enable(void *dev_hndl, unsigned int mask); -int xdma_user_isr_disable(void *dev_hndl, unsigned int mask); - -/* - * xdma_xfer_submit - submit data for dma operation (for both read and write) - * This is a blocking call - * @channel: channle number (< channel_max) - * == channel_max means libxdma can pick any channel available:q - - * @dir: DMA_FROM/TO_DEVICE - * @offset: offset into the DDR/BRAM memory to read from or write to - * @sg_tbl: the scatter-gather list of data buffers - * @timeout: timeout in mili-seconds, *currently ignored - * return # of bytes transfered or - * < 0 in case of error - * TODO: exact error code will be defined later - */ -ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr, - struct sg_table *sgt, bool dma_mapped, int timeout_ms); - - -/////////////////////missing API//////////////////// - -//xdma_get_channle_state - if no interrupt on DMA hang is available -//xdma_channle_restart - -#endif diff --git a/sdk/linux_kernel_drivers/xocl/xclfeatures.h b/sdk/linux_kernel_drivers/xocl/xclfeatures.h deleted file mode 100644 index 5709b93c..00000000 --- a/sdk/linux_kernel_drivers/xocl/xclfeatures.h +++ /dev/null @@ -1,146 +0,0 @@ -/** - * Copyright (C) 2015-2018 Xilinx, Inc - * - * This file is dual licensed. It may be redistributed and/or modified - * under the terms of the Apache 2.0 License OR version 2 of the GNU - * General Public License. - * - * Apache License Verbiage - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * GPL license Verbiage: - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - - -/** - * Xilinx SDAccel FPGA BIOS definition - * Copyright (C) 2016-2017, Xilinx Inc - All rights reserved - */ - - -//Layout: At address 0xB0000, we will have the FeatureRomHeader that comprises: -// -//1. First have FeatureRomHeader: 152 bytes of information followed by -//2. Then, as a part of FeatureRomHeader we have the PRRegion struct(s). -// The number of such structs will be same as OCLRegionCount. -//3. After this the freq scaling table is laid out. -// - -//#include - -typedef struct PartialRegion { - uint16_t clk[4]; - uint8_t XPR; //0 : non-xpt, 1: xpr -} PRRegion; - -// Each entry represents one row in freq scaling table. -struct FreqScalingTableRow{ - short config0; - short freq; - short config2; -}; - -enum PROMType { - BPI = 0 - ,SPI = 1 - //room for 6 more types of flash devices. -}; - -enum DebugType { - DT_NIFD = 0x01, - DT_FIREWALL = 0x02 - //There is room for future expansion upto 8 IPs -}; - -// This bit mask is used with the FeatureBitMap to calculate 64 bool features -// -// To test if a feature is provided: -// FeatureRomHeader header; -// if (FeatureBitMask::FBM_IS_UNIFIED & header.FeatureBitMap) -// // it is supported -// else -// // it is not supported -// -// To set if a feature is provided: -// header.FeatureBitMap = 0; -// header.FeatureBitMap |= FeatureBitMask::FBM_IS_UNIFIED; -// -enum FeatureBitMask -{ - UNIFIED_PLATFORM = 0x0000000000000001 /* bit 1 : Unified platform */ - ,XARE_ENBLD = 0x0000000000000002 /* bit 2 : Aurora link enabled DSA */ - ,BOARD_MGMT_ENBLD = 0x0000000000000004 /* bit 3 : Has MB based power monitoring */ - ,MB_SCHEDULER = 0x0000000000000008 /* bit 4: Has MB based scheduler */ - ,PROM_MASK = 0x0000000000000070 /* bits 5,6 &7 : 3 bits for PROMType */ - /** ------ Bit 8 unused **/ - ,DEBUG_MASK = 0x000000000000FF00 /* bits 9 through 16 : 8 bits for DebugType */ - - //....more -}; - - - -// In the following data structures, the EntryPointString, MajorVersion, and MinorVersion -// values are all used in the Runtime to identify if the ROM is producing valid data, and -// to pick the schema to read the rest of the data; Ergo, these values shall not change. - -/* - * Struct used for > 2017.2_sdx - * This struct should be used for version (==) 10.0 (Major: 10, Minor: 0) - */ -struct FeatureRomHeader { - unsigned char EntryPointString[4]; // This is "xlnx" - uint8_t MajorVersion; // Feature ROM's major version eg 1 - uint8_t MinorVersion; // minor version eg 2. - // -- DO NOT CHANGE THE TYPES ABOVE THIS LINE -- - uint32_t VivadoBuildID; // Vivado Software Build (e.g., 1761098 ). From ./vivado --version - uint32_t IPBuildID; // IP Build (e.g., 1759159 from abve) - uint64_t TimeSinceEpoch; // linux time(NULL) call, at write_dsa_rom invocation - unsigned char FPGAPartName[64]; // The hardware FPGA part. Null termninated - unsigned char VBNVName[64]; // eg : xilinx:xil-accel-rd-ku115:4ddr-xpr:3.4: null terminated - uint8_t DDRChannelCount; // 4 for TUL - uint8_t DDRChannelSize; // 4 (in GB) - uint64_t DRBaseAddress; // The Dynamic Range's (AppPF/CL/Userspace) Base Address - uint64_t FeatureBitMap; // Feature Bit Map, specifies 64 different bool features, maps to enum FeatureBitMask -}; - - -/* - * Struct used for 2017.1_sdx - * This struct should be used for all versions below (<) 10.0 (Major: 10, Minor: 0) -struct FeatureRomHeader { - unsigned char EntryPointString[4]; // This is "xlnx" - uint8_t MajorVersion; // Feature ROM's major version eg 1 - uint8_t MinorVersion; // minor version eg 2. - // -- DO NOT CHANGE THE TYPES ABOVE THIS LINE -- - uint32_t VivadoBuildID; // Vivado Software Build (e.g., 1761098 ). From ./vivado --version - uint32_t IPBuildID; // IP Build (e.g., 1759159 from abve) - uint64_t TimeSinceEpoch; // linux time(NULL) call, at write_dsa_rom invocation - unsigned char FPGAPartName[64]; // The hardware FPGA part. Null termninated - unsigned char VBNVName[64]; // eg : xilinx:xil-accel-rd-ku115:4ddr-xpr:3.4: null terminated - uint8_t DDRChannelCount; // 4 for TUL - uint8_t DDRChannelSize; // 4 (in GB) - uint8_t OCLRegionCount; // Number of OCL regions - uint8_t FPGAType; // maps to enum FPGAGeneration - uint8_t NumFreqTableRows; // Number of rows in freq scaling table. - PRRegion region[1]; // The PRRegion struct, lay them out one after another totalling OCLRegionCount. - unsigned char FreqTable[1]; // NumFreqTableRows of FreqScalingTableRow struct -}; -*/ - diff --git a/sdk/linux_kernel_drivers/xocl/xocl_bo.c b/sdk/linux_kernel_drivers/xocl/xocl_bo.c deleted file mode 100644 index b8aedfc6..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_bo.c +++ /dev/null @@ -1,1041 +0,0 @@ -/* - * Copyright (C) 2016-2018 Xilinx, Inc - * - * Authors: - * Sonal Santan - * Sarabjeet Singh - * - * A GEM style device manager for PCIe based OpenCL accelerators. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#ifdef XOCL_CMA_ALLOC -#include -#endif -#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,0,0) -#include -#endif -#include -#include "xocl_drv.h" -#include "xocl_ioctl.h" -#include "xocl_xdma.h" - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) -#define XOCL_DRM_FREE_MALLOC -#elif defined(RHEL_RELEASE_CODE) -#if RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,4) -#define XOCL_DRM_FREE_MALLOC -#endif -#endif - -#if defined(XOCL_DRM_FREE_MALLOC) -static inline void drm_free_large(void *ptr) -{ - kvfree(ptr); -} - -static inline void *drm_malloc_ab(size_t nmemb, size_t size) -{ - return kvmalloc_array(nmemb, sizeof(struct page *), GFP_KERNEL); -} -#endif - -static inline int xocl_drm_mm_insert_node(struct drm_mm *mm, - struct drm_mm_node *node, - u64 size) -{ -#if defined(XOCL_DRM_FREE_MALLOC) - return drm_mm_insert_node_generic(mm, node, size, PAGE_SIZE, 0, 0); -#else - return drm_mm_insert_node_generic(mm, node, size, PAGE_SIZE, 0, 0, 0); -#endif -} - - -static inline void __user *to_user_ptr(u64 address) -{ - return (void __user *)(uintptr_t)address; -} - -static size_t xocl_bo_physical_addr(const struct drm_xocl_bo *xobj) -{ - uint64_t paddr = xobj->mm_node ? xobj->mm_node->start : 0xffffffffffffffffull; - - //Sarab: Need to check for number of hops & size of DDRs - if (xobj->flags & XOCL_BO_ARE) - paddr |= XOCL_ARE_HOP; - return paddr; -} - -void xocl_describe(const struct drm_xocl_bo *xobj) -{ - size_t size_in_kb = xobj->base.size / 1024; - size_t physical_addr = xocl_bo_physical_addr(xobj); - unsigned ddr = xocl_bo_ddr_idx(xobj->flags); - unsigned userptr = xocl_bo_userptr(xobj) ? 1 : 0; - - DRM_DEBUG("%p: H[%p] SIZE[0x%zxKB] D[0x%zx] DDR[%u] UPTR[%u] SGLCOUNT[%u]\n", - xobj, xobj->vmapping, size_in_kb, physical_addr, ddr, userptr, xobj->sgt->orig_nents); -} - -static void xocl_free_mm_node(struct drm_xocl_bo *xobj) -{ - struct drm_xocl_dev *xdev = xobj->base.dev->dev_private; - unsigned ddr = xocl_bo_ddr_idx(xobj->flags); - if (!xobj->mm_node) - return; - - mutex_lock(&xdev->mm_lock); - xdev->mm_usage_stat[ddr].memory_usage -= xobj->base.size; - xdev->mm_usage_stat[ddr].bo_count--; - drm_mm_remove_node(xobj->mm_node); - mutex_unlock(&xdev->mm_lock); - kfree(xobj->mm_node); - xobj->mm_node = NULL; -} - -void xocl_free_bo(struct drm_gem_object *obj) -{ - struct drm_xocl_bo *xobj = to_xocl_bo(obj); - struct drm_xocl_dev *xdev = xobj->base.dev->dev_private; - int npages = obj->size >> PAGE_SHIFT; - DRM_DEBUG("Freeing BO %p\n", xobj); - - if (xobj->vmapping) - vunmap(xobj->vmapping); - xobj->vmapping = NULL; - - if (xobj->pages) { - if (xocl_bo_userptr(xobj)) { - release_pages(xobj->pages, npages, 0); - drm_free_large(xobj->pages); - } -#ifdef XOCL_CMA_ALLOC - else if (xocl_bo_cma(xobj)) { - if (xobj->pages[0]) - cma_release(xdev->cma_blk, xobj->pages[0], npages); - drm_free_large(xobj->pages); - } -#endif - else if (!xocl_bo_import(xobj)) { - drm_gem_put_pages(obj, xobj->pages, false, false); - } - } - xobj->pages = NULL; - - if (!xocl_bo_import(xobj)) { - DRM_DEBUG("Freeing regular buffer\n"); - if (xobj->sgt) { - sg_free_table(xobj->sgt); - kfree(xobj->sgt); - xobj->sgt = NULL; - } - xocl_free_mm_node(xobj); - } - else { - DRM_DEBUG("Freeing imported buffer\n"); - if (!(xobj->flags & XOCL_BO_ARE)) - xocl_free_mm_node(xobj); - - if (obj->import_attach) { - DRM_DEBUG("Unnmapping attached dma buf\n"); - dma_buf_unmap_attachment(obj->import_attach, xobj->sgt, DMA_TO_DEVICE); - drm_prime_gem_destroy(obj, NULL); - } - } - - //If it is imported BO then we do not delete SG Table - //And if is imported from ARE device then we do not free the mm_node as well - - //Sarab: Call detach here........ - //to let the exporting device know that importing device do not need it anymore.. - //else free_bo i.e this function is not called for exporting device - //as it assumes that the exported buffer is still being used - //dmabuf->ops->release(dmabuf); - //The drm_driver.gem_free_object callback is responsible for cleaning up the dma_buf attachment and references acquired at import time. - - /* This crashes machine.. Using above code instead - * drm_prime_gem_destroy calls detach function.. - struct dma_buf *imported_dma_buf = obj->dma_buf; - if (imported_dma_buf->ops->detach) - imported_dma_buf->ops->detach(imported_dma_buf, obj->import_attach); - */ - - drm_gem_object_release(obj); - kfree(xobj); -} - - -static inline int check_bo_user_flags(const struct drm_device *dev, unsigned flags) -{ - const unsigned ddr_count = xocl_ddr_channel_count(dev); - struct drm_xocl_dev *xdev = dev->dev_private; - unsigned ddr; - - if(ddr_count == 0) - return -EINVAL; - if (flags == 0xffffffff) - return 0; - if (flags == DRM_XOCL_BO_EXECBUF) - return 0; -#ifdef XOCL_CMA_ALLOC - if (flags == DRM_XOCL_BO_CMA) - return 0; -#else - if (flags == DRM_XOCL_BO_CMA) - return -EINVAL; -#endif - ddr = xocl_bo_ddr_idx(flags); - if (ddr == 0xffffffff) - return 0; - if (ddr >= ddr_count) - return -EINVAL; - if (xdev->unified) { - if (xdev->topology.m_data[ddr].m_used != 1) { - printk(KERN_INFO "Bank %d is marked as unused in axlf\n", ddr); - return -EINVAL; - } - } - return 0; -} - - -static struct drm_xocl_bo *xocl_create_bo(struct drm_device *dev, - uint64_t unaligned_size, - unsigned user_flags) -{ - size_t size = PAGE_ALIGN(unaligned_size); - struct drm_xocl_bo *xobj; - struct drm_xocl_dev *xdev = dev->dev_private; - unsigned ddr = xocl_bo_ddr_idx(user_flags); - const unsigned ddr_count = xocl_ddr_channel_count(dev); - int err = 0; - - if (!size) - return ERR_PTR(-EINVAL); - - /* Either none or only one DDR should be specified */ - if (check_bo_user_flags(dev, user_flags)) - return ERR_PTR(-EINVAL); - - xobj = kzalloc(sizeof(*xobj), GFP_KERNEL); - if (!xobj) - return ERR_PTR(-ENOMEM); - - err = drm_gem_object_init(dev, &xobj->base, size); - if (err) - goto out3; - - if (user_flags == DRM_XOCL_BO_EXECBUF) { - xobj->flags = XOCL_BO_EXECBUF; - xobj->mm_node = NULL; - xobj->metadata.state = DRM_XOCL_EXECBUF_STATE_ABORT; - return xobj; - } - -#ifdef XOCL_CMA_ALLOC - if (user_flags == DRM_XOCL_BO_CMA) { - xobj->flags = XOCL_BO_CMA; - xobj->mm_node = NULL; - return xobj; - } -#endif - - xobj->mm_node = kzalloc(sizeof(*xobj->mm_node), GFP_KERNEL); - if (!xobj->mm_node) { - err = -ENOMEM; - goto out3; - } - - mutex_lock(&xdev->mm_lock); - if (ddr != 0xffffffff) { - /* Attempt to allocate buffer on the requested DDR */ - DRM_DEBUG("%s:%s:%d: %u\n", __FILE__, __func__, __LINE__, ddr); - err = xocl_drm_mm_insert_node(&xdev->mm[ddr], xobj->mm_node, xobj->base.size); - if (err) - goto out2; - } - else { - /* Attempt to allocate buffer on any DDR */ - for (ddr = 0; ddr < ddr_count; ddr++) { - DRM_DEBUG("%s:%s:%d: %u\n", __FILE__, __func__, __LINE__, ddr); - if(xdev->unified && !xdev->topology.m_data[ddr].m_used) - continue; - err = xocl_drm_mm_insert_node(&xdev->mm[ddr], xobj->mm_node, xobj->base.size); - if (err == 0) - break; - } - if (err) - goto out2; - } - xdev->mm_usage_stat[ddr].memory_usage += xobj->base.size; - xdev->mm_usage_stat[ddr].bo_count++; - mutex_unlock(&xdev->mm_lock); - /* Record the DDR we allocated the buffer on */ - xobj->flags |= (1 << ddr); - - return xobj; -out2: - mutex_unlock(&xdev->mm_lock); - kfree(xobj->mm_node); - drm_gem_object_release(&xobj->base); -out3: - kfree(xobj); - return ERR_PTR(err); -} - -/* - * For ARE device do not reserve DDR space - * In below import it will reuse the mm_node which is already created by other application - */ - -static struct drm_xocl_bo *xocl_create_bo_forARE(struct drm_device *dev, - uint64_t unaligned_size, - struct drm_mm_node *exporting_mm_node) -{ - struct drm_xocl_bo *xobj; - size_t size = PAGE_ALIGN(unaligned_size); - int err = 0; - - if (!size) - return ERR_PTR(-EINVAL); - - xobj = kzalloc(sizeof(*xobj), GFP_KERNEL); - if (!xobj) - return ERR_PTR(-ENOMEM); - - err = drm_gem_object_init(dev, &xobj->base, size); - if (err) - goto out3; - - xobj->mm_node = exporting_mm_node; - if (!xobj->mm_node) { - err = -ENOMEM; - goto out3; - } - - /* Record that this buffer is on remote device to be access over ARE*/ - xobj->flags = XOCL_BO_ARE; - return xobj; -out3: - kfree(xobj); - return ERR_PTR(err); -} - - -int xocl_create_bo_ioctl(struct drm_device *dev, - void *data, - struct drm_file *filp) -{ - int ret; - int j; - struct drm_xocl_bo *xobj; - struct page *cpages; - unsigned int page_count; - struct drm_xocl_create_bo *args = data; - unsigned ddr = args->flags & 0xf; - struct drm_xocl_dev *xdev = dev->dev_private; - - if (args->flags && (args->flags != DRM_XOCL_BO_EXECBUF)) { - if (hweight_long(ddr) > 1) - return -EINVAL; - } - - xobj = xocl_create_bo(dev, args->size, args->flags); - - if (IS_ERR(xobj)) { - DRM_DEBUG("object creation failed\n"); - return PTR_ERR(xobj); - } - -#ifdef XOCL_CMA_ALLOC - if (args->flags == DRM_XOCL_BO_CMA) { - page_count = xobj->base.size >> PAGE_SHIFT; - xobj->pages = drm_malloc_ab(page_count, sizeof(*xobj->pages)); - if (!xobj->pages) { - ret = -ENOMEM; - goto out_free; - } - cpages = cma_alloc(xdev->cma_blk, page_count, 0, GFP_KERNEL); - if (!cpages) { - ret = -ENOMEM; - goto out_free; - } - for (j = 0; j < page_count; j++) - xobj->pages[j] = cpages++; - } - else { - xobj->pages = drm_gem_get_pages(&xobj->base); - } -#else - xobj->pages = drm_gem_get_pages(&xobj->base); -#endif - if (IS_ERR(xobj->pages)) { - ret = PTR_ERR(xobj->pages); - goto out_free; - } - - xobj->sgt = drm_prime_pages_to_sg(xobj->pages, xobj->base.size >> PAGE_SHIFT); - if (IS_ERR(xobj->sgt)) { - ret = PTR_ERR(xobj->sgt); - goto out_free; - } - - xobj->vmapping = vmap(xobj->pages, xobj->base.size >> PAGE_SHIFT, VM_MAP, PAGE_KERNEL); - - if (!xobj->vmapping) { - ret = -ENOMEM; - goto out_free; - } - - ret = drm_gem_create_mmap_offset(&xobj->base); - if (ret < 0) - goto out_free; - - ret = drm_gem_handle_create(filp, &xobj->base, &args->handle); - if (ret < 0) - goto out_free; - - xocl_describe(xobj); - drm_gem_object_unreference_unlocked(&xobj->base); - return ret; - -out_free: - xocl_free_bo(&xobj->base); - return ret; -} - -int xocl_userptr_bo_ioctl(struct drm_device *dev, - void *data, - struct drm_file *filp) -{ - int ret; - struct drm_xocl_bo *xobj; - unsigned int page_count; - struct drm_xocl_userptr_bo *args = data; - unsigned ddr = args->flags & 0xf; - - if (offset_in_page(args->addr)) - return -EINVAL; - - if (args->flags & DRM_XOCL_BO_EXECBUF) - return -EINVAL; - - if (args->flags & DRM_XOCL_BO_CMA) - return -EINVAL; - - if (args->flags && (hweight_long(ddr) > 1)) - return -EINVAL; - - xobj = xocl_create_bo(dev, args->size, args->flags); - - if (IS_ERR(xobj)) { - DRM_DEBUG("object creation failed\n"); - return PTR_ERR(xobj); - } - - /* Use the page rounded size so we can accurately account for number of pages */ - page_count = xobj->base.size >> PAGE_SHIFT; - - xobj->pages = drm_malloc_ab(page_count, sizeof(*xobj->pages)); - if (!xobj->pages) { - ret = -ENOMEM; - goto out1; - } - ret = get_user_pages_fast(args->addr, page_count, 1, xobj->pages); - - if (ret != page_count) - goto out0; - - xobj->sgt = drm_prime_pages_to_sg(xobj->pages, page_count); - if (IS_ERR(xobj->sgt)) { - ret = PTR_ERR(xobj->sgt); - goto out0; - } - - /* TODO: resolve the cache issue */ - xobj->vmapping = vmap(xobj->pages, page_count, VM_MAP, PAGE_KERNEL); - - if (!xobj->vmapping) { - ret = -ENOMEM; - goto out1; - } - - ret = drm_gem_handle_create(filp, &xobj->base, &args->handle); - if (ret) - goto out1; - - xobj->flags |= XOCL_BO_USERPTR; - xocl_describe(xobj); - drm_gem_object_unreference_unlocked(&xobj->base); - return ret; - -out0: - drm_free_large(xobj->pages); - xobj->pages = NULL; -out1: - xocl_free_bo(&xobj->base); - DRM_DEBUG("handle creation failed\n"); - return ret; -} - - -int xocl_map_bo_ioctl(struct drm_device *dev, - void *data, - struct drm_file *filp) -{ - int ret = 0; - struct drm_xocl_map_bo *args = data; - struct drm_gem_object *obj; - - obj = xocl_gem_object_lookup(dev, filp, args->handle); - if (!obj) { - DRM_ERROR("Failed to look up GEM BO %d\n", args->handle); - return -ENOENT; - } - - if (xocl_bo_userptr(to_xocl_bo(obj))) { - ret = -EPERM; - goto out; - } - /* The mmap offset was set up at BO allocation time. */ - args->offset = drm_vma_node_offset_addr(&obj->vma_node); - xocl_describe(to_xocl_bo(obj)); -out: - drm_gem_object_unreference_unlocked(obj); - return ret; -} - -static struct sg_table *alloc_onetime_sg_table(struct page **pages, uint64_t offset, uint64_t size) -{ - int ret; - unsigned int nr_pages; - struct sg_table *sgt = kmalloc(sizeof(struct sg_table), GFP_KERNEL); - if (!sgt) - return ERR_PTR(-ENOMEM); - - pages += (offset >> PAGE_SHIFT); - offset &= (~PAGE_MASK); - nr_pages = PAGE_ALIGN(size + offset) >> PAGE_SHIFT; - - ret = sg_alloc_table_from_pages(sgt, pages, nr_pages, offset, size, GFP_KERNEL); - if (ret) - goto cleanup; - return sgt; - -cleanup: - kfree(sgt); - return ERR_PTR(-ENOMEM); -} - -static int acquire_channel(struct drm_xocl_dev *xdev, enum drm_xocl_sync_bo_dir dir) -{ - int channel = 0; - int result = 0; - - if (down_interruptible(&xdev->channel_sem[dir])) { - channel = -ERESTARTSYS; - goto out; - } - - for (channel = 0; channel < xdev->channel; channel++) { - result = test_and_clear_bit(channel, &xdev->channel_bitmap[dir]); - if (result) - break; - } - if (!result) { - // How is this possible? - DRM_ERROR("Failed to acquire a valid channel\n"); - up(&xdev->channel_sem[dir]); - channel = -EIO; - } -out: - return channel; -} - -static void release_channel(struct drm_xocl_dev *xdev, enum drm_xocl_sync_bo_dir dir, int channel) -{ - set_bit(channel, &xdev->channel_bitmap[dir]); - up(&xdev->channel_sem[dir]); -} - - -int xocl_sync_bo_ioctl(struct drm_device *dev, - void *data, - struct drm_file *filp) -{ - const struct drm_xocl_bo *xobj; - struct sg_table *sgt; - u64 paddr = 0; - int channel = 0; - ssize_t ret = 0; - const struct drm_xocl_sync_bo *args = data; - struct drm_xocl_dev *xdev = dev->dev_private; - const bool dir = (args->dir == DRM_XOCL_SYNC_BO_TO_DEVICE) ? true : false; - struct drm_gem_object *gem_obj = xocl_gem_object_lookup(dev, filp, - args->handle); - if (!gem_obj) { - DRM_ERROR("Failed to look up GEM BO %d\n", args->handle); - return -ENOENT; - } - - xobj = to_xocl_bo(gem_obj); - sgt = xobj->sgt; - - //Sarab: If it is a remote BO then why do sync over ARE. - //We should do sync directly using the other device which this bo locally. - //So that txfer is: HOST->PCIE->DDR; Else it will be HOST->PCIE->ARE->DDR - paddr = xocl_bo_physical_addr(xobj); - - if (paddr == 0xffffffffffffffffull) - return -EINVAL; - - /* If device is offline (due to error), reject all DMA requests */ - if (xdev->offline) - return -ENODEV; - - - if ((args->offset >= gem_obj->size) || (args->size > gem_obj->size) || - ((args->offset + args->size) > gem_obj->size)) { - ret = -EINVAL; - goto out; - } - - /* only invalidate the range of addresses requested by the user */ - /* - if (args->dir == DRM_XOCL_SYNC_BO_TO_DEVICE) - flush_kernel_vmap_range(kaddr, args->size); - else if (args->dir == DRM_XOCL_SYNC_BO_FROM_DEVICE) - invalidate_kernel_vmap_range(kaddr, args->size); - else { - ret = -EINVAL; - goto out; - } - */ - paddr += args->offset; - - if (args->offset || (args->size != xobj->base.size)) { - sgt = alloc_onetime_sg_table(xobj->pages, args->offset, args->size); - if (IS_ERR(sgt)) { - ret = PTR_ERR(sgt); - goto out; - } - } - - //drm_clflush_sg(sgt); - channel = acquire_channel(xdev, args->dir); - - if (channel < 0) { - ret = -EINVAL; - goto clear; - } - /* Now perform DMA */ - ret = xdma_migrate_bo(xdev, sgt, dir, paddr, channel); - if (ret >= 0) { - xdev->channel_usage[args->dir][channel] += ret; - ret = (ret == args->size) ? 0 : -EIO; - } - release_channel(xdev, args->dir, channel); -clear: - if (args->offset || (args->size != xobj->base.size)) { - sg_free_table(sgt); - kfree(sgt); - } -out: - drm_gem_object_unreference_unlocked(gem_obj); - return ret; -} - -int xocl_info_bo_ioctl(struct drm_device *dev, - void *data, - struct drm_file *filp) -{ - const struct drm_xocl_bo *xobj; - struct drm_xocl_info_bo *args = data; - struct drm_gem_object *gem_obj = xocl_gem_object_lookup(dev, filp, - args->handle); - - if (!gem_obj) { - DRM_ERROR("Failed to look up GEM BO %d\n", args->handle); - return -ENOENT; - } - - xobj = to_xocl_bo(gem_obj); - - args->size = xobj->base.size; - - args->paddr = xocl_bo_physical_addr(xobj); - xocl_describe(xobj); - drm_gem_object_unreference_unlocked(gem_obj); - - return 0; -} - -int xocl_pwrite_bo_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp) -{ - struct drm_xocl_bo *xobj; - const struct drm_xocl_pwrite_bo *args = data; - struct drm_gem_object *gem_obj = xocl_gem_object_lookup(dev, filp, - args->handle); - char __user *user_data = to_user_ptr(args->data_ptr); - int ret = 0; - void *kaddr; - - if (!gem_obj) { - DRM_ERROR("Failed to look up GEM BO %d\n", args->handle); - return -ENOENT; - } - - if ((args->offset > gem_obj->size) || (args->size > gem_obj->size) - || ((args->offset + args->size) > gem_obj->size)) { - ret = -EINVAL; - goto out; - } - - if (args->size == 0) { - ret = 0; - goto out; - } - - if (!access_ok(VERIFY_READ, user_data, args->size)) { - ret = -EFAULT; - goto out; - } - - xobj = to_xocl_bo(gem_obj); - - if (xocl_bo_userptr(xobj)) { - ret = -EPERM; - goto out; - } - - kaddr = xobj->vmapping; - kaddr += args->offset; - - ret = copy_from_user(kaddr, user_data, args->size); -out: - drm_gem_object_unreference_unlocked(gem_obj); - - return ret; -} - -int xocl_pread_bo_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp) -{ - struct drm_xocl_bo *xobj; - const struct drm_xocl_pread_bo *args = data; - struct drm_gem_object *gem_obj = xocl_gem_object_lookup(dev, filp, - args->handle); - char __user *user_data = to_user_ptr(args->data_ptr); - int ret = 0; - void *kaddr; - - if (!gem_obj) { - DRM_ERROR("Failed to look up GEM BO %d\n", args->handle); - return -ENOENT; - } - - if (xocl_bo_userptr(to_xocl_bo(gem_obj))) { - ret = -EPERM; - goto out; - } - - if ((args->offset > gem_obj->size) || (args->size > gem_obj->size) - || ((args->offset + args->size) > gem_obj->size)) { - ret = -EINVAL; - goto out; - } - - if (args->size == 0) { - ret = 0; - goto out; - } - - if (!access_ok(VERIFY_WRITE, user_data, args->size)) { - ret = EFAULT; - goto out; - } - - xobj = to_xocl_bo(gem_obj); - kaddr = xobj->vmapping;; - kaddr += args->offset; - - ret = copy_to_user(user_data, kaddr, args->size); - -out: - drm_gem_object_unreference_unlocked(gem_obj); - - return ret; -} - -struct sg_table *xocl_gem_prime_get_sg_table(struct drm_gem_object *obj) -{ - struct drm_xocl_bo *xobj = to_xocl_bo(obj); - return drm_prime_pages_to_sg(xobj->pages, xobj->base.size >> PAGE_SHIFT); -} - - -static struct drm_xocl_bo *xocl_is_exporting_xare(struct drm_device *dev, struct dma_buf_attachment *attach) -{ - struct drm_gem_object *exporting_gem_obj; - struct drm_device *exporting_drm_dev; - struct drm_xocl_dev *exporting_xdev; - - struct device_driver *importing_dma_driver = dev->dev->driver; - struct dma_buf *exporting_dma_buf = attach->dmabuf; - struct device_driver *exporting_dma_driver = attach->dev->driver; - struct drm_xocl_dev *xdev = dev->dev_private; - - if (!strstr(xdev->header.VBNVName, "-xare")) - return NULL; - - //We don't know yet if the exporting device is Xilinx/XOCL or third party or USB device - //So checking it in below code - if (importing_dma_driver != exporting_dma_driver) - return NULL; - - //Exporting devices have same driver as us. So this is Xilinx device - //So now we can get gem_object, drm_device & xocl_dev - exporting_gem_obj = exporting_dma_buf->priv; - exporting_drm_dev = exporting_gem_obj->dev; - exporting_xdev = exporting_drm_dev->dev_private; - //exporting_xdev->header;//This has FeatureROM header - if (strstr(exporting_xdev->header.VBNVName, "-xare")) - return to_xocl_bo(exporting_gem_obj); - - return NULL; -} - -struct drm_gem_object *xocl_gem_prime_import_sg_table(struct drm_device *dev, - struct dma_buf_attachment *attach, struct sg_table *sgt) -{ - int ret = 0; - // This is exporting device - struct drm_xocl_bo *exporting_xobj = xocl_is_exporting_xare(dev, attach); - - // For ARE device resue the mm node from exporting xobj - - // For non ARE devices we need to create a full BO but share the SG table - // ???? add flags to create_bo.. for DDR bank?? - - struct drm_xocl_bo *importing_xobj = exporting_xobj ? xocl_create_bo_forARE(dev, attach->dmabuf->size, exporting_xobj->mm_node) : - xocl_create_bo(dev, attach->dmabuf->size, 0); - - if (IS_ERR(importing_xobj)) { - DRM_DEBUG("object creation failed\n"); - return (struct drm_gem_object *)importing_xobj; - } - - importing_xobj->flags |= XOCL_BO_IMPORT; - importing_xobj->sgt = sgt; - importing_xobj->pages = drm_malloc_ab(attach->dmabuf->size >> PAGE_SHIFT, sizeof(*importing_xobj->pages)); - if (!importing_xobj->pages) { - ret = -ENOMEM; - goto out_free; - } - - ret = drm_prime_sg_to_page_addr_arrays(sgt, importing_xobj->pages, - NULL, attach->dmabuf->size >> PAGE_SHIFT); - if (ret) - goto out_free; - - importing_xobj->vmapping = vmap(importing_xobj->pages, importing_xobj->base.size >> PAGE_SHIFT, VM_MAP, - PAGE_KERNEL); - - if (!importing_xobj->vmapping) { - ret = -ENOMEM; - goto out_free; - } - - ret = drm_gem_create_mmap_offset(&importing_xobj->base); - if (ret < 0) - goto out_free; - - xocl_describe(importing_xobj); - return &importing_xobj->base; - -out_free: - xocl_free_bo(&importing_xobj->base); - DRM_ERROR("Buffer import failed\n"); - return ERR_PTR(ret); -} - -void *xocl_gem_prime_vmap(struct drm_gem_object *obj) -{ - struct drm_xocl_bo *xobj = to_xocl_bo(obj); - return xobj->vmapping; -} - -void xocl_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) -{ - -} - -static int xocl_init_unmgd(struct drm_xocl_unmgd *unmgd, uint64_t data_ptr, uint64_t size, - enum drm_xocl_sync_bo_dir dir) -{ - int ret; - char __user *user_data = to_user_ptr(data_ptr); - - if (!access_ok((dir == DRM_XOCL_SYNC_BO_TO_DEVICE) ? VERIFY_READ : VERIFY_WRITE, user_data, size)) - return -EFAULT; - - memset(unmgd, 0, sizeof(struct drm_xocl_unmgd)); - - unmgd->npages = (((unsigned long)user_data + size + PAGE_SIZE - 1) - - ((unsigned long)user_data & PAGE_MASK)) >> PAGE_SHIFT; - - unmgd->pages = drm_malloc_ab(unmgd->npages, sizeof(*unmgd->pages)); - if (!unmgd->pages) - return -ENOMEM; - - ret = get_user_pages_fast(data_ptr, unmgd->npages, (dir == DRM_XOCL_SYNC_BO_FROM_DEVICE) ? 1 : 0, unmgd->pages); - - if (ret != unmgd->npages) - goto clear_pages; - - unmgd->sgt = alloc_onetime_sg_table(unmgd->pages, data_ptr & ~PAGE_MASK, size); - if (IS_ERR(unmgd->sgt)) { - ret = PTR_ERR(unmgd->sgt); - goto clear_release; - } - - return 0; - -clear_release: - release_pages(unmgd->pages, unmgd->npages, 0); -clear_pages: - drm_free_large(unmgd->pages); - unmgd->pages = NULL; - return ret; -} - -static void xocl_finish_unmgd(struct drm_xocl_unmgd *unmgd) -{ - if (!unmgd->pages) - return; - sg_free_table(unmgd->sgt); - kfree(unmgd->sgt); - release_pages(unmgd->pages, unmgd->npages, 0); - drm_free_large(unmgd->pages); - unmgd->pages = NULL; -} - - -int xocl_pwrite_unmgd_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp) -{ - int channel; - struct drm_xocl_unmgd unmgd; - const struct drm_xocl_pwrite_unmgd *args = data; - struct drm_xocl_dev *xdev = dev->dev_private; - const enum drm_xocl_sync_bo_dir dir = DRM_XOCL_SYNC_BO_TO_DEVICE; - ssize_t ret = 0; - - if (args->address_space != 0) - return -EFAULT; - - if (args->size == 0) - return 0; - - DRM_DEBUG("%s:%d\n", __func__, __LINE__); - ret = xocl_init_unmgd(&unmgd, args->data_ptr, args->size, dir); - if (ret) - return ret; - - channel = acquire_channel(xdev, dir); - DRM_DEBUG("%s:%d\n", __func__, __LINE__); - if (channel < 0) { - ret = -EINVAL; - goto clear; - } - /* Now perform DMA */ - ret = xdma_migrate_bo(xdev, unmgd.sgt, (dir == DRM_XOCL_SYNC_BO_TO_DEVICE), args->paddr, channel); - if (ret >= 0) { - xdev->channel_usage[dir][channel] += ret; - ret = (ret == args->size) ? 0 : -EIO; - } - release_channel(xdev, dir, channel); - DRM_DEBUG("%s:%llx\n", __func__, xdev->channel_usage[dir][channel]); -clear: - xocl_finish_unmgd(&unmgd); - return ret; -} - -int xocl_pread_unmgd_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp) -{ - int channel; - struct drm_xocl_unmgd unmgd; - const struct drm_xocl_pwrite_unmgd *args = data; - struct drm_xocl_dev *xdev = dev->dev_private; - const enum drm_xocl_sync_bo_dir dir = DRM_XOCL_SYNC_BO_FROM_DEVICE; - ssize_t ret = 0; - - DRM_DEBUG("%s:%d\n", __func__, __LINE__); - if (args->address_space != 0) - return -EFAULT; - - if (args->size == 0) - return 0; - - ret = xocl_init_unmgd(&unmgd, args->data_ptr, args->size, dir); - if (ret) - return ret; - - DRM_DEBUG("%s:%d\n", __func__, __LINE__); - channel = acquire_channel(xdev, dir); - - if (channel < 0) { - ret = -EINVAL; - goto clear; - } - /* Now perform DMA */ - ret = xdma_migrate_bo(xdev, unmgd.sgt, (dir == DRM_XOCL_SYNC_BO_TO_DEVICE), args->paddr, channel); - if (ret >= 0) { - xdev->channel_usage[dir][channel] += ret; - ret = (ret == args->size) ? 0 : -EIO; - } - release_channel(xdev, dir, channel); - DRM_DEBUG("%s:%llx\n", __func__, xdev->channel_usage[dir][channel]); -clear: - xocl_finish_unmgd(&unmgd); - return ret; -} - -int xocl_usage_stat_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp) -{ - struct drm_xocl_dev *xdev = dev->dev_private; - struct drm_xocl_usage_stat *args = data; - args->mm_channel_count = xocl_ddr_channel_count(dev); - if (args->mm_channel_count > 8) - args->mm_channel_count = 8; - memcpy(args->mm, xdev->mm_usage_stat, sizeof(struct drm_xocl_mm_stat) * args->mm_channel_count); - args->dma_channel_count = xdev->channel; - if (args->dma_channel_count > 8) - args->dma_channel_count = 8; - memcpy(args->h2c, xdev->channel_usage[DRM_XOCL_SYNC_BO_TO_DEVICE], sizeof(unsigned long long) * args->dma_channel_count); - memcpy(args->c2h, xdev->channel_usage[DRM_XOCL_SYNC_BO_FROM_DEVICE], sizeof(unsigned long long) * args->dma_channel_count); - DRM_INFO("%s h2c[0] 0%llx\n", __func__, args->h2c[0]); - DRM_INFO("%s c2h[0] 0%llx\n", __func__, args->c2h[0]); - DRM_INFO("%s\n", __func__); - return 0; -} - - -// 67d7842dbbe25473c3c32b93c0da8047785f30d78e8a024de1b57352245f9689 diff --git a/sdk/linux_kernel_drivers/xocl/xocl_ctx.c b/sdk/linux_kernel_drivers/xocl/xocl_ctx.c deleted file mode 100644 index 24af6f2f..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_ctx.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2017-2018 Xilinx, Inc - * - * Authors: - * Sonal Santan - * - * A GEM style device manager for PCIe based OpenCL accelerators. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include "xocl_drv.h" -#include "xocl_ioctl.h" -#include "xocl_xdma.h" - - -void xocl_track_ctx(struct drm_xocl_dev *xdev, struct drm_xocl_client_ctx *fpriv) -{ - unsigned long flags; - - spin_lock_irqsave(&xdev->exec.ctx_list_lock, flags); - list_add_tail(&fpriv->link, &xdev->exec.ctx_list); - spin_unlock_irqrestore(&xdev->exec.ctx_list_lock, flags); -} - -void xocl_untrack_ctx(struct drm_xocl_dev *xdev, struct drm_xocl_client_ctx *fpriv) -{ - unsigned long flags; - - spin_lock_irqsave(&xdev->exec.ctx_list_lock, flags); - list_del(&fpriv->link); - spin_unlock_irqrestore(&xdev->exec.ctx_list_lock, flags); -} - diff --git a/sdk/linux_kernel_drivers/xocl/xocl_drv.c b/sdk/linux_kernel_drivers/xocl/xocl_drv.c deleted file mode 100644 index c97835b0..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_drv.c +++ /dev/null @@ -1,832 +0,0 @@ -/* - * Copyright (C) 2016-2018 Xilinx, Inc - * - * Authors: - * Sonal Santan - * Hem Neema - * - * A GEM style device manager for PCIe based OpenCL accelerators. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,0,0) -#include -#endif -#include -#include -#include -#include -#ifdef XOCL_CMA_ALLOC -#include -#endif -#include "xocl_drv.h" -#include "xocl_ioctl.h" -#include "xocl_xdma.h" -#include "xclbin.h" - -#define XOCL_DRIVER_NAME "xocl" -#define XOCL_DRIVER_DESC "Xilinx PCIe Accelerator Device Manager" -#define XOCL_DRIVER_DATE "20171111" -#define XOCL_DRIVER_MAJOR 2017 -#define XOCL_DRIVER_MINOR 4 -#define XOCL_DRIVER_PATCHLEVEL 5 - - -#define XOCL_DRIVER_VERSION \ - __stringify(XOCL_DRIVER_MAJOR) "." \ - __stringify(XOCL_DRIVER_MINOR) "." \ - __stringify(XOCL_DRIVER_PATCHLEVEL) - -#define XOCL_DRIVER_VERSION_NUMBER \ - ((XOCL_DRIVER_MAJOR)*1000 + (XOCL_DRIVER_MINOR)*100 + XOCL_DRIVER_PATCHLEVEL) - - -#define XOCL_FILE_PAGE_OFFSET 0x100000 - -#ifndef VM_RESERVED -#define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP) -#endif - -static const struct pci_device_id pciidlist[] = { - { PCI_DEVICE(0x10ee, 0x4A48), }, - { PCI_DEVICE(0x10ee, 0x4A88), }, - { PCI_DEVICE(0x10ee, 0x4B48), }, - { PCI_DEVICE(0x10ee, 0x4B88), }, - { PCI_DEVICE(0x10ee, 0x6850), }, - { PCI_DEVICE(0x10ee, 0x6890), }, - { PCI_DEVICE(0x10ee, 0x6950), }, - { PCI_DEVICE(0x10ee, 0x6990), }, - { PCI_DEVICE(0x10ee, 0x6A50), }, - { PCI_DEVICE(0x10ee, 0x6A90), }, - { PCI_DEVICE(0x10ee, 0x6E50), }, - { PCI_DEVICE(0x10ee, 0x6B10), }, - { PCI_DEVICE(0x1d0f, 0xf010), }, // shell 1.4 - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, pciidlist); - -static struct cma *xocl_cma = NULL; - -static void xocl_print_dev_info(const struct drm_xocl_dev *xdev) -{ - DRM_INFO("%s [Timestamp 0x%llx]\n", xdev->header.VBNVName, xdev->header.TimeSinceEpoch); - DRM_INFO("%d bi-directional DMA channels\n", xdev->channel); - DRM_INFO("%d DDR channels, Total RAM = %dGB\n", xdev->header.DDRChannelCount, - xdev->header.DDRChannelSize * xdev->header.DDRChannelCount); - DRM_INFO("PCI Resource 0x%llx [Size 0x%llxKB]\n", xdev->res_start, xdev->res_len/1024); -} - -static int probe_feature_rom(struct drm_xocl_dev *xdev) -{ - u32 val; - unsigned short ddr = (xdev->ddev->pdev->subsystem_device >> 12) & 0x000f; - val = ioread32(xdev->user_bar + XOCL_FEATURE_ROM); - // Magic number check - if (val != 0x786e6c78) { - if (xdev->ddev->pdev->vendor == 0x1d0f && (xdev->ddev->pdev->device == 0x1042 || xdev->ddev->pdev->device == 0xf010)) { - printk(KERN_INFO "XOCL: Found AWS VU9P Device without featureROM\n"); - //This is AWS device. Fill the FeatureROM struct. Right now it doesn't have FeatureROM - memset(xdev->header.EntryPointString, 0, sizeof(xdev->header.EntryPointString)); - strncpy(xdev->header.EntryPointString, "xlnx", 4); - memset(xdev->header.FPGAPartName, 0, sizeof(xdev->header.FPGAPartName)); - strncpy(xdev->header.FPGAPartName, "AWS VU9P", 8); - memset(xdev->header.VBNVName, 0, sizeof(xdev->header.VBNVName)); - strncpy(xdev->header.VBNVName, "xilinx_aws-vu9p-f1_dynamic_5_0", 35); - xdev->header.MajorVersion = 4; - xdev->header.MinorVersion = 0; - xdev->header.VivadoBuildID = 0xabcd; - xdev->header.IPBuildID = 0xabcd; - xdev->header.TimeSinceEpoch = 0xabcd; - xdev->header.DDRChannelCount = 4; - xdev->header.DDRChannelSize = 16; - xdev->header.FeatureBitMap = 0x0; - printk(KERN_INFO "XOCL: Enabling AWS dynamic 5.0 DSA\n"); - xdev->header.FeatureBitMap = UNIFIED_PLATFORM; - xdev->unified = true; - } else { - DRM_ERROR("XOCL: Probe of Feature ROM failed\n"); - return -ENODEV; - } - } else { - printk(KERN_INFO "XOCL: Printing PCI VendorID: %llx\n", xdev->ddev->pdev->vendor); - printk(KERN_INFO "XOCL: Printing PCI DeviceID: %llx\n", xdev->ddev->pdev->device); - memcpy_fromio(&xdev->header, xdev->user_bar + XOCL_FEATURE_ROM, sizeof(struct FeatureRomHeader)); - // Sanity check - if (strstr(xdev->header.VBNVName, "-xare")) {//This is ARE device - xdev->header.DDRChannelCount = xdev->header.DDRChannelCount - 1; //ARE is mapped like another DDR inside FPGA; map_connects as M04_AXI - } - if (ddr != xdev->header.DDRChannelCount) { - DRM_ERROR("XOCL: Feature ROM DDR channel count not consistent\n"); - return -ENODEV; - } - - if(xdev->header.FeatureBitMap & UNIFIED_PLATFORM) { - xdev->unified = true; - } - } - - printk(KERN_INFO "XOCL: ROM magic : %s\n", xdev->header.EntryPointString); - printk(KERN_INFO "XOCL: VBNV: %s", xdev->header.VBNVName); - printk(KERN_INFO "XOCL: DDR channel count : %d\n", xdev->header.DDRChannelCount); - printk(KERN_INFO "XOCL: DDR channel size: %d GB\n", xdev->header.DDRChannelSize); - printk(KERN_INFO "XOCL: Major Version: %d \n", xdev->header.MajorVersion); - printk(KERN_INFO "XOCL: Minor Version: %d \n", xdev->header.MinorVersion); - printk(KERN_INFO "XOCL: IPBuildID: %u\n", xdev->header.IPBuildID); - printk(KERN_INFO "XOCL: TimeSinceEpoch: %llx\n", xdev->header.TimeSinceEpoch); - printk(KERN_INFO "XOCL: FeatureBitMap: %llx\n", xdev->header.FeatureBitMap); - -// if(xdev->header.MajorVersion >= 10) -// printk(KERN_INFO "Printing DRBaseAddress: %llx\n", xdev->header.DRBaseAddress); - return 0; -} - -static int xocl_drm_load(struct drm_device *ddev, unsigned long flags) -{ - struct drm_xocl_dev *xdev; - unsigned i; - int result = 0; - unsigned long long segment = 0; - unsigned short ddr = 0; - unsigned long long ddr_size = 0; - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,4,0) - drm_dev_set_unique(ddev, dev_name(ddev->dev)); -#endif - - xdev = devm_kzalloc(ddev->dev, sizeof(*xdev), GFP_KERNEL); - if (!xdev) - return -ENOMEM; - xdev->ddev = ddev; - ddev->dev_private = xdev; - - xdev->res_start = pci_resource_start(xdev->ddev->pdev, 0); - xdev->res_len = pci_resource_end(xdev->ddev->pdev, 0) - xdev->res_start + 1; - - xdev->user_bar = pci_iomap(xdev->ddev->pdev, 0, xdev->res_len); - if (!xdev->user_bar) - return -EIO; - - result = probe_feature_rom(xdev); - if (result) - goto bar_cleanup; - - - if (xdev->unified) { - memset(&xdev->topology, 0, sizeof(struct drm_xocl_mem_topology)); - memset(&xdev->connectivity, 0, sizeof(struct drm_xocl_connectivity)); - memset(&xdev->layout, 0, sizeof(struct drm_xocl_layout)); - memset(&xdev->debug_layout, 0, sizeof(struct drm_xocl_debug_layout)); - } else { - printk(KERN_INFO "XOCL : non-unified ddr initialization.\n"); - ddr = xocl_ddr_channel_count(ddev); - ddr_size = xocl_ddr_channel_size(ddev); - - xdev->mm = devm_kzalloc(ddev->dev, sizeof(struct drm_mm) * ddr, GFP_KERNEL); - xdev->mm_usage_stat = devm_kzalloc(ddev->dev, sizeof(struct drm_xocl_mm_stat) * ddr, GFP_KERNEL); - if (!xdev->mm || !xdev->mm_usage_stat) { - result = -ENOMEM; - goto bar_cleanup; - } - - for (i = 0; i < ddr; i++) { - drm_mm_init(&xdev->mm[i], segment, ddr_size); - segment += ddr_size; - } - } - - mutex_init(&xdev->mm_lock); - // Now call XDMA core init - DRM_INFO("Enable XDMA core\n"); - result = xdma_init_glue(xdev); - if (result) { - DRM_ERROR("XDMA device initialization failed with err code: %d\n", result); - goto mm_cleanup; - } - - DRM_INFO("%s:%d:%s()", __FILE__, __LINE__, __func__); - - sema_init(&xdev->channel_sem[0], xdev->channel); - sema_init(&xdev->channel_sem[1], xdev->channel); - /* Initialize bit mask to represent individual channels */ - xdev->channel_bitmap[0] = BIT(xdev->channel); - xdev->channel_bitmap[0]--; - xdev->channel_bitmap[1] = xdev->channel_bitmap[0]; - - xdev->channel_usage[0] = devm_kzalloc(ddev->dev, sizeof(unsigned long long) * xdev->channel, GFP_KERNEL); - xdev->channel_usage[1] = devm_kzalloc(ddev->dev, sizeof(unsigned long long) * xdev->channel, GFP_KERNEL); - - if (!xdev->channel_usage[0] || !xdev->channel_usage[1]) { - result = -ENOMEM; - goto xdma_cleanup; - } - - xdev->cma_blk = xocl_cma; - - mutex_init(&xdev->stat_lock); - xdev->offline = false; - xocl_print_dev_info(xdev); - - //Init xocl sysfs - xocl_fini_sysfs(&xdev->ddev->pdev->dev); - result = xocl_init_sysfs(&xdev->ddev->pdev->dev); - if (result) { - DRM_ERROR("failed to create sysds file for xocl: %d\n", result); - goto all_cleanup; - } - - xocl_init_exec(xdev); - xdev->xvc.bar = xdev->user_bar; -#ifdef XOCL_BUILTIN_XVC - xocl_xvc_device_init(&xdev->xvc, &xdev->ddev->pdev->dev); -#endif - return result; - -all_cleanup: - mutex_destroy(&xdev->stat_lock); -xdma_cleanup: - xdma_fini_glue(xdev); -mm_cleanup: - if (!xdev->unified) { - for (i = 0; i < ddr; i++) { - drm_mm_takedown(&xdev->mm[i]); - } - } - DRM_INFO("%s:%d:%s()", __FILE__, __LINE__, __func__); -bar_cleanup: - pci_iounmap(xdev->ddev->pdev, xdev->user_bar); - xdev->user_bar = NULL; - return result; -} - -static int xocl_drm_unload(struct drm_device *drm) -{ - int i = 0; - struct drm_xocl_dev *xdev = drm->dev_private; - const unsigned short ddr = xocl_ddr_channel_count(drm); - - xdev->offline = true; -#ifdef XOCL_BUILTIN_XVC - xocl_xvc_device_fini(&xdev->xvc); -#endif - xocl_fini_exec(xdev); - - if(xdev->unified) { - for (i = 0; i < ddr; i++) { - if(xdev->topology.m_data[i].m_used) - drm_mm_takedown(&xdev->mm[i]); - } - vfree(xdev->topology.m_data); - vfree(xdev->topology.topology); - memset(&xdev->topology, 0, sizeof(xdev->topology)); - vfree(xdev->connectivity.connections); - memset(&xdev->connectivity, 0, sizeof(xdev->connectivity)); - vfree(xdev->layout.layout); - memset(&xdev->layout, 0, sizeof(xdev->layout)); - vfree(xdev->debug_layout.layout); - memset(&xdev->debug_layout, 0, sizeof(xdev->debug_layout)); - } else { - for (i = 0; i < ddr; i++) { - drm_mm_takedown(&xdev->mm[i]); - } - } - - mutex_destroy(&xdev->stat_lock); - mutex_destroy(&xdev->mm_lock); - - pci_iounmap(xdev->ddev->pdev, xdev->user_bar); - xdma_fini_glue(xdev); - xocl_fini_sysfs(&xdev->ddev->pdev->dev); - dev_set_drvdata(&xdev->ddev->pdev->dev, NULL); - return 0; -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) -static void xocl_drm_unload2(struct drm_device *drm) -{ - xocl_drm_unload(drm); -} -#endif - -static void xocl_free_object(struct drm_gem_object *obj) -{ - xocl_free_bo(obj); -} - -static int xocl_mmap(struct file *filp, struct vm_area_struct *vma) -{ - int ret; - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->minor->dev; - struct drm_xocl_dev *xdev = dev->dev_private; - struct mm_struct *mm = current->mm; - unsigned long vsize; - - //DRM_DEBUG("mmap operation 0x%lx 0x%lx 0x%lx\n", vma->vm_start, vma->vm_end, vma->vm_pgoff); - /* If the page offset is > than 4G, then let GEM handle that and do what - * it thinks is best,we will only handle page offsets less than 4G. - */ - if (likely(vma->vm_pgoff >= XOCL_FILE_PAGE_OFFSET)) { - ret = drm_gem_mmap(filp, vma); - if (ret) - return ret; - /* Clear VM_PFNMAP flag set by drm_gem_mmap() - * we have "struct page" for all backing pages for bo - */ - vma->vm_flags &= ~VM_PFNMAP; - /* Clear VM_IO flag set by drm_gem_mmap() - * it prevents gdb from accessing mapped buffers - */ - vma->vm_flags &= ~VM_IO; - vma->vm_flags |= VM_MIXEDMAP; - vma->vm_flags |= mm->def_flags; - vma->vm_pgoff = 0; - - /* Override pgprot_writecombine() mapping setup by drm_gem_mmap() - * which results in very poor read performance - */ - if (vma->vm_flags & (VM_READ | VM_MAYREAD)) - vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); - else - vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); - return ret; - } - - if (vma->vm_pgoff != 0) - return -EINVAL; - - vsize = vma->vm_end - vma->vm_start; - if (vsize > xdev->res_len) - return -EINVAL; - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - vma->vm_flags |= VM_IO; - vma->vm_flags |= VM_RESERVED; - - ret = io_remap_pfn_range(vma, vma->vm_start, - xdev->res_start >> PAGE_SHIFT, - vsize, vma->vm_page_prot); - DRM_INFO("io_remap_pfn_range ret code: %d", ret); - - return ret; - -} - -int xocl_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct drm_xocl_bo *xobj = to_xocl_bo(vma->vm_private_data); - loff_t num_pages; - unsigned int page_offset; - int ret = 0; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) - page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; -#else - page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; -#endif - - if (!xobj->pages) - return VM_FAULT_SIGBUS; - - num_pages = DIV_ROUND_UP(xobj->base.size, PAGE_SIZE); - if (page_offset > num_pages) - return VM_FAULT_SIGBUS; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) - ret = vm_insert_page(vma, vmf->address, xobj->pages[page_offset]); -#else - ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, xobj->pages[page_offset]); -#endif - switch (ret) { - case -EAGAIN: - case 0: - case -ERESTARTSYS: - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - default: - return VM_FAULT_SIGBUS; - } -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) -int xocl_gem_fault2(struct vm_fault *vmf) -{ - return xocl_gem_fault(vmf->vma, vmf); -} -#endif - -static int xocl_info_ioctl(struct drm_device *dev, - void *data, - struct drm_file *filp) -{ - struct drm_xocl_info *obj = data; - struct drm_xocl_dev *xdev = dev->dev_private; - struct pci_dev *pdev = xdev->ddev->pdev; - printk(KERN_INFO "%s %s INFO IOCTL \n", DRV_NAME, __FUNCTION__); - - obj->vendor = pdev->vendor; - obj->device = pdev->device; - obj->subsystem_vendor = pdev->subsystem_vendor; - obj->subsystem_device = pdev->subsystem_device; - obj->driver_version = XOCL_DRIVER_VERSION_NUMBER; - obj->pci_slot = PCI_SLOT(pdev->devfn); - - printk(KERN_INFO "%s %s PCI Slot: %d \n", DRV_NAME, __FUNCTION__, obj->pci_slot); - return 0; -} - -static int xocl_client_open(struct drm_device *dev, struct drm_file *filp) -{ - struct drm_xocl_dev *xdev = dev->dev_private; - struct drm_xocl_client_ctx *fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL); - if (!fpriv) - return -ENOMEM; - filp->driver_priv = fpriv; - mutex_init(&fpriv->lock); - atomic_set(&fpriv->trigger, 0); - xocl_track_ctx(xdev, fpriv); - DRM_INFO("Pid %d opened device\n", pid_nr(task_tgid(current))); - return 0; -} - -static void xocl_client_release(struct drm_device *dev, struct drm_file *filp) -{ - struct drm_xocl_dev *xdev = dev->dev_private; - struct drm_xocl_client_ctx *fpriv = filp->driver_priv; - int i; - unsigned bit; - - if (!fpriv) - return; - - xocl_untrack_ctx(xdev, fpriv); - if (!fpriv->eventfd_bitmap) - goto out; - - /* Clear all the eventfd structures */ - mutex_lock(&xdev->exec.user_msix_table_lock); - for (i = XOCL_USER_INTR_START; i < XOCL_USER_INTR_END; i++) { - bit = 1 << i; - if (!(fpriv->eventfd_bitmap & bit)) - continue; - xdma_user_interrupt_config(xdev, i, false); - eventfd_ctx_put(xdev->exec.user_msix_table[i]); - xdev->exec.user_msix_table[i] = NULL; - } - fpriv->eventfd_bitmap = 0; - mutex_unlock(&xdev->exec.user_msix_table_lock); -out: - mutex_destroy(&fpriv->lock); - kfree(fpriv); - filp->driver_priv = NULL; - DRM_INFO("Pid %d closed device\n", pid_nr(task_tgid(current))); -} - -static unsigned int xocl_poll(struct file *filp, poll_table *wait) -{ - int counter; - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->minor->dev; - struct drm_xocl_dev *xdev = dev->dev_private; - struct drm_xocl_client_ctx *fpriv = priv->driver_priv; - int ret = 0; - - BUG_ON(!fpriv); - poll_wait(filp, &xdev->exec.poll_wait_queue, wait); - /* - * Mutex lock protects from two threads from the same application - * calling poll concurrently using the same file handle - */ - mutex_lock(&fpriv->lock); - counter = atomic_read(&fpriv->trigger); - if (counter > 0) { - /* - * Use atomic here since the trigger may be incremented by interrupt - * handler running concurrently - */ - atomic_dec(&fpriv->trigger); - ret = POLLIN; - } - mutex_unlock(&fpriv->lock); - return ret; -} - -static const struct drm_ioctl_desc xocl_ioctls[] = { - DRM_IOCTL_DEF_DRV(XOCL_CREATE_BO, xocl_create_bo_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_USERPTR_BO, xocl_userptr_bo_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_MAP_BO, xocl_map_bo_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_SYNC_BO, xocl_sync_bo_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_INFO_BO, xocl_info_bo_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_PWRITE_BO, xocl_pwrite_bo_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_PREAD_BO, xocl_pread_bo_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_CTX, xocl_ctx_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_INFO, xocl_info_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_READ_AXLF, xocl_read_axlf_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_PWRITE_UNMGD, xocl_pwrite_unmgd_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_PREAD_UNMGD, xocl_pread_unmgd_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_USAGE_STAT, xocl_usage_stat_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_USER_INTR, xocl_user_intr_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), - DRM_IOCTL_DEF_DRV(XOCL_EXECBUF, xocl_execbuf_ioctl, - DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW), -}; - -static const struct file_operations xocl_driver_fops = { - .owner = THIS_MODULE, - .open = drm_open, - .mmap = xocl_mmap, - .poll = xocl_poll, - .read = drm_read, - .unlocked_ioctl = drm_ioctl, - .release = drm_release, -}; - -static const struct vm_operations_struct xocl_vm_ops = { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - .fault = xocl_gem_fault2, -#else - .fault = xocl_gem_fault, -#endif - .open = drm_gem_vm_open, - .close = drm_gem_vm_close, -}; - -static struct drm_driver xocl_drm_driver = { - .driver_features = DRIVER_GEM | DRIVER_PRIME | - DRIVER_RENDER, - .postclose = xocl_client_release, - .open = xocl_client_open, - .load = xocl_drm_load, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - .unload = xocl_drm_unload2, -#else - .unload = xocl_drm_unload, -#endif - .gem_free_object = xocl_free_object, - .gem_vm_ops = &xocl_vm_ops, - .prime_handle_to_fd = drm_gem_prime_handle_to_fd, - .prime_fd_to_handle = drm_gem_prime_fd_to_handle, - .gem_prime_import = drm_gem_prime_import, - .gem_prime_export = drm_gem_prime_export, - .gem_prime_get_sg_table = xocl_gem_prime_get_sg_table, - .gem_prime_import_sg_table = xocl_gem_prime_import_sg_table, - .gem_prime_vmap = xocl_gem_prime_vmap, - .gem_prime_vunmap = xocl_gem_prime_vunmap, - .ioctls = xocl_ioctls, - .num_ioctls = ARRAY_SIZE(xocl_ioctls), - .fops = &xocl_driver_fops, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0) - .set_busid = drm_pci_set_busid, -#endif - .name = XOCL_DRIVER_NAME, - .desc = XOCL_DRIVER_DESC, - .date = XOCL_DRIVER_DATE, - .major = XOCL_DRIVER_MAJOR, - .minor = XOCL_DRIVER_MINOR, - .patchlevel = XOCL_DRIVER_PATCHLEVEL, -}; - -// TODO: Umang remove the additional DRM_INFO's once this driver has been -// in production for some time. 07/06/2017. -static int xocl_driver_load(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct drm_device *dev; - int ret; - - DRM_INFO("%s:%d:%s()", __FILE__, __LINE__, __func__); - - dev = drm_dev_alloc(&xocl_drm_driver, &pdev->dev); - if (IS_ERR(dev)) - return PTR_ERR(dev); - - DRM_INFO("%s:%d:%s()", __FILE__, __LINE__, __func__); - ret = pci_enable_device(pdev); - if (ret) - goto err_free; - - DRM_INFO("%s:%d:%s()", __FILE__, __LINE__, __func__); - dev->pdev = pdev; - pci_set_drvdata(pdev, dev); - - DRM_INFO("%s:%d:%s()", __FILE__, __LINE__, __func__); - ret = drm_dev_register(dev, ent->driver_data); - DRM_INFO("%s:%d:%s()", __FILE__, __LINE__, __func__); - if (ret) { - goto err_reg; - } - - DRM_INFO("%s:%d:%s()", __FILE__, __LINE__, __func__); - return 0; - -err_reg: - DRM_INFO("%s:%d:%s()", __FILE__, __LINE__, __func__); - pci_disable_device(pdev); -err_free: - DRM_INFO("%s:%d:%s()", __FILE__, __LINE__, __func__); - drm_dev_unref(dev); - return ret; - -} - -static int xocl_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - DRM_INFO("%s:%d:%s()", __FILE__, __LINE__, __func__); - return xocl_driver_load(pdev, ent); -} - -static void xocl_pci_remove(struct pci_dev *pdev) -{ - struct drm_device *dev = pci_get_drvdata(pdev); - DRM_INFO("%s:%d:%s()", __FILE__, __LINE__, __func__); - pci_disable_device(pdev); - drm_put_dev(dev); -} - -static pci_ers_result_t xocl_error_detected(struct pci_dev *pdev, - pci_channel_state_t state) -{ - struct xdma_pci_dev *xpdev = dev_get_drvdata(&pdev->dev); - - switch (state) { - case pci_channel_io_normal: - return PCI_ERS_RESULT_CAN_RECOVER; - case pci_channel_io_frozen: - DRM_INFO("dev 0x%p,0x%p, frozen state error, reset controller\n", - pdev, xpdev); - //xdma_dev_disable(xpdev, false); - return PCI_ERS_RESULT_NEED_RESET; - case pci_channel_io_perm_failure: - DRM_INFO("dev 0x%p,0x%p, failure state error, req. disconnect\n", - pdev, xpdev); - return PCI_ERS_RESULT_DISCONNECT; - } - return PCI_ERS_RESULT_NEED_RESET; -} - -static pci_ers_result_t xocl_slot_reset(struct pci_dev *pdev) -{ - struct drm_device *ddev = pci_get_drvdata(pdev); - - DRM_INFO("0x%p restart after slot reset\n", ddev->dev_private); - pci_restore_state(pdev); - //queue_work(xdma_workq, &dev->reset_work); - return PCI_ERS_RESULT_RECOVERED; -} - -static void xocl_error_resume(struct pci_dev *pdev) -{ - struct drm_device *ddev = pci_get_drvdata(pdev); - - DRM_INFO("dev 0x%p,0x%p.\n", pdev, ddev->dev_private); - pci_cleanup_aer_uncorrect_error_status(pdev); -} - -void xocl_reset_notify(struct pci_dev *pdev, bool prepare) -{ - struct drm_device *ddev = dev_get_drvdata(&pdev->dev); - struct drm_xocl_dev *xdev; - - if(ddev) { - xdev = ddev->dev_private; - } - else { - DRM_ERROR("%s: %s ddev is null", DRV_NAME, __FUNCTION__); - return; - } - - if(xdev) - DRM_INFO("%s: %s dev 0x%p,0x%p, prepare %d.\n", DRV_NAME, __FUNCTION__, - pdev, ddev->dev_private, prepare); - else { - DRM_ERROR("%s: %s xdev is null", DRV_NAME, __FUNCTION__); - return; - } - - if (prepare) { - xdev->offline = true; - xdma_device_offline(pdev, xdev->xdma_handle); - } - else { - xdma_device_online(pdev, xdev->xdma_handle); - xdev->offline = false; - } -} -EXPORT_SYMBOL_GPL(xocl_reset_notify); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) -static void xocl_reset_prepare(struct pci_dev *pdev) -{ - xocl_reset_notify(pdev, true); -} - -static void xocl_reset_done(struct pci_dev *pdev) -{ - xocl_reset_notify(pdev, false); -} -#endif - -static const struct pci_error_handlers xocl_err_handler = { - .error_detected = xocl_error_detected, - .slot_reset = xocl_slot_reset, - .resume = xocl_error_resume, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) - .reset_prepare = xocl_reset_prepare, - .reset_done = xocl_reset_done, -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) - .reset_notify = xocl_reset_notify, -#endif -}; - - -static struct pci_driver xocl_pci_driver = { - .name = XOCL_DRIVER_NAME, - .id_table = pciidlist, - .probe = xocl_pci_probe, - .remove = xocl_pci_remove, - .err_handler = &xocl_err_handler, -}; - -/* init xilinx opencl drm platform */ -static int __init xocl_init(void) -{ - int result; -#ifdef XOCL_BUILTIN_XVC - result = xocl_xvc_chardev_init(); - if (result) { - DRM_ERROR("XVC registration failed with error code: %d\n", result); - return result; - } -#endif - result = pci_register_driver(&xocl_pci_driver); - if (result) { - DRM_ERROR("PCIe registration failed with error code: %d\n", result); - goto unregister_xvc; - } - -#ifdef XOCL_CMA_ALLOC - result = cma_init_reserved_mem(XOCL_CMA_BASE, XOCL_CMA_SIZE, 0, &xocl_cma); - if (result) { - DRM_ERROR("CMA region allocation for PCI Slave failed with error code: %d\n", result); - goto unregister_pci; - } -#endif - return 0; - -unregister_pci: - pci_unregister_driver(&xocl_pci_driver); - -unregister_xvc: -#ifdef XOCL_BUILTIN_XVC - xocl_xvc_chardev_exit(); -#endif - return result; -} - -static void __exit xocl_exit(void) -{ - DRM_INFO("%s:%d:%s()", __FILE__, __LINE__, __func__); - pci_unregister_driver(&xocl_pci_driver); -#ifdef XOCL_BUILTIN_XVC - xocl_xvc_chardev_exit(); -#endif -} - -module_init(xocl_init); -module_exit(xocl_exit); - - -MODULE_VERSION(__stringify(XOCL_DRIVER_MAJOR) "." - __stringify(XOCL_DRIVER_MINOR) "." - __stringify(XOCL_DRIVER_PATCHLEVEL)); - -MODULE_DESCRIPTION(XOCL_DRIVER_DESC); -MODULE_AUTHOR("Sonal Santan "); -MODULE_LICENSE("GPL"); - -// 67d7842dbbe25473c3c32b93c0da8047785f30d78e8a024de1b57352245f9689 diff --git a/sdk/linux_kernel_drivers/xocl/xocl_drv.h b/sdk/linux_kernel_drivers/xocl/xocl_drv.h deleted file mode 100644 index 20c34c1e..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_drv.h +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2016-2018 Xilinx, Inc - * - * Authors: - * Sonal Santan - * - * A GEM style device manager for PCIe based OpenCL accelerators. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _XCL_XOCL_DRV_H_ -#define _XCL_XOCL_DRV_H_ - -#include -#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,0,0) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include "xclfeatures.h" -#include "xclbin.h" -#include "xocl_ioctl.h" -#include "xocl_exec.h" -#include "xocl_xvc.h" -#include "libxdma.h" - -#define DRV_NAME "xocl" - -// For CMA kernel command line should be cma=nn[MG]@[start[MG] - -#define XOCL_BO_USERPTR (1 << 31) -#define XOCL_BO_IMPORT (1 << 30) -#define XOCL_BO_EXECBUF (1 << 29) -#define XOCL_BO_CMA (1 << 28) -#define XOCL_BO_DDR0 (1 << 0) -#define XOCL_BO_DDR1 (1 << 1) -#define XOCL_BO_DDR2 (1 << 2) -#define XOCL_BO_DDR3 (1 << 3) -#define XOCL_BO_ARE (1 << 4) //When the BO is imported from an ARE device. This is remote BO to be accessed over ARE - -#define XOCL_CHANNEL_COUNT 4 -#define XOCL_RD_MTX 0 -#define XOCL_WR_MTX 1 - -#define XOCL_CMA_BASE 0x200000000 // (8 GB) -#define XOCL_CMA_SIZE 0x020000000 // (512 MB) -#define XOCL_CMA_NAME "PCISlave" - -#define XOCL_ARE_HOP 0x400000000ull - -#define XOCL_FEATURE_ROM 0x0B0000 -#define XOCL_SCHD_HW 0x180000 -#define XOCL_SCHD_CMD_QUEUE 0x190000 -#define XOCL_SCHD_CMD_STATUS 0x190000 - -struct cma; - -struct drm_xocl_exec_metadata { - enum drm_xocl_execbuf_state state; - unsigned int index; -}; - -struct drm_xocl_bo { - /* drm base object */ - struct drm_gem_object base; - struct drm_mm_node *mm_node; - struct drm_xocl_exec_metadata metadata; - struct page **pages; - struct sg_table *sgt; - void *vmapping; - unsigned flags; -}; - -struct drm_xocl_unmgd { - struct page **pages; - struct sg_table *sgt; - unsigned int npages; - unsigned flags; -}; - -struct drm_xocl_mem_topology { - //TODO : check the first 4 entries - remove unneccessary ones. - int32_t bank_count; - struct mem_data* m_data; - u32 m_data_length; //length of the mem_data section. - uint64_t bank_size; //in KB. Currently only fixed sizes are supported. - uint64_t size; - struct mem_topology *topology; -}; - -struct drm_xocl_connectivity { - uint64_t size; - struct connectivity *connections; -}; - -struct drm_xocl_layout { - uint64_t size; - struct ip_layout *layout; -}; - -struct drm_xocl_debug_layout { - uint64_t size; - struct debug_ip_layout *layout; -}; - -struct drm_xocl_dev { - struct drm_device *ddev; - /* The feature Rom header */ - struct FeatureRomHeader header; - /* Number of bidirectional channels */ - unsigned channel; - /* Memory manager array, one per DDR channel */ - struct drm_mm *mm; - /* Memory manager lock */ - struct mutex mm_lock; - /* Semaphore, one for each direction */ - struct semaphore channel_sem[2]; - /* Channel usage bitmasks, one for each direction - * bit 1 indicates channel is free, bit 0 indicates channel is free - */ - volatile unsigned long channel_bitmap[2]; - unsigned long long *channel_usage[2]; - struct drm_xocl_mm_stat *mm_usage_stat; - struct xdma_dev *xdma_handle; - struct cma *cma_blk; - bool offline; - /* Lock for stats */ - struct mutex stat_lock; - void *__iomem user_bar; - phys_addr_t res_start; - resource_size_t res_len; - bool unified; //unified platform, populated from FeatureROM, - u64 unique_id_last_bitstream; - struct xocl_xvc xvc; - struct drm_xocl_exec_core exec; - struct drm_xocl_mem_topology topology; - struct drm_xocl_layout layout; - struct drm_xocl_debug_layout debug_layout; - struct drm_xocl_connectivity connectivity; -}; - -static inline struct drm_gem_object *xocl_gem_object_lookup(struct drm_device *dev, - struct drm_file *filp, - u32 handle) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) - return drm_gem_object_lookup(filp, handle); -#elif defined(RHEL_RELEASE_CODE) -#if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4) - return drm_gem_object_lookup(filp, handle); -#else - return drm_gem_object_lookup(dev, filp, handle); -#endif -#else - return drm_gem_object_lookup(dev, filp, handle); -#endif -} - -static inline struct drm_xocl_bo *to_xocl_bo(struct drm_gem_object *bo) -{ - return (struct drm_xocl_bo *)bo; -} - -static inline struct drm_xocl_dev *bo_xocl_dev(const struct drm_xocl_bo *bo) -{ - return bo->base.dev->dev_private; -} - -static inline unsigned xocl_bo_ddr_idx(unsigned flags) -{ - const unsigned ddr = flags & 0xf; - if (!ddr) - return 0xffffffff; - return __builtin_ctz(ddr); -} - -static inline unsigned short xocl_ddr_channel_count(const struct drm_device *drm) -{ - struct drm_xocl_dev *xdev = drm->dev_private; - struct drm_xocl_mem_topology *topology; - if(!xdev->unified) - return xdev->header.DDRChannelCount; - topology = &xdev->topology; - return topology->bank_count; -} - -static inline unsigned long long xocl_ddr_channel_size(const struct drm_device *drm) -{ - struct drm_xocl_dev *xdev = drm->dev_private; - struct drm_xocl_mem_topology *topology; - - if(!xdev->unified) { - /* Channel size is in GB */ - return xdev->header.DDRChannelSize * 0x40000000ull; - } - topology = &xdev->topology; - return topology->bank_size; -} - -static inline bool xocl_bo_userptr(const struct drm_xocl_bo *bo) -{ - return (bo->flags & XOCL_BO_USERPTR); -} - -static inline bool xocl_bo_import(const struct drm_xocl_bo *bo) -{ - return (bo->flags & XOCL_BO_IMPORT); -} - -static inline bool xocl_bo_execbuf(const struct drm_xocl_bo *bo) -{ - return (bo->flags & XOCL_BO_EXECBUF); -} - -static inline bool xocl_bo_cma(const struct drm_xocl_bo *bo) -{ - return (bo->flags & XOCL_BO_CMA); -} - -int xocl_create_bo_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); -int xocl_userptr_bo_ioctl(struct drm_device *dev, - void *data, - struct drm_file *filp); -int xocl_sync_bo_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); -int xocl_map_bo_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); -int xocl_info_bo_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); -int xocl_pwrite_bo_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); -int xocl_pread_bo_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); -int xocl_ctx_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); -int xocl_pwrite_unmgd_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); -int xocl_pread_unmgd_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); -int xocl_usage_stat_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); -int xocl_read_axlf_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); - - -void xocl_describe(const struct drm_xocl_bo *obj); - -void xocl_free_bo(struct drm_gem_object *obj); - -int xocl_migrate_bo(struct drm_device *ddev, const struct drm_xocl_bo *xobj, - enum drm_xocl_sync_bo_dir dir); - -int xocl_user_event(int irq, struct drm_xocl_dev *xdev); - -/** - * DMA-BUF support - */ -struct drm_gem_object *xocl_gem_prime_import_sg_table(struct drm_device *dev, - struct dma_buf_attachment *attach, struct sg_table *sgt); - -struct sg_table *xocl_gem_prime_get_sg_table(struct drm_gem_object *obj); - -void *xocl_gem_prime_vmap(struct drm_gem_object *obj); - -void xocl_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); - -/** - * Sysfs related functions - */ -int xocl_init_sysfs(struct device *dev); -void xocl_fini_sysfs(struct device *dev); - -/** - * DEBUG and EXEC support - */ - -int xocl_debug_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); -int xocl_execbuf_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); - -int xocl_user_intr_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp); - -#endif - -// 67d7842dbbe25473c3c32b93c0da8047785f30d78e8a024de1b57352245f9689 diff --git a/sdk/linux_kernel_drivers/xocl/xocl_exec.c b/sdk/linux_kernel_drivers/xocl/xocl_exec.c deleted file mode 100644 index c9e7865a..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_exec.c +++ /dev/null @@ -1,1426 +0,0 @@ -/* - * Copyright (C) 2017-2018 Xilinx, Inc - * - * Authors: - * Soren Soe - * - * A GEM style device manager for PCIe based OpenCL accelerators. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include -#include -#include -#include -#include "ert.h" -#include "xocl_drv.h" -#include "xocl_exec.h" -#include "xocl_xdma.h" - -//#define SCHED_VERBOSE -#define SCHED_THREAD_ENABLE - -#if 0 -static unsigned long zero = 0; -static unsigned long time_ns(void) -{ - struct timeval now; - do_gettimeofday(&now); - if (!zero) - zero = timeval_to_ns(&now); - return timeval_to_ns(&now) - zero; -} -#endif - -#define sched_error_on(xdev,expr,msg) \ -({ \ - unsigned int ret = 0; \ - if ((expr)) { \ - DRM_INFO("Assertion failed: %s:%d:%s:%s %s\n" \ - ,__FILE__,__LINE__,__FUNCTION__,#expr,msg); \ - xdev->exec.scheduler->error=1; \ - ret = 1; \ - } \ - (ret); \ -}) - - -#ifdef SCHED_VERBOSE -# define SCHED_DEBUG(msg) printk(msg) -# define SCHED_DEBUGF(format,...) printk(format, ##__VA_ARGS__) -#else -# define SCHED_DEBUG(msg) -# define SCHED_DEBUGF(format,...) -#endif - -#define XOCL_U32_MASK 0xFFFFFFFF - -/** - * struct xocl_sched: scheduler for xocl_cmd objects - * - * @scheduler_thread: thread associated with this scheduler - * @use_count: use count for this scheduler - * @wait_queue: conditional wait queue for scheduler thread - * @error: set to 1 to indicate scheduler error - * @command_queue: list of command objects managed by scheduler - * @intc: boolean flag set when there is a pending interrupt for command completion - * @poll: number of running commands in polling mode - */ -struct xocl_sched -{ - struct task_struct *scheduler_thread; - unsigned int use_count; - - wait_queue_head_t wait_queue; - unsigned int error; - - struct list_head command_queue; - atomic_t intc; /* pending interrupt */ - atomic_t poll; /* number of cmds to poll */ -}; - -static struct xocl_sched global_scheduler0; - -/** - * Command data used by scheduler - * - * @list: command object moves from list to list - * @bo: underlying drm buffer object - * @xdev: device handle - * @xs: scehduler processing this commands - * @state: state of command object per scheduling - * @cu_idx: index of CU executing this cmd object; used in penguin mode only - * @slot_idx: command queue index of this command object - * @packet: mapped ert packet object from user space - */ -struct xocl_cmd -{ - struct list_head list; - struct drm_xocl_bo *bo; - struct drm_xocl_dev *xdev; - struct xocl_sched *xs; - enum ert_cmd_state state; - int cu_idx; - int slot_idx; - - struct ert_packet *packet; -}; - -/** - * set_cmd_int_state() - Set internal command state used by scheduler only - * - * @xcmd: command to change internal state on - * @state: new command state per ert.h - */ -inline void -set_cmd_int_state(struct xocl_cmd* xcmd, enum ert_cmd_state state) -{ - SCHED_DEBUGF("->set_cmd_int_state(,%d)\n",state); - xcmd->state = state; - SCHED_DEBUG("<-set_cmd_int_state\n"); -} - -/** - * set_cmd_state() - Set both internal and external state of a command - * - * The state is reflected externally through the command packet - * as well as being captured in internal state variable - * - * @xcmd: command object - * @state: new state - */ -inline void -set_cmd_state(struct xocl_cmd* xcmd, enum ert_cmd_state state) -{ - SCHED_DEBUGF("->set_cmd_state(,%d)\n",state); - xcmd->state = state; - xcmd->packet->state = state; - SCHED_DEBUG("<-set_cmd_state\n"); -} - -/** - * List of free xocl_cmd objects. - * - * @free_cmds: populated with recycled xocl_cmd objects - * @cmd_mutex: mutex lock for cmd_list - * - * Command objects are recycled for later use and only freed when kernel - * module is unloaded. - */ -static LIST_HEAD(free_cmds); -static DEFINE_MUTEX(free_cmds_mutex); - -/** - * List of new pending xocl_cmd objects - * - * @pending_cmds: populated from user space with new commands for buffer objects - * @num_pending: number of pending commands - * - * Scheduler copies pending commands to its private queue when necessary - */ -static LIST_HEAD(pending_cmds); -static DEFINE_MUTEX(pending_cmds_mutex); -static atomic_t num_pending = ATOMIC_INIT(0); - -/** - * get_free_xocl_cmd() - Get a free command object - * - * Get from free/recycled list or allocate a new command if necessary. - * - * Return: Free command object - */ -static struct xocl_cmd* -get_free_xocl_cmd(void) -{ - struct xocl_cmd* cmd; - SCHED_DEBUG("-> get_free_xocl_cmd\n"); - mutex_lock(&free_cmds_mutex); - cmd=list_first_entry_or_null(&free_cmds,struct xocl_cmd,list); - if (cmd) - list_del(&cmd->list); - mutex_unlock(&free_cmds_mutex); - if (!cmd) - cmd = kmalloc(sizeof(struct xocl_cmd),GFP_KERNEL); - if (!cmd) - return ERR_PTR(-ENOMEM); - SCHED_DEBUGF("<- get_free_xocl_cmd %p\n",cmd); - return cmd; -} - -/** - * add_cmd() - Add a new command to pending list - * - * @xdev: device owning adding the buffer object - * @bo: buffer objects from user space from which new command is created - * - * Scheduler copies pending commands to its internal command queue. - * - * Return: 0 on success, -errno on failure - */ -static int -add_cmd(struct drm_xocl_dev *xdev, struct drm_xocl_bo* bo) -{ - struct xocl_cmd *xcmd = get_free_xocl_cmd(); - SCHED_DEBUG("-> add_cmd\n"); - xcmd->bo=bo; - xcmd->xdev=xdev; - xcmd->cu_idx=-1; - xcmd->slot_idx=-1; - xcmd->packet = (struct ert_packet*)bo->vmapping; - xcmd->xs = xdev->exec.scheduler; - set_cmd_state(xcmd,ERT_CMD_STATE_NEW); - mutex_lock(&pending_cmds_mutex); - list_add_tail(&xcmd->list,&pending_cmds); - mutex_unlock(&pending_cmds_mutex); - - /* wake scheduler */ - atomic_inc(&num_pending); - wake_up_interruptible(&xcmd->xs->wait_queue); - - SCHED_DEBUG("<- add_cmd\n"); - return 0; -} - -/** - * recycle_cmd() - recycle a command objects - * - * @xcmd: command object to recycle - * - * Command object is added to the freelist - * - * Return: 0 - */ -static int -recycle_cmd(struct xocl_cmd* xcmd) -{ - SCHED_DEBUGF("recycle %p\n",xcmd); - mutex_lock(&free_cmds_mutex); - list_del(&xcmd->list); - list_add_tail(&xcmd->list,&free_cmds); - mutex_unlock(&free_cmds_mutex); - return 0; -} - -/** - * delete_cmd_list() - reclaim memory for all allocated command objects - */ -static void -delete_cmd_list(void) -{ - struct xocl_cmd *xcmd; - struct list_head *pos, *next; - - mutex_lock(&free_cmds_mutex); - list_for_each_safe(pos, next, &free_cmds) { - xcmd = list_entry(pos, struct xocl_cmd, list); - list_del(pos); - kfree(xcmd); - } - mutex_unlock(&free_cmds_mutex); -} - - - -/** - * struct xocl_sched_ops: scheduler specific operations - * - * Scheduler can operate in MicroBlaze mode (mb/ert) or in penguin mode. This - * struct differentiates specific operations. The struct is per device node, - * meaning that one device can operate in ert mode while another can operate in - * penguin mode. - */ -struct xocl_sched_ops -{ - int (*submit) (struct xocl_cmd *xcmd); - void (*query) (struct xocl_cmd *xcmd); -}; - -static struct xocl_sched_ops mb_ops; -static struct xocl_sched_ops penguin_ops; - -/** - * is_ert() - Check if running in embedded (ert) mode. - * - * Return: %true of ert mode, %false otherwise - */ -inline unsigned int -is_ert(struct drm_xocl_dev *xdev) -{ - return xdev->exec.ops == &mb_ops; -} - -/** - * ffs_or_neg_one() - Find first set bit in a 32 bit mask. - * - * @mask: mask to check - * - * First LSBit is at position 0. - * - * Return: Position of first set bit, or -1 if none - */ -inline int -ffs_or_neg_one(u32 mask) -{ - if (!mask) - return -1; - return ffs(mask)-1; -} - -/** - * ffz_or_neg_one() - First first zero bit in bit mask - * - * @mask: mask to check - * Return: Position of first zero bit, or -1 if none - */ -inline int -ffz_or_neg_one(u32 mask) -{ - if (mask==XOCL_U32_MASK) - return -1; - return ffz(mask); -} - - -/** - * slot_size() - slot size per device configuration - * - * Return: Command queue slot size - */ -inline unsigned int -slot_size(struct drm_xocl_dev *xdev) -{ - return ERT_CQ_SIZE / xdev->exec.num_slots; -} - -/** - * cu_mask_idx() - CU mask index for a given cu index - * - * @cu_idx: Global [0..127] index of a CU - * Return: Index of the CU mask containing the CU with cu_idx - */ -inline unsigned int -cu_mask_idx(unsigned int cu_idx) -{ - return cu_idx >> 5; /* 32 cus per mask */ -} - -/** - * cu_idx_in_mask() - CU idx within its mask - * - * @cu_idx: Global [0..127] index of a CU - * Return: Index of the CU within the mask that contains it - */ -inline unsigned int -cu_idx_in_mask(unsigned int cu_idx) -{ - return cu_idx - (cu_mask_idx(cu_idx) << 5); -} - -/** - * cu_idx_from_mask() - Given CU idx within a mask return its global idx [0..127] - * - * @cu_idx: Index of CU with mask identified by mask_idx - * @mask_idx: Mask index of the has CU with cu_idx - * Return: Global cu_idx [0..127] - */ -inline unsigned int -cu_idx_from_mask(unsigned int cu_idx, unsigned int mask_idx) -{ - return cu_idx + (mask_idx << 5); -} - -/** - * slot_mask_idx() - Slot mask idx index for a given slot_idx - * - * @slot_idx: Global [0..127] index of a CQ slot - * Return: Index of the slot mask containing the slot_idx - */ -inline unsigned int -slot_mask_idx(unsigned int slot_idx) -{ - return slot_idx >> 5; -} - -/** - * slot_idx_in_mask() - Index of command queue slot within the mask that contains it - * - * @slot_idx: Global [0..127] index of a CQ slot - * Return: Index of slot within the mask that contains it - */ -inline unsigned int -slot_idx_in_mask(unsigned int slot_idx) -{ - return slot_idx - (slot_mask_idx(slot_idx) << 5); -} - -/** - * slot_idx_from_mask_idx() - Given slot idx within a mask, return its global idx [0..127] - * - * @slot_idx: Index of slot with mask identified by mask_idx - * @mask_idx: Mask index of the mask hat has slot with slot_idx - * Return: Global slot_idx [0..127] - */ -inline unsigned int -slot_idx_from_mask_idx(unsigned int slot_idx,unsigned int mask_idx) -{ - return slot_idx + (mask_idx << 5); -} - -/** - * opcode() - Command opcode - * - * @cmd: Command object - * Return: Opcode per command packet - */ -inline u32 -opcode(struct xocl_cmd* xcmd) -{ - return xcmd->packet->opcode; -} - -/** - * payload_size() - Command payload size - * - * @xcmd: Command object - * Return: Size in number of words of command packet payload - */ -inline u32 -payload_size(struct xocl_cmd *xcmd) -{ - return xcmd->packet->count; -} - -/** - * packet_size() - Command packet size - * - * @xcmd: Command object - * Return: Size in number of words of command packet - */ -inline u32 -packet_size(struct xocl_cmd *xcmd) -{ - return payload_size(xcmd) + 1; -} - -/** - * cu_masks() - Number of command packet cu_masks - * - * @xcmd: Command object - * Return: Total number of CU masks in command packet - */ -inline u32 -cu_masks(struct xocl_cmd *xcmd) -{ - struct ert_start_kernel_cmd *sk; - if (opcode(xcmd)!=ERT_START_KERNEL) - return 0; - sk = (struct ert_start_kernel_cmd *)xcmd->packet; - return 1 + sk->extra_cu_masks; -} - -/** - * regmap_size() - Size of regmap is payload size (n) minus the number of cu_masks - * - * @xcmd: Command object - * Return: Size of register map in number of words - */ -inline u32 -regmap_size(struct xocl_cmd* xcmd) -{ - return payload_size(xcmd) - cu_masks(xcmd); -} - -/** - * cu_idx_to_addr() - Convert CU idx into it relative bar address. - * - * @xdev: Device handle - * @cu_idx: Global CU idx - * Return: Address of CU relative to bar - */ -inline u32 -cu_idx_to_addr(struct drm_xocl_dev *xdev,unsigned int cu_idx) -{ - return (cu_idx << xdev->exec.cu_shift_offset) + xdev->exec.cu_base_addr; -} - -/** - * cu_idx_to_bitmask() - Compute the cu bitmask for cu_idx - * - * Subtract 32 * lower bitmasks prior to bitmask repsenting - * this index. For example, f.x cu_idx=67 - * 1 << (67 - (67>>5)<<5) = - * 1 << (67 - (2<<5)) = - * 1 << (67 - 64) = - * 1 << 3 = - * 0b1000 for position 4 in third bitmask - * - * @xdev: Device handle - * @cu_idx: Global index [0..127] of CU - * - * This function computes the bitmask for cu_idx in the mask that stores cu_idx - * - * Return: Bitmask with bit set for corresponding CU - */ -inline u32 -cu_idx_to_bitmask(struct drm_xocl_dev *xdev, u32 cu_idx) -{ - return 1 << (cu_idx - (cu_mask_idx(cu_idx)<<5)); -} - - -/** - * configure() - Configure the scheduler - * - * Process the configure command sent from user space. Only one process can - * configure the scheduler, so if scheduler is already configured, the - * function should verify that another process doesn't expect different - * configuration. - * - * Future may need ability to query current configuration so as to keep - * multiple processes in sync. - * - * Return: 0 on success, 1 on failure - */ -static int -configure(struct xocl_cmd *xcmd) -{ - struct drm_xocl_dev *xdev=xcmd->xdev; - struct ert_configure_cmd *cfg; - - if (sched_error_on(xdev,opcode(xcmd)!=ERT_CONFIGURE,"expected configure command")) - return 1; - - cfg = (struct ert_configure_cmd *)(xcmd->packet); - - if (xdev->exec.configured==0) { - SCHED_DEBUG("configuring scheduler\n"); - xdev->exec.num_slots = ERT_CQ_SIZE / cfg->slot_size; - xdev->exec.num_cus = cfg->num_cus; - xdev->exec.cu_shift_offset = cfg->cu_shift; - xdev->exec.cu_base_addr = cfg->cu_base_addr; - xdev->exec.num_cu_masks = ((xdev->exec.num_cus-1)>>5) + 1; - - if (cfg->ert) { - SCHED_DEBUG("++ configuring embedded scheduler mode\n"); - xdev->exec.ops = &mb_ops; - xdev->exec.polling_mode = cfg->polling; - xdev->exec.cq_interrupt = cfg->cq_int; - } - else { - SCHED_DEBUG("++ configuring penguin scheduler mode\n"); - xdev->exec.ops = &penguin_ops; - xdev->exec.polling_mode = 1; - } - - DRM_INFO("scheduler config ert(%d) slots(%d), cus(%d), cu_shift(%d), cu_base(0x%x), cu_masks(%d)\n" - ,is_ert(xdev) - ,xdev->exec.num_slots - ,xdev->exec.num_cus - ,xdev->exec.cu_shift_offset - ,xdev->exec.cu_base_addr - ,xdev->exec.num_cu_masks); - - return 0; - } - - DRM_INFO("reconfiguration of scheduler not supported\n"); - - return 1; -} - -/** - * acquire_slot_idx() - Acquire a slot index if available. Update slot status to busy - * so it cannot be reacquired. - * - * This function is called from scheduler thread - * - * Return: Command queue slot index, or -1 if none avaiable - */ -static int -acquire_slot_idx(struct drm_xocl_dev *xdev) -{ - unsigned int mask_idx=0, slot_idx=-1; - u32 mask; - SCHED_DEBUG("-> acquire_slot_idx\n"); - for (mask_idx=0; mask_idxexec.num_slot_masks; ++mask_idx) { - mask = xdev->exec.slot_status[mask_idx]; - slot_idx = ffz_or_neg_one(mask); - if (slot_idx==-1 || slot_idx_from_mask_idx(slot_idx,mask_idx)>=xdev->exec.num_slots) - continue; - xdev->exec.slot_status[mask_idx] ^= (1< release_slot_idx slot_status[%d]=0x%x, pos=%d\n" - ,mask_idx,xdev->exec.slot_status[mask_idx],pos); - xdev->exec.slot_status[mask_idx] ^= (1<exec.submitted_cmds[cmd_idx]; - if (sched_error_on(xdev,!xcmd,"no submtted cmd")) - return -1; - return xcmd->cu_idx; -} - -/** - * cu_done() - Check status of CU - * - * @cu_idx: Index of cu to check - * - * This function is called in polling mode only. The cu_idx - * is guaranteed to have been started - * - * Return: %true if cu done, %false otherwise - */ -inline int -cu_done(struct drm_xocl_dev *xdev, unsigned int cu_idx) -{ - u32 cu_addr = cu_idx_to_addr(xdev,cu_idx); - SCHED_DEBUGF("-> cu_done(,%d) checks cu at address 0x%x\n",cu_idx,cu_addr); - /* done is indicated by AP_DONE(2) alone or by AP_DONE(2) | AP_IDLE(4) - * but not by AP_IDLE itself. Since 0x10 | (0x10 | 0x100) = 0x110 - * checking for 0x10 is sufficient. */ - if (ioread32(xdev->user_bar + cu_addr) & 2) { - unsigned int mask_idx = cu_mask_idx(cu_idx); - unsigned int pos = cu_idx_in_mask(cu_idx); - xdev->exec.cu_status[mask_idx] ^= 1<exec.submitted_cmds[cmd_idx]; - u32 opc = 0; - SCHED_DEBUGF("-> cmd_done(,%d)\n",cmd_idx); - - if (sched_error_on(xdev,!xcmd || xcmd->slot_idx!=cmd_idx,"no command or missing slot index")) - return false; - - opc = opcode(xcmd); - if (opc==ERT_START_CU) { - int val = cu_done(xdev,get_cu_idx(xdev,cmd_idx)); - SCHED_DEBUGF("<- cmd_done (cu_done) returns %d\n",val); - return val; - } - if (opc==ERT_CONFIGURE) { - SCHED_DEBUG("<- cmd_done (configure) returns 1\n"); - return true; - } - SCHED_DEBUG("<- cmd_done returns 0\n"); - return false; -} - -/** - * notify_host() - Notify user space that a command is complete. - */ -static void -notify_host(struct xocl_cmd *xcmd) -{ - struct list_head *ptr; - struct drm_xocl_client_ctx *entry; - struct drm_xocl_dev *xdev = xcmd->xdev; - unsigned long flags = 0; - - SCHED_DEBUG("-> notify_host\n"); - - /* now for each client update the trigger counter in the context */ - spin_lock_irqsave(&xdev->exec.ctx_list_lock, flags); - list_for_each(ptr, &xdev->exec.ctx_list) { - entry = list_entry(ptr, struct drm_xocl_client_ctx, link); - atomic_inc(&entry->trigger); - } - spin_unlock_irqrestore(&xdev->exec.ctx_list_lock, flags); - /* wake up all the clients */ - wake_up_interruptible(&xdev->exec.poll_wait_queue); - SCHED_DEBUG("<- notify_host\n"); -} - -/** - * mark_cmd_complete() - Move a command to complete state - * - * Commands are marked complete in two ways - * 1. Through polling of CUs or polling of MB status register - * 2. Through interrupts from MB - * In both cases, the completed commands are residing in the completed_cmds - * list and the number of completed commands is reflected in num_completed. - * - * @xcmd: Command to mark complete - * - * The command is removed from the slot it occupies in the device command - * queue. The slot is released so new commands can be submitted. The host - * is notified that some command has completed. - */ -static void -mark_cmd_complete(struct xocl_cmd *xcmd) -{ - SCHED_DEBUGF("-> mark_cmd_complete(,%d)\n",xcmd->slot_idx); - xcmd->xdev->exec.submitted_cmds[xcmd->slot_idx] = NULL; - set_cmd_state(xcmd,ERT_CMD_STATE_COMPLETED); - if (xcmd->xdev->exec.polling_mode) - atomic_dec(&xcmd->xs->poll); - release_slot_idx(xcmd->xdev,xcmd->slot_idx); - notify_host(xcmd); - SCHED_DEBUGF("<- mark_cmd_complete\n"); -} - -/** - * mark_mask_complete() - Move all commands in mask to complete state - * - * @mask: Bitmask with queried statuses of commands - * @mask_idx: Index of the command mask. Used to offset the actual cmd slot index - */ -static void -mark_mask_complete(struct drm_xocl_dev *xdev, u32 mask, unsigned int mask_idx) -{ - int bit_idx=0,cmd_idx=0; - SCHED_DEBUGF("-> mark_mask_complete(,0x%x,%d)\n",mask,mask_idx); - if (!mask) - return; - for (bit_idx=0, cmd_idx=mask_idx<<5; bit_idx<32; mask>>=1,++bit_idx,++cmd_idx) - if (mask & 0x1) - mark_cmd_complete(xdev->exec.submitted_cmds[cmd_idx]); - SCHED_DEBUG("<- mark_mask_complete\n"); -} - -/** - * queued_to_running() - Move a command from queued to running state if possible - * - * @xcmd: Command to start - * - * Upon success, the command is not necessarily running. In ert mode the - * command will have been submitted to the embedded scheduler, whereas in - * penguin mode the command has been started on a CU. - * - * Return: %true if command was submitted to device, %false otherwise - */ -static int -queued_to_running(struct xocl_cmd *xcmd) -{ - int retval = false; - - SCHED_DEBUG("-> queued_to_running\n"); - - if (opcode(xcmd)==ERT_CONFIGURE) - configure(xcmd); - - if (xcmd->xdev->exec.ops->submit(xcmd)) { - set_cmd_int_state(xcmd,ERT_CMD_STATE_RUNNING); - if (xcmd->xdev->exec.polling_mode) - atomic_inc(&xcmd->xs->poll); - xcmd->xdev->exec.submitted_cmds[xcmd->slot_idx] = xcmd; - retval = true; - } - - SCHED_DEBUGF("<- queued_to_running returns %d\n",retval); - - return retval; -} - -/** - * running_to_complete() - Check status of running commands - * - * @xcmd: Command is in running state - * - * If a command is found to be complete, it marked complete prior to return - * from this function. - */ -static void -running_to_complete(struct xocl_cmd *xcmd) -{ - SCHED_DEBUG("-> running_to_complete\n"); - - xcmd->xdev->exec.ops->query(xcmd); - - SCHED_DEBUG("<- running_to_complete\n"); -} - -/** - * complete_to_free() - Recycle a complete command objects - * - * @xcmd: Command is in complete state - */ -static void -complete_to_free(struct xocl_cmd *xcmd) -{ - SCHED_DEBUG("-> complete_to_free\n"); - - drm_gem_object_unreference_unlocked(&xcmd->bo->base); - recycle_cmd(xcmd); - - SCHED_DEBUG("<- complete_to_free\n"); -} - -/** - * scheduler_queue_cmds() - Queue any pending commands - * - * The scheduler copies pending commands to its internal command queue where - * is is now in queued state. - */ -static void -scheduler_queue_cmds(struct xocl_sched *xs) -{ - struct xocl_cmd *xcmd; - - SCHED_DEBUG("-> scheduler_queue_cmds\n"); - mutex_lock(&pending_cmds_mutex); - while (!list_empty(&pending_cmds)) { - xcmd = list_first_entry(&pending_cmds,struct xocl_cmd,list); - if (xcmd->xs != xs) - continue; - list_del(&xcmd->list); - list_add_tail(&xcmd->list,&xs->command_queue); - set_cmd_int_state(xcmd,ERT_CMD_STATE_QUEUED); - atomic_dec(&num_pending); - } - mutex_unlock(&pending_cmds_mutex); - SCHED_DEBUG("<- scheduler_queue_cmds\n"); -} - -/** - * scheduler_iterator_cmds() - Iterate all commands in scheduler command queue - */ -static void -scheduler_iterate_cmds(struct xocl_sched *xs) -{ - struct xocl_cmd *xcmd; - struct list_head *pos, *next; - - SCHED_DEBUG("-> scheduler_iterate_cmds\n"); - list_for_each_safe(pos, next, &xs->command_queue) { - xcmd = list_entry(pos, struct xocl_cmd, list); - - if (xcmd->state == ERT_CMD_STATE_QUEUED) - queued_to_running(xcmd); - if (xcmd->state == ERT_CMD_STATE_RUNNING) - running_to_complete(xcmd); - if (xcmd->state == ERT_CMD_STATE_COMPLETED) - complete_to_free(xcmd); - - } - SCHED_DEBUG("<- scheduler_iterate_cmds\n"); -} - -/** - * scheduler_wait_condition() - Check status of scheduler wait condition - * - * Scheduler must wait (sleep) if - * 1. there are no pending commands - * 2. no pending interrupt from embedded scheduler - * 3. no pending complete commands in polling mode - * - * Return: 1 if scheduler must wait, 0 othewise - */ -static int -scheduler_wait_condition(struct xocl_sched *xs) -{ - if (kthread_should_stop() || xs->error) { - SCHED_DEBUG("scheduler wakes kthread_should_stop\n"); - return 0; - } - - if (atomic_read(&num_pending)) { - SCHED_DEBUG("scheduler wakes to copy new pending commands\n"); - return 0; - } - - if (atomic_read(&xs->intc)) { - SCHED_DEBUG("scheduler wakes on interrupt\n"); - atomic_set(&xs->intc,0); - return 0; - } - - if (atomic_read(&xs->poll)) { - SCHED_DEBUG("scheduler wakes to poll\n"); - return 0; - } - - SCHED_DEBUG("scheduler waits ...\n"); - return 1; -} - -/** - * scheduler_wait() - check if scheduler should wait - * - * See scheduler_wait_condition(). - */ -static void -scheduler_wait(struct xocl_sched *xs) -{ - wait_event_interruptible(xs->wait_queue,scheduler_wait_condition(xs)==0); -} - -/** - * scheduler_loop() - Run one loop of the scheduler - */ -static void -scheduler_loop(struct xocl_sched *xs) -{ - SCHED_DEBUG("scheduler_loop\n"); - - scheduler_wait(xs); - - if (xs->error) { - DRM_INFO("scheduler encountered unexpected error and exits\n"); - return; - } - - /* queue new pending commands */ - scheduler_queue_cmds(xs); - - /* iterate all commands */ - scheduler_iterate_cmds(xs); -} - -/** - * scheduler() - Command scheduler thread routine - */ -#if defined(__GNUC__) && !defined(SCHED_THREAD_ENABLE) -__attribute__((unused)) -#endif -static int -scheduler(void* data) -{ - struct xocl_sched *xs = (struct xocl_sched *)data; - while (!kthread_should_stop() && !xs->error) - scheduler_loop(xs); - DRM_INFO("%s:%d scheduler thread exits with value %d\n",__FILE__,__LINE__,xs->error); - return xs->error; -} - -/** - * init_scheduler_thread() - Initialize scheduler thread if necessary - * - * Return: 0 on success, -errno otherwise - */ -static int -init_scheduler_thread(void) -{ -#ifdef SCHED_THREAD_ENABLE - SCHED_DEBUGF("init_scheduler_thread use_count=%d\n",global_scheduler0.use_count); - if (global_scheduler0.use_count++) - return 0; - - init_waitqueue_head(&global_scheduler0.wait_queue); - global_scheduler0.error = 0; - - INIT_LIST_HEAD(&global_scheduler0.command_queue); - atomic_set(&global_scheduler0.intc,0); - atomic_set(&global_scheduler0.poll,0); - - global_scheduler0.scheduler_thread = kthread_run(scheduler,(void*)&global_scheduler0,"xocl-scheduler-thread0"); - if (IS_ERR(global_scheduler0.scheduler_thread)) { - int ret = PTR_ERR(global_scheduler0.scheduler_thread); - DRM_ERROR(__func__); - return ret; - } -#endif - return 0; -} - -/** - * fini_scheduler_thread() - Finalize scheduler thread if unused - * - * Return: 0 on success, -errno otherwise - */ -static int -fini_scheduler_thread(void) -{ - int retval = 0; - SCHED_DEBUGF("fini_scheduler_thread use_count=%d\n",global_scheduler0.use_count); - if (--global_scheduler0.use_count) - return 0; - - retval = kthread_stop(global_scheduler0.scheduler_thread); - - /* clear stale command objects if any */ - while (!list_empty(&pending_cmds)) { - struct xocl_cmd *xcmd = list_first_entry(&pending_cmds,struct xocl_cmd,list); - DRM_INFO("deleting stale pending cmd\n"); - list_del(&xcmd->list); - drm_gem_object_unreference_unlocked(&xcmd->bo->base); - } - while (!list_empty(&global_scheduler0.command_queue)) { - struct xocl_cmd *xcmd = list_first_entry(&global_scheduler0.command_queue,struct xocl_cmd,list); - DRM_INFO("deleting stale scheduler cmd\n"); - list_del(&xcmd->list); - drm_gem_object_unreference_unlocked(&xcmd->bo->base); - } - - delete_cmd_list(); - - return retval; -} - - -/** - * mb_query() - Check command status of argument command - * - * @xcmd: Command to check - * - * This function is for ERT mode. In polling mode, check the command status - * register containing the slot assigned to the command. In interrupt mode - * check the interrupting status register. The function checks all commands in - * the same command status register as argument command so more than one - * command may be marked complete by this function. - */ -static void -mb_query(struct xocl_cmd *xcmd) -{ - struct drm_xocl_dev *xdev = xcmd->xdev; - unsigned int cmd_mask_idx = slot_mask_idx(xcmd->slot_idx); - - SCHED_DEBUGF("-> mb_query slot_idx=%d, cmd_mask_idx=%d\n",xcmd->slot_idx,cmd_mask_idx); - - if (xdev->exec.polling_mode - || (cmd_mask_idx==0 && atomic_read(&xdev->exec.sr0)) - || (cmd_mask_idx==1 && atomic_read(&xdev->exec.sr1)) - || (cmd_mask_idx==2 && atomic_read(&xdev->exec.sr2)) - || (cmd_mask_idx==3 && atomic_read(&xdev->exec.sr3))) { - u32 csr_addr = ERT_STATUS_REGISTER_ADDR + (cmd_mask_idx<<2); - u32 mask = ioread32(xcmd->xdev->user_bar + csr_addr); - if (mask) - mark_mask_complete(xcmd->xdev,mask,cmd_mask_idx); - SCHED_DEBUGF("++ mb_query csr_addr=0x%x mask=0x%x\n",csr_addr,mask); - } - - SCHED_DEBUGF("<- mb_query\n"); -} - -/** - * penguin_query() - Check command status of argument command - * - * @xcmd: Command to check - * - * Function is called in penguin mode (no embedded scheduler). - */ -static void -penguin_query(struct xocl_cmd *xcmd) -{ - u32 opc = opcode(xcmd); - - SCHED_DEBUGF("-> penguin_queury() slot_idx=%d\n",xcmd->slot_idx); - - if (opc==ERT_CONFIGURE || (opc==ERT_START_CU && cu_done(xcmd->xdev,get_cu_idx(xcmd->xdev,xcmd->slot_idx)))) - mark_cmd_complete(xcmd); - - SCHED_DEBUG("<- penguin_queury\n"); -} - -/** - * mb_submit() - Submit a command the embedded scheduler command queue - * - * @xcmd: Command to submit - * Return: %true if successfully submitted, %false otherwise - */ -static int -mb_submit(struct xocl_cmd *xcmd) -{ - u32 slot_addr; - - SCHED_DEBUG("-> mb_submit\n"); - - xcmd->slot_idx = acquire_slot_idx(xcmd->xdev); - if (xcmd->slot_idx<0) { - SCHED_DEBUG("<- mb_submit returns 0\n"); - return 0; - } - - slot_addr = ERT_CQ_BASE_ADDR + xcmd->slot_idx*slot_size(xcmd->xdev); - SCHED_DEBUGF("++ mb_submit slot_idx=%d, slot_addr=0x%x\n",xcmd->slot_idx,slot_addr); - - /* write packet minus header */ - memcpy_toio(xcmd->xdev->user_bar + slot_addr + 4,xcmd->packet->data,(packet_size(xcmd)-1)*sizeof(u32)); - - /* write header */ - iowrite32(xcmd->packet->header,xcmd->xdev->user_bar + slot_addr); - - /* trigger interrupt to embedded scheduler if feature is enabled */ - if (xcmd->xdev->exec.cq_interrupt) { - u32 cq_int_addr = ERT_CQ_STATUS_REGISTER_ADDR + (slot_mask_idx(xcmd->slot_idx)<<2); - u32 mask = 1<slot_idx); - SCHED_DEBUGF("++ mb_submit writes slot mask 0x%x to CQ_INT register at addr 0x%x\n", - mask,cq_int_addr); - iowrite32(mask,xcmd->xdev->user_bar + cq_int_addr); - } - - SCHED_DEBUG("<- mb_submit returns 1\n"); - return 1; -} - -/** - * get_free_cu() - get index of first available CU per command cu mask - * - * @xcmd: command containing CUs to check for availability - * - * This function is called kernel software scheduler mode only, in embedded - * scheduler mode, the hardware scheduler handles the commands directly. - * - * Return: Index of free CU, -1 of no CU is available. - */ -static int -get_free_cu(struct xocl_cmd *xcmd) -{ - int mask_idx=0; - SCHED_DEBUG("-> get_free_cu\n"); - for (mask_idx=0; mask_idxxdev->exec.num_cu_masks; ++mask_idx) { - u32 cmd_mask = xcmd->packet->data[mask_idx]; /* skip header */ - u32 busy_mask = xcmd->xdev->exec.cu_status[mask_idx]; - int cu_idx = ffs_or_neg_one((cmd_mask | busy_mask) ^ busy_mask); - if (cu_idx>=0) { - xcmd->xdev->exec.cu_status[mask_idx] ^= 1<xdev->user_bar; - u32 cu_addr = cu_idx_to_addr(xcmd->xdev,cu_idx); - u32 size = regmap_size(xcmd); - struct ert_start_kernel_cmd *ecmd = (struct ert_start_kernel_cmd *)xcmd->packet; - - SCHED_DEBUGF("-> configure_cu cu_idx=%d, cu_addr=0x%x, regmap_size=%d\n" - ,cu_idx,cu_addr,size); - - /* write register map, but skip first word (AP_START) */ - /* can't get memcpy_toio to work */ - /* memcpy_toio(user_bar + cu_addr + 4,ecmd->data + ecmd->extra_cu_masks + 1,(size-1)*4); */ - for (i=1; idata + ecmd->extra_cu_masks + i),user_bar + cu_addr + (i<<2)); - - /* start CU at base + 0x0 */ - iowrite32(0x1,user_bar + cu_addr); - - SCHED_DEBUG("<- configure_cu\n"); -} - -/** - * penguin_submit() - penguin submit of a command - * - * @xcmd: command to submit - * - * Special processing for configure command. Configuration itself is - * done/called by queued_to_running before calling penguin_submit. In penguin - * mode configuration need to ensure that the command is retired properly by - * scheduler, so assign it a slot index and let normal flow continue. - * - * Return: %true on successful submit, %false otherwise - */ -static int -penguin_submit(struct xocl_cmd *xcmd) -{ - SCHED_DEBUG("-> penguin_submit\n"); - - /* configuration was done by submit_cmds, ensure the cmd retired properly */ - if (opcode(xcmd)==ERT_CONFIGURE) { - xcmd->slot_idx = acquire_slot_idx(xcmd->xdev); - SCHED_DEBUG("<- penguin_submit (configure)\n"); - return 1; - } - - if (opcode(xcmd)!=ERT_START_CU) - return 0; - - /* extract cu list */ - xcmd->cu_idx = get_free_cu(xcmd); - if (xcmd->cu_idx<0) - return 0; - - xcmd->slot_idx = acquire_slot_idx(xcmd->xdev); - if (xcmd->slot_idx<0) - return 0; - - /* found free cu, transfer regmap and start it */ - configure_cu(xcmd,xcmd->cu_idx); - - SCHED_DEBUGF("<- penguin_submit cu_idx=%d slot=%d\n",xcmd->cu_idx,xcmd->slot_idx); - - return 1; -} - - -/** - * mb_ops: operations for ERT scheduling - */ -static struct xocl_sched_ops mb_ops = { - .submit = mb_submit, - .query = mb_query, -}; - -/** - * penguin_ops: operations for kernel mode scheduling - */ -static struct xocl_sched_ops penguin_ops = { - .submit = penguin_submit, - .query = penguin_query, -}; - -/** - * xocl_user_event() - Interrupt service routine for MB interrupts - * - * Called by xocl_xdma_user_isr() which is our stub for user ISR registered with libxdma - * Kernel doc says eventfd_signal() does not sleep so it should be okay to call this in ISR - * TODO: Add support for locking so xdev->user_msix_table[irq] is not deleted/changed by - * xocl_user_intr_ioctl() while we are using it. - */ -int -xocl_user_event(int irq, struct drm_xocl_dev *xdev) -{ - SCHED_DEBUGF("xocl_user_event %d\n",irq); - if (irq>=XOCL_CSR_INTR0 && irq<=XOCL_CSR_INTR3 && is_ert(xdev) && !xdev->exec.polling_mode) { - - if (irq==0) - atomic_set(&xdev->exec.sr0,1); - else if (irq==1) - atomic_set(&xdev->exec.sr1,1); - else if (irq==2) - atomic_set(&xdev->exec.sr2,1); - else if (irq==3) - atomic_set(&xdev->exec.sr3,1); - - /* wake up all scheduler ... currently one only */ - atomic_set(&global_scheduler0.intc,1); - wake_up_interruptible(&global_scheduler0.wait_queue); - return 0; - } - if (!xdev->exec.user_msix_table[irq]) - return -EFAULT; - if (eventfd_signal(xdev->exec.user_msix_table[irq], 1) == 1) - return 0; - return -EFAULT; -} - - -/** - * xocl_execbuf_ioctl() - Entry point for exec buffer. - * - * @dev: Device node calling execbuf - * @data: Payload - * @filp: - * - * Function adds exec buffer to the pending list of commands - * - * Return: 0 on success, -errno otherwise - */ -int -xocl_execbuf_ioctl(struct drm_device *dev, - void *data, - struct drm_file *filp) -{ - struct drm_gem_object *obj; - struct drm_xocl_bo *xobj; - struct drm_xocl_dev *xdev = dev->dev_private; - struct drm_xocl_execbuf *args = data; - int ret = 0; - - SCHED_DEBUG("-> xocl_execbuf_ioctl\n"); - obj = xocl_gem_object_lookup(dev, filp, args->exec_bo_handle); - if (!obj) { - DRM_INFO("Failed to look up GEM BO %d\n", args->exec_bo_handle); - return -ENOENT; - } - - xobj = to_xocl_bo(obj); - if (!xocl_bo_execbuf(xobj)) { - ret = -EINVAL; - goto out; - } - - /* Add the command to pending list */ - if (add_cmd(xdev,xobj)) { - ret = -EINVAL; - goto out; - } - - /* we keep a bo reference which is released later when the bo is retired when task is done */ - SCHED_DEBUG("<- xocl_execbuf_ioctl\n"); - return ret; -out: - drm_gem_object_unreference_unlocked(&xobj->base); - return ret; -} - -/** - * xocl_init_exec() - Initialize the command execution for device - * - * @xdev: Device node to initialize - * - * Return: 0 on success, -errno otherwise - */ -int -xocl_init_exec(struct drm_xocl_dev *xdev) -{ - unsigned int i; - - mutex_init(&xdev->exec.user_msix_table_lock); - spin_lock_init(&xdev->exec.ctx_list_lock); - INIT_LIST_HEAD(&xdev->exec.ctx_list); - init_waitqueue_head(&xdev->exec.poll_wait_queue); - - xdev->exec.scheduler = &global_scheduler0; - - for (i=0; iexec.submitted_cmds[i] = NULL; - - xdev->exec.num_slots = 16; - xdev->exec.num_cus = 0; - xdev->exec.cu_base_addr = 0; - xdev->exec.cu_shift_offset = 0; - xdev->exec.cq_interrupt = 0; - xdev->exec.polling_mode = 1; - - for (i=0; iexec.slot_status[i] = 0; - xdev->exec.num_slot_masks = 1; - - for (i=0; iexec.cu_status[i] = 0; - xdev->exec.num_cu_masks = 0; - - xdma_user_interrupt_config(xdev, XOCL_CSR_INTR0, true); - xdma_user_interrupt_config(xdev, XOCL_CSR_INTR1, true); - xdma_user_interrupt_config(xdev, XOCL_CSR_INTR2, true); - xdma_user_interrupt_config(xdev, XOCL_CSR_INTR3, true); - xdev->exec.ops = &penguin_ops; - - atomic_set(&xdev->exec.sr0,0); - atomic_set(&xdev->exec.sr1,0); - atomic_set(&xdev->exec.sr2,0); - atomic_set(&xdev->exec.sr3,0); - - init_scheduler_thread(); - return 0; -} - -/** - * xocl_fini_exec() - Finalize the command execution for device - * - * @xdev: Device node to finalize - * - * Return: 0 on success, -errno otherwise - */ -int xocl_fini_exec(struct drm_xocl_dev *xdev) -{ - int i; - - fini_scheduler_thread(); - - xdma_user_interrupt_config(xdev, XOCL_CSR_INTR0, false); - xdma_user_interrupt_config(xdev, XOCL_CSR_INTR1, false); - xdma_user_interrupt_config(xdev, XOCL_CSR_INTR2, false); - xdma_user_interrupt_config(xdev, XOCL_CSR_INTR3, false); - for (i=0; i<16; i++) { - xdma_user_interrupt_config(xdev, i, false); - if (xdev->exec.user_msix_table[i]) - eventfd_ctx_put(xdev->exec.user_msix_table[i]); - } - mutex_destroy(&xdev->exec.user_msix_table_lock); - - return 0; -} diff --git a/sdk/linux_kernel_drivers/xocl/xocl_exec.h b/sdk/linux_kernel_drivers/xocl/xocl_exec.h deleted file mode 100644 index e36f3990..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_exec.h +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright (C) 2017-2018 Xilinx, Inc - * - * Authors: - * Sonal Santan - * - * Compute unit execution, interrupt management and client context core data structures. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _XCL_XOCL_EXEC_H_ -#define _XCL_XOCL_EXEC_H_ - -#include -#include -#include -#include - -#define XOCL_CSR_INTR0 0 -#define XOCL_CSR_INTR1 1 -#define XOCL_CSR_INTR2 2 -#define XOCL_CSR_INTR3 3 - -#define XOCL_USER_INTR_START 4 -#define XOCL_USER_INTR_END 16 - -#define XOCL_MAX_SLOTS 128 -#define XOCL_MAX_CUS 128 -#define XOCL_MAX_U32_SLOT_MASKS (((XOCL_MAX_SLOTS-1)>>5) + 1) -#define XOCL_MAX_U32_CU_MASKS (((XOCL_MAX_CUS-1)>>5) + 1) - -struct eventfd_ctx; -struct drm_xocl_dev; - -struct drm_xocl_client_ctx { - struct list_head link; - atomic_t trigger; - /* - * Bitmap to indicate all the user interrupts registered. These are unmanaged - * interrupts directly used by the non-OpenCL application. The corresponding - * eventfd objects are stored in drm_xocl_dev::user_msix_table - */ - unsigned int eventfd_bitmap; - struct mutex lock; -}; - -/** - * struct drm_xocl_exec_core: Core data structure for command execution on a device - * - * @user_msix_table: Eventfd table for user interrupts - * @user_msix_table_lock: Eventfd table lock - * @ctx_list: Context list populated with device context - * @ctx_list_lock: Context list lock - * @poll_wait_queue: Wait queue for device polling - * @scheduler: Command queue scheduler - * @submitted_cmds: Tracking of command submitted for execution on this device - * @num_slots: Number of command queue slots - * @num_cus: Number of CUs in loaded program - * @cu_shift_offset: CU idx to CU address shift value - * @cu_base_addr: Base address of CU address space - * @polling_mode: If set then poll for command completion - * @cq_interrupt: If set then trigger interrupt to MB on new commands - * @configured: Flag to indicate that the core data structure has been initialized - * @slot_status: Bitmap to track status (busy(1)/free(0)) slots in command queue - * @num_slot_masks: Number of slots status masks used (computed from @num_slots) - * @cu_status: Bitmap to track status (busy(1)/free(0)) of CUs. Unused in ERT mode. - * @num_cu_masks: Number of CU masks used (computed from @num_cus) - * @sr0: If set, then status register [0..31] is pending with completed commands (ERT only). - * @sr1: If set, then status register [32..63] is pending with completed commands (ERT only). - * @sr2: If set, then status register [64..95] is pending with completed commands (ERT only). - * @sr3: If set, then status register [96..127] is pending with completed commands (ERT only). - * @ops: Scheduler operations vtable - */ -struct drm_xocl_exec_core { - struct eventfd_ctx *user_msix_table[16]; - struct mutex user_msix_table_lock; - - struct list_head ctx_list; - spinlock_t ctx_list_lock; - wait_queue_head_t poll_wait_queue; - - struct xocl_sched *scheduler; - - struct xocl_cmd *submitted_cmds[XOCL_MAX_SLOTS]; - - unsigned int num_slots; - unsigned int num_cus; - unsigned int cu_shift_offset; - u32 cu_base_addr; - unsigned int polling_mode; - unsigned int cq_interrupt; - unsigned int configured; - - /* Bitmap tracks busy(1)/free(0) slots in cmd_slots*/ - u32 slot_status[XOCL_MAX_U32_SLOT_MASKS]; - unsigned int num_slot_masks; /* ((num_slots-1)>>5)+1 */ - - u32 cu_status[XOCL_MAX_U32_CU_MASKS]; - unsigned int num_cu_masks; /* ((num_cus-1)>>5+1 */ - - /* Status register pending complete. Written by ISR, cleared by scheduler */ - atomic_t sr0; - atomic_t sr1; - atomic_t sr2; - atomic_t sr3; - - /* Operations for dynamic indirection dependt on MB or kernel scheduler */ - struct xocl_sched_ops* ops; -}; - -int xocl_init_exec(struct drm_xocl_dev *xdev); -int xocl_fini_exec(struct drm_xocl_dev *xdev); - -int xocl_init_test_thread(struct drm_xocl_dev *xdev); -int xocl_fini_test_thread(struct drm_xocl_dev *xdev); - -void xocl_track_ctx(struct drm_xocl_dev *xdev, struct drm_xocl_client_ctx *fpriv); -void xocl_untrack_ctx(struct drm_xocl_dev *xdev, struct drm_xocl_client_ctx *fpriv); - -#endif diff --git a/sdk/linux_kernel_drivers/xocl/xocl_ioctl.c b/sdk/linux_kernel_drivers/xocl/xocl_ioctl.c deleted file mode 100644 index 0de72558..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_ioctl.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Copyright (C) 2016-2018 Xilinx, Inc - * - * Authors: - * Sonal Santan - * - * A GEM style device manager for PCIe based OpenCL accelerators. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,0,0) -#include -#endif -#include -#include -#include "xocl_drv.h" -#include "xocl_ioctl.h" -#include "xocl_xdma.h" - -static const struct axlf_section_header* get_axlf_section(const struct axlf* top, enum axlf_section_kind kind) -{ - int i = 0; - printk(KERN_INFO "Trying to find section header for axlf section %d", kind); - for(i = 0; i < top->m_header.m_numSections; i++) - { - printk(KERN_INFO "Section is %d",top->m_sections[i].m_sectionKind); - if(top->m_sections[i].m_sectionKind == kind) { - printk(KERN_INFO "Found section header for axlf"); - return &top->m_sections[i]; - } - } - printk(KERN_INFO "Did NOT find section header for axlf section %d", kind); - return NULL; -} - - -static long xclbin_precheck_cleanup(struct drm_device *dev, int preserve_mem) -{ - struct drm_xocl_dev *xdev = dev->dev_private; - struct drm_xocl_mem_topology *topology = &xdev->topology; - long err = 0; - short ddr = 0; - unsigned i = 0; - printk(KERN_INFO "%s XOCL: Existing bank count = %d\n", __FUNCTION__, topology->bank_count); - ddr = 0; - if( !preserve_mem ) { // Data Retention - for (i= 0; i < topology->bank_count; i++) { - if (topology->m_data[i].m_used) { - ddr++; - if (xdev->mm_usage_stat[ddr -1].bo_count !=0 ) { - err = -EBUSY; - printk(KERN_INFO "%s The ddr %d has pre-existing buffer allocations, please exit and re-run.\n", __FUNCTION__, ddr -1); - return err; - } - } - } - - printk(KERN_INFO "XOCL: Marker 2.1\n"); - //Cleanup the topology struct from the previous xclbin - ddr = xocl_ddr_channel_count(dev); - printk( KERN_INFO "%s XOCL: xocl_ddr_channel_count(dev): %d\n", __FUNCTION__, ddr ); - for (i = 0; i < ddr; i++) { - if(topology->m_data[i].m_used) { - printk(KERN_INFO "Taking down DDR : %d", i); - drm_mm_takedown(&xdev->mm[i]); - } - } - - vfree(topology->m_data); - vfree(topology->topology); - memset(topology, 0, sizeof(struct drm_xocl_mem_topology)); - } - - vfree(xdev->connectivity.connections); - memset(&xdev->connectivity, 0, sizeof(xdev->connectivity)); - vfree(xdev->layout.layout); - memset(&xdev->layout, 0, sizeof(xdev->layout)); - vfree(xdev->debug_layout.layout); - memset(&xdev->debug_layout, 0, sizeof(xdev->debug_layout)); - - return err; -} - - -int xocl_read_axlf_ioctl(struct drm_device *dev, - void *data, - struct drm_file *filp) -{ - struct drm_xocl_axlf *axlf_obj_ptr = data; - struct drm_xocl_dev *xdev = dev->dev_private; - long err = 0; - unsigned i = 0; - uint64_t copy_buffer_size = 0; - struct axlf* copy_buffer = 0; - const struct axlf_section_header *memHeader = 0; - char __user *buffer =0; - int32_t bank_count = 0; - short ddr = 0; - struct axlf bin_obj; - int preserve_mem; - struct drm_xocl_mem_topology *topology; - struct drm_xocl_mem_topology new_topology; - new_topology.topology = NULL; - new_topology.m_data = NULL; - - printk(KERN_INFO "%s %s READ_AXLF IOCTL \n", DRV_NAME, __FUNCTION__); - - if(!xdev->unified) { - printk(KERN_INFO "XOCL: not unified dsa"); - return err; - } - - printk(KERN_INFO "XOCL: Marker 0 %p\n", data); - if (copy_from_user((void *)&bin_obj, (void*)axlf_obj_ptr->xclbin, sizeof(struct axlf))) - return -EFAULT; - if (memcmp(bin_obj.m_magic, "xclbin2", 8)) - return -EINVAL; - //Ignore timestamp matching for AWS platform - if(bin_obj.m_header.m_featureRomTimeStamp != xdev->header.TimeSinceEpoch && strstr(xdev->header.VBNVName, "xilinx_aw") == NULL) { - printk(KERN_ERR "TimeStamp of ROM did not match Xclbin\n"); - return -EINVAL; - } - - printk(KERN_INFO "XOCL: VBNV and TimeStamps matched\n"); - - if(bin_obj.m_uniqueId == xdev->unique_id_last_bitstream) { - printk(KERN_INFO "Skipping repopulating topology, connectivity,ip_layout data\n"); - return err; - } - - //Copy from user space and proceed. - copy_buffer_size = (bin_obj.m_header.m_numSections)*sizeof(struct axlf_section_header) + sizeof(struct axlf); - copy_buffer = (struct axlf*)vmalloc(copy_buffer_size); - if(!copy_buffer) { - printk(KERN_ERR "Unable to create copy_buffer"); - return -EFAULT; - } - printk(KERN_INFO "XOCL: Marker 1\n"); - - if (copy_from_user((void *)copy_buffer, (void *)axlf_obj_ptr->xclbin, copy_buffer_size)) { - err = -EFAULT; - goto done; - } - - buffer = (char __user *)axlf_obj_ptr->xclbin; - err = !access_ok(VERIFY_READ, buffer, bin_obj.m_header.m_length); - if (err) { - err = -EFAULT; - goto done; - } - - //--- - printk(KERN_INFO "Finding MEM_TOPOLOGY section\n"); - memHeader = get_axlf_section(copy_buffer, MEM_TOPOLOGY); - if (memHeader == 0) { - printk(KERN_INFO "Did not find MEM_TOPOLOGY section.\n"); - err = -EINVAL; - goto done; - } - printk(KERN_INFO "XOCL: Marker 2\n"); - - printk(KERN_INFO "%s XOCL: MEM_TOPOLOGY offset = %llx, size = %llx\n", __FUNCTION__, memHeader->m_sectionOffset , memHeader->m_sectionSize); - - if((memHeader->m_sectionOffset + memHeader->m_sectionSize) > bin_obj.m_header.m_length) { - err = -EINVAL; - goto done; - } - - buffer = (char __user *)axlf_obj_ptr->xclbin; - buffer += memHeader->m_sectionOffset; - - new_topology.topology = vmalloc(memHeader->m_sectionSize); - err = copy_from_user(new_topology.topology, buffer, memHeader->m_sectionSize); - if (err) - goto done; - - get_user(bank_count, buffer); - new_topology.size = memHeader->m_sectionSize; - new_topology.bank_count = bank_count; - new_topology.m_data_length = bank_count*sizeof(struct mem_data); - buffer += offsetof(struct mem_topology, m_mem_data); - new_topology.m_data = vmalloc(new_topology.m_data_length); - err = copy_from_user(new_topology.m_data, buffer, bank_count*sizeof(struct mem_data)); - if (err ) - goto done; - - //check for null pointer, then do mem compare - preserve_mem = 0; - if( xdev->topology.topology != NULL ) { - // m_data can be of different length but we would not compare them if topology match fails - if( !memcmp(new_topology.topology, xdev->topology.topology, memHeader->m_sectionSize) && - !memcmp(new_topology.m_data, xdev->topology.m_data, new_topology.bank_count*sizeof(struct mem_data) ) ) { - printk( KERN_INFO "XOCL: MEM_TOPOLOGY match, preserve mem_topology.\n" ); - preserve_mem = 1; - } else { - printk( KERN_INFO "XOCL: MEM_TOPOLOGY mismatch, do not preserve mem_topology.\n" ); - } - } - - //Switching the xclbin, make sure none of the buffers are used. - err = xclbin_precheck_cleanup(dev, preserve_mem); - if(err) - goto done; - - if( !preserve_mem ) { // Data Retention - xdev->topology.topology = new_topology.topology; - xdev->topology.size = new_topology.size; - xdev->topology.bank_count = new_topology.bank_count; - xdev->topology.m_data_length = new_topology.m_data_length; - xdev->topology.m_data = new_topology.m_data; - new_topology.topology = NULL; - new_topology.m_data = NULL; - } - - //---- - printk(KERN_INFO "Finding IP_LAYOUT section\n"); - memHeader = get_axlf_section(copy_buffer, IP_LAYOUT); - if (memHeader == 0) { - printk(KERN_INFO "Did not find IP_LAYOUT section.\n"); - } else { - printk(KERN_INFO "%s XOCL: IP_LAYOUT offset = %llx, size = %llx, xclbin length = %llx\n", __FUNCTION__, memHeader->m_sectionOffset , memHeader->m_sectionSize, bin_obj.m_header.m_length); - - if((memHeader->m_sectionOffset + memHeader->m_sectionSize) > bin_obj.m_header.m_length) { - printk(KERN_INFO "%s XOCL: IP_LAYOUT section extends beyond xclbin boundary %llx\n", __FUNCTION__, bin_obj.m_header.m_length); - err = -EINVAL; - goto done; - } - printk(KERN_INFO "XOCL: Marker 3.1\n"); - buffer += memHeader->m_sectionOffset; - xdev->layout.layout = vmalloc(memHeader->m_sectionSize); - err = copy_from_user(xdev->layout.layout, buffer, memHeader->m_sectionSize); - printk(KERN_INFO "XOCL: Marker 3.2\n"); - if (err) - goto done; - xdev->layout.size = memHeader->m_sectionSize; - printk(KERN_INFO "XOCL: Marker 3.3\n"); - } - - //---- - printk(KERN_INFO "Finding DEBUG_IP_LAYOUT section\n"); - memHeader = get_axlf_section(copy_buffer, DEBUG_IP_LAYOUT); - if (memHeader == 0) { - printk(KERN_INFO "Did not find DEBUG_IP_LAYOUT section.\n"); - } else { - printk(KERN_INFO "%s XOCL: DEBUG_IP_LAYOUT offset = %llx, size = %llx, xclbin length = %llx\n", __FUNCTION__, memHeader->m_sectionOffset , memHeader->m_sectionSize, bin_obj.m_header.m_length); - - if((memHeader->m_sectionOffset + memHeader->m_sectionSize) > bin_obj.m_header.m_length) { - printk(KERN_INFO "%s XOCL: DEBUG_IP_LAYOUT section extends beyond xclbin boundary %llx\n", __FUNCTION__, bin_obj.m_header.m_length); - err = -EINVAL; - goto done; - } - printk(KERN_INFO "XOCL: Marker 4.1\n"); - buffer = (char __user *)axlf_obj_ptr->xclbin; - buffer += memHeader->m_sectionOffset; - xdev->debug_layout.layout = vmalloc(memHeader->m_sectionSize); - err = copy_from_user(xdev->debug_layout.layout, buffer, memHeader->m_sectionSize); - printk(KERN_INFO "XOCL: Marker 4.2\n"); - if (err) - goto done; - xdev->debug_layout.size = memHeader->m_sectionSize; - printk(KERN_INFO "XOCL: Marker 4.3\n"); - } - - //--- - printk(KERN_INFO "Finding CONNECTIVITY section\n"); - memHeader = get_axlf_section(copy_buffer, CONNECTIVITY); - if (memHeader == 0) { - printk(KERN_INFO "Did not find CONNECTIVITY section.\n"); - } else { - printk(KERN_INFO "%s XOCL: CONNECTIVITY offset = %llx, size = %llx\n", __FUNCTION__, memHeader->m_sectionOffset , memHeader->m_sectionSize); - if((memHeader->m_sectionOffset + memHeader->m_sectionSize) > bin_obj.m_header.m_length) { - err = -EINVAL; - goto done; - } - buffer = (char __user *)axlf_obj_ptr->xclbin; - buffer += memHeader->m_sectionOffset; - xdev->connectivity.connections = vmalloc(memHeader->m_sectionSize); - err = copy_from_user(xdev->connectivity.connections, buffer, memHeader->m_sectionSize); - if (err) - goto done; - xdev->connectivity.size = memHeader->m_sectionSize; - } - - printk(KERN_INFO "XOCL: Marker 5\n"); - - topology = &xdev->topology; - - printk(KERN_INFO "XOCL: Topology Bank count = %d, data_length = %d\n", topology->bank_count, xdev->topology.m_data_length); - - if (!preserve_mem) { // Data Retention - xdev->mm = devm_kzalloc(dev->dev, sizeof(struct drm_mm) * topology->bank_count, GFP_KERNEL); - xdev->mm_usage_stat = devm_kzalloc(dev->dev, sizeof(struct drm_xocl_mm_stat) * topology->bank_count, GFP_KERNEL); - if (!xdev->mm || !xdev->mm_usage_stat) { - err = -ENOMEM; - goto done; - } - } - - //Check if sizes are same across banks. - ddr = 0; - for (i=0; i < topology->bank_count; i++) - { - printk(KERN_INFO "XOCL, DDR Info Index: %d Type:%d Used:%d Size:%llx Base_addr:%llx\n", i, - topology->m_data[i].m_type, topology->m_data[i].m_used, topology->m_data[i].m_size, - topology->m_data[i].m_base_address); - if (topology->m_data[i].m_used) - { - ddr++; - if ((topology->bank_size !=0) && (topology->bank_size != topology->m_data[i].m_size)) { - //we support only same sized banks for initial testing, so return error. - printk(KERN_INFO "%s err: %ld\n", __FUNCTION__, err); - err = -EFAULT; - vfree(xdev->topology.m_data); - memset(&xdev->topology, 0, sizeof(xdev->topology)); - goto done; - } - topology->bank_size = topology->m_data[i].m_size; - } - } - - //xdev->topology.used_bank_count = ddr; - printk(KERN_INFO "XOCL: Unified flow, used bank count :%d bank size(KB):%llx\n", ddr, xdev->topology.bank_size); - - if (!preserve_mem) { // Data Retention - //initialize the used banks and their sizes. Currently only fixed sizes are supported. - for (i=0; i < topology->bank_count; i++) - { - if (topology->m_data[i].m_used) { - printk(KERN_INFO "%s Allocating DDR:%d with base_addr:%llx, size %llx \n", __FUNCTION__, i, - topology->m_data[i].m_base_address, topology->m_data[i].m_size*1024); - drm_mm_init(&xdev->mm[i], topology->m_data[i].m_base_address, topology->m_data[i].m_size*1024); - printk(KERN_INFO "drm_mm_init called \n"); - } - } - } - - //Populate with "this" bitstream, so avoid redownload the next time - xdev->unique_id_last_bitstream = bin_obj.m_uniqueId; - -done: - printk(KERN_INFO "%s err: %ld\n", __FUNCTION__, err); - vfree(copy_buffer); - if (new_topology.topology != NULL) - vfree(new_topology.topology); - if (new_topology.m_data != NULL) - vfree(new_topology.m_data); - return err; - -} - -int xocl_ctx_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp) -{ - unsigned long flags; - int ret = 0; - struct drm_xocl_dev *xdev = dev->dev_private; - struct drm_xocl_ctx *args = data; - - if (args->op == XOCL_CTX_OP_FREE_CTX) { - DRM_INFO("Releasing context for pid %d\n", pid_nr(task_tgid(current))); - spin_lock_irqsave(&xdev->exec.ctx_list_lock, flags); - spin_unlock_irqrestore(&xdev->exec.ctx_list_lock, flags); - return 0; - } - - if (args->op != XOCL_CTX_OP_ALLOC_CTX) - return -EINVAL; - - DRM_INFO("Creating context for pid %d\n", pid_nr(task_tgid(current))); - - spin_lock_irqsave(&xdev->exec.ctx_list_lock, flags); - - spin_unlock_irqrestore(&xdev->exec.ctx_list_lock, flags); - return ret; -} - - -int xocl_debug_ioctl(struct drm_device *dev, - void *data, - struct drm_file *filp) -{ - int ret = -EINVAL; - //struct drm_xocl_debug *args = data; - return ret; -} - - - -int xocl_user_intr_ioctl(struct drm_device *dev, void *data, - struct drm_file *filp) - -{ - struct eventfd_ctx *trigger; - int ret = 0; - struct drm_xocl_user_intr *args = data; - struct drm_xocl_dev *xdev = dev->dev_private; - struct drm_xocl_client_ctx *fpriv = filp->driver_priv; - - if ((args->msix >= XOCL_USER_INTR_END) || (args->msix < XOCL_USER_INTR_START)) - return -EINVAL; - mutex_lock(&xdev->exec.user_msix_table_lock); - if (xdev->exec.user_msix_table[args->msix]) { - ret = -EPERM; - goto out; - } - - if (args->fd < 0) - goto out; - trigger = eventfd_ctx_fdget(args->fd); - if (IS_ERR(trigger)) { - ret = PTR_ERR(trigger); - goto out; - } - xdev->exec.user_msix_table[args->msix] = trigger; - xdma_user_interrupt_config(xdev, args->msix, true); - fpriv->eventfd_bitmap |= (1 << args->msix); -out: - mutex_unlock(&xdev->exec.user_msix_table_lock); - return ret; -} diff --git a/sdk/linux_kernel_drivers/xocl/xocl_ioctl.h b/sdk/linux_kernel_drivers/xocl/xocl_ioctl.h deleted file mode 100644 index 49ffa85c..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_ioctl.h +++ /dev/null @@ -1,375 +0,0 @@ -/** - * Copyright (C) 2015-2018 Xilinx, Inc - * - * This file is dual licensed. It may be redistributed and/or modified - * under the terms of the Apache 2.0 License OR version 2 of the GNU - * General Public License. - * - * Apache License Verbiage - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * GPL license Verbiage: - * - * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* - * A GEM style device manager for PCIe based OpenCL accelerators. - * - * Copyright (C) 2017 Xilinx, Inc. All rights reserved. - * - * Authors: - * Sonal Santan - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _XCL_XOCL_IOCTL_H_ -#define _XCL_XOCL_IOCTL_H_ - -#if defined(__KERNEL__) -#include -#elif defined(__cplusplus) -#include -#include -#else -#include -#include -#endif - -enum { - /* GEM core ioctls */ - /* Buffer creation */ - DRM_XOCL_CREATE_BO = 0, - /* Buffer creation from user provided pointer */ - DRM_XOCL_USERPTR_BO, - /* Map buffer into application user space (no DMA is performed) */ - DRM_XOCL_MAP_BO, - /* Sync buffer (like fsync) in the desired direction by using DMA */ - DRM_XOCL_SYNC_BO, - /* Get information about the buffer such as physical address in the device, etc */ - DRM_XOCL_INFO_BO, - /* Update host cached copy of buffer wih user's data */ - DRM_XOCL_PWRITE_BO, - /* Update user's data with host cached copy of buffer */ - DRM_XOCL_PREAD_BO, - /* Other ioctls */ - DRM_XOCL_OCL_RESET, - /* Currently unused */ - DRM_XOCL_CTX, - /* Get information from device */ - DRM_XOCL_INFO, - /* Unmanaged DMA from/to device */ - DRM_XOCL_PREAD_UNMGD, - DRM_XOCL_PWRITE_UNMGD, - /* Various usage metrics */ - DRM_XOCL_USAGE_STAT, - /* Hardware debug command */ - DRM_XOCL_DEBUG, - /* Command to run on one or more CUs */ - DRM_XOCL_EXECBUF, - /* Register eventfd for user interrupts */ - DRM_XOCL_USER_INTR, - /* Read xclbin/axlf */ - DRM_XOCL_READ_AXLF, - DRM_XOCL_NUM_IOCTLS -}; - -enum drm_xocl_sync_bo_dir { - DRM_XOCL_SYNC_BO_TO_DEVICE = 0, - DRM_XOCL_SYNC_BO_FROM_DEVICE -}; - -/* - * Higher 4 bits are for DDR, one for each DDR - * LSB bit for execbuf - */ -#define DRM_XOCL_BO_BANK0 (0x1) -#define DRM_XOCL_BO_BANK1 (0x1 << 1) -#define DRM_XOCL_BO_BANK2 (0x1 << 2) -#define DRM_XOCL_BO_BANK3 (0x1 << 3) -#define DRM_XOCL_BO_CMA (0x1 << 30) -#define DRM_XOCL_BO_EXECBUF (0x1 << 31) - -struct drm_xocl_create_bo { - uint64_t size; - uint32_t handle; - uint32_t flags; -}; - -struct drm_xocl_userptr_bo { - uint64_t addr; - uint64_t size; - uint32_t handle; - uint32_t flags; -}; - -struct drm_xocl_map_bo { - uint32_t handle; - uint32_t pad; - uint64_t offset; -}; - -/** - * struct drm_xocl_sync_bo - used for SYNQ_BO IOCTL - * @handle: GEM object handle - * @flags: Unused - * @size: Number of bytes to migrate - * @offset: Offset into the object to write to - * @dir: DRM_XOCL_SYNC_DIR_XXX - */ -struct drm_xocl_sync_bo { - uint32_t handle; - uint32_t flags; - uint64_t size; - uint64_t offset; - enum drm_xocl_sync_bo_dir dir; -}; - -/** - * struct drm_xocl_info_bo - used for INFO_BO IOCTL - * @handle: GEM object handle - * @size: Size of buffer object in bytes - * @paddr: physical address (out) - */ -struct drm_xocl_info_bo { - uint32_t handle; - uint32_t flags; - uint64_t size; - uint64_t paddr; -}; - -struct drm_xocl_axlf { - struct axlf *xclbin; -}; - -/** - * struct drm_xocl_pwrite_bo - used for PWRITE_BO IOCTL - * @handle: GEM object handle - * @pad: Padding - * @offset: Offset into the buffer object to write to - * @size: Length of data to write - * @data_ptr: Pointer to read the data from - */ -struct drm_xocl_pwrite_bo { - uint32_t handle; - uint32_t pad; - uint64_t offset; - uint64_t size; - uint64_t data_ptr; -}; - -/** - * struct drm_xocl_pread_bo - used for PREAD_BO IOCTL - * @handle: GEM object handle - * @pad: Padding - * @offset: Offset into the buffer object to read from - * @size: Length of data to read - * @data_ptr: Pointer to write the data into - */ -struct drm_xocl_pread_bo { - uint32_t handle; - uint32_t pad; - uint64_t offset; - uint64_t size; - uint64_t data_ptr; -}; - -enum drm_xocl_ctx_code { - XOCL_CTX_OP_ALLOC_CTX = 0, - XOCL_CTX_OP_FREE_CTX -}; - -struct drm_xocl_ctx { - enum drm_xocl_ctx_code op; - char uuid[16]; - uint32_t cu_bitmap; - uint32_t flags; -}; - -struct drm_xocl_info { - unsigned short vendor; - unsigned short device; - unsigned short subsystem_vendor; - unsigned short subsystem_device; - unsigned int dma_engine_version; - unsigned int driver_version; - unsigned int pci_slot; - char reserved[64]; -}; - - -/** - * struct drm_xocl_pwrite_unmgd (used with PWRITE_UNMGD IOCTL) - * @address_space: Address space in the DSA; currently only 0 is suported - * @pad: Padding - * @offset: Physical address in the specified address space - * @size: Length of data to write - * @data_ptr: Pointer to read the data from - */ -struct drm_xocl_pwrite_unmgd { - uint32_t address_space; - uint32_t pad; - uint64_t paddr; - uint64_t size; - uint64_t data_ptr; -}; - -/** - * struct drm_xocl_pread_unmgd (used for PREAD_UNMGD IOCTL) - * @address_space: Address space in the DSA; currently only 0 is valid - * @pad: Padding - * @offset: Physical address in the specified address space - * @size: Length of data to write - * @data_ptr: Pointer to write the data to - */ -struct drm_xocl_pread_unmgd { - uint32_t address_space; - uint32_t pad; - uint64_t paddr; - uint64_t size; - uint64_t data_ptr; -}; - - -struct drm_xocl_mm_stat { - size_t memory_usage; - unsigned int bo_count; -}; - -/** - * struct drm_xocl_stats (used for STATS IOCTL) - * @address_space: Address space in the DSA; currently only 0 is valid - * @pad: Padding - * @offset: Physical address in the specified address space - * @size: Length of data to write - * @data_ptr: Pointer to write the data to - */ -struct drm_xocl_usage_stat { - unsigned dma_channel_count; - unsigned mm_channel_count; - uint64_t h2c[8]; - uint64_t c2h[8]; - struct drm_xocl_mm_stat mm[8]; -}; - -enum drm_xocl_debug_code { - DRM_XOCL_DEBUG_ACQUIRE_CU = 0, - DRM_XOCL_DEBUG_RELEASE_CU, - DRM_XOCL_DEBUG_NIFD_RD, - DRM_XOCL_DEBUG_NIFD_WR, -}; - -struct drm_xocl_debug { - uint32_t ctx_id; - enum drm_xocl_debug_code code; - unsigned int code_size; - uint64_t code_ptr; -}; - -/** - * Opcodes for the embedded scheduler provided by the client to the driver - */ -enum drm_xocl_execbuf_code { - DRM_XOCL_EXECBUF_RUN_KERNEL = 0, - DRM_XOCL_EXECBUF_RUN_KERNEL_XYZ, - DRM_XOCL_EXECBUF_PING, - DRM_XOCL_EXECBUF_DEBUG, -}; - -/** - * State of exec request managed by the kernel driver - */ -enum drm_xocl_execbuf_state { - DRM_XOCL_EXECBUF_STATE_COMPLETE = 0, - DRM_XOCL_EXECBUF_STATE_RUNNING, - DRM_XOCL_EXECBUF_STATE_SUBMITTED, - DRM_XOCL_EXECBUF_STATE_QUEUED, - DRM_XOCL_EXECBUF_STATE_ERROR, - DRM_XOCL_EXECBUF_STATE_ABORT, -}; - -/** - * Layout of BO of EXECBUF kind - */ -struct drm_xocl_execbuf_bo { - enum drm_xocl_execbuf_state state; - enum drm_xocl_execbuf_code code; - uint64_t cu_bitmap; - uint64_t token; - char buf[3584]; // inline regmap layout -}; - -struct drm_xocl_execbuf { - uint32_t ctx_id; - uint32_t exec_bo_handle; -}; - -/** - * struct drm_xocl_user_intr (used for XOCL_USER_INTR IOCTL) - * @ctx_id: Context created before with CTX ioctl - * @fd: File descriptor created with eventfd system call - * @msix: User interrupt number (0 to 15) - */ -struct drm_xocl_user_intr { - uint32_t ctx_id; - int fd; - int msix; -}; - - -#define DRM_IOCTL_XOCL_CREATE_BO DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_XOCL_CREATE_BO, struct drm_xocl_create_bo) -#define DRM_IOCTL_XOCL_USERPTR_BO DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_XOCL_USERPTR_BO, struct drm_xocl_userptr_bo) -#define DRM_IOCTL_XOCL_MAP_BO DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_XOCL_MAP_BO, struct drm_xocl_map_bo) -#define DRM_IOCTL_XOCL_SYNC_BO DRM_IOW (DRM_COMMAND_BASE + \ - DRM_XOCL_SYNC_BO, struct drm_xocl_sync_bo) -#define DRM_IOCTL_XOCL_INFO_BO DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_XOCL_INFO_BO, struct drm_xocl_info_bo) -#define DRM_IOCTL_XOCL_PWRITE_BO DRM_IOW (DRM_COMMAND_BASE + \ - DRM_XOCL_PWRITE_BO, struct drm_xocl_pwrite_bo) -#define DRM_IOCTL_XOCL_PREAD_BO DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_XOCL_PREAD_BO, struct drm_xocl_pread_bo) -#define DRM_IOCTL_XOCL_CTX DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_XOCL_CTX, struct drm_xocl_ctx) -#define DRM_IOCTL_XOCL_INFO DRM_IOR(DRM_COMMAND_BASE + \ - DRM_XOCL_INFO, struct drm_xocl_info) -#define DRM_IOCTL_XOCL_READ_AXLF DRM_IOW(DRM_COMMAND_BASE + \ - DRM_XOCL_READ_AXLF, struct drm_xocl_axlf) -#define DRM_IOCTL_XOCL_PWRITE_UNMGD DRM_IOW (DRM_COMMAND_BASE + \ - DRM_XOCL_PWRITE_UNMGD, struct drm_xocl_pwrite_unmgd) -#define DRM_IOCTL_XOCL_PREAD_UNMGD DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_XOCL_PREAD_UNMGD, struct drm_xocl_pread_unmgd) -#define DRM_IOCTL_XOCL_USAGE_STAT DRM_IOR(DRM_COMMAND_BASE + \ - DRM_XOCL_USAGE_STAT, struct drm_xocl_usage_stat) -#define DRM_IOCTL_XOCL_DEBUG DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_XOCL_DEBUG, struct drm_xocl_debug) -#define DRM_IOCTL_XOCL_EXECBUF DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_XOCL_EXECBUF, struct drm_xocl_execbuf) -#define DRM_IOCTL_XOCL_USER_INTR DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_XOCL_USER_INTR, struct drm_xocl_user_intr) - -#endif diff --git a/sdk/linux_kernel_drivers/xocl/xocl_sysfs.c b/sdk/linux_kernel_drivers/xocl/xocl_sysfs.c deleted file mode 100644 index dab368be..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_sysfs.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2016-2018 Xilinx, Inc - * - * Authors: - * Umang Parekh - * - * sysfs for the device attributes. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "xocl_drv.h" - -//-xclbinid-- -static ssize_t xclbinid_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct drm_device *ddev = dev_get_drvdata(dev); - struct drm_xocl_dev *xdev = ddev->dev_private; - return sprintf(buf, "%llx\n", xdev->unique_id_last_bitstream); -} - -static DEVICE_ATTR_RO(xclbinid); - -//-Base address-- -static ssize_t dr_base_addr_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct drm_device *ddev = dev_get_drvdata(dev); - struct drm_xocl_dev *xdev = ddev->dev_private; - - //TODO: Fix: DRBaseAddress no longer required in feature rom - if(xdev->header.MajorVersion >= 10) - return sprintf(buf, "%llu\n", xdev->header.DRBaseAddress); - else - return sprintf(buf, "%u\n", 0); -} - -static DEVICE_ATTR_RO(dr_base_addr); - - -//-Mem_topology-- -static ssize_t mem_topology_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - printk(KERN_INFO "%s %s In mem_topology_show function \n", DRV_NAME, __FUNCTION__); - struct drm_device *ddev = dev_get_drvdata(dev); - struct drm_xocl_dev *xdev = ddev->dev_private; - memcpy(buf, xdev->topology.topology, xdev->topology.size); - printk(KERN_INFO "%s %s Mem-copied %llx bytes \n", DRV_NAME, __FUNCTION__, xdev->topology.size); - return xdev->topology.size; -} - -static DEVICE_ATTR_RO(mem_topology); - -//-Connectivity-- -static ssize_t connectivity_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - printk(KERN_INFO "%s %s In connectivity_show function \n", DRV_NAME, __FUNCTION__); - struct drm_device *ddev = dev_get_drvdata(dev); - struct drm_xocl_dev *xdev = ddev->dev_private; - memcpy(buf, xdev->connectivity.connections, xdev->connectivity.size); - return xdev->connectivity.size; -} - -static DEVICE_ATTR_RO(connectivity); - -//-IP_layout-- -static ssize_t ip_layout_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - printk(KERN_INFO "%s %s In ip_layout_show function \n", DRV_NAME, __FUNCTION__); - struct drm_device *ddev = dev_get_drvdata(dev); - struct drm_xocl_dev *xdev = ddev->dev_private; - memcpy(buf, xdev->layout.layout, xdev->layout.size); - return xdev->layout.size; -} - -static DEVICE_ATTR_RO(ip_layout); - -//- Debug IP_layout-- -static ssize_t debug_ip_layout_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - printk(KERN_INFO "%s %s In debug_ip_layout_show function \n", DRV_NAME, __FUNCTION__); - struct drm_device *ddev = dev_get_drvdata(dev); - struct drm_xocl_dev *xdev = ddev->dev_private; - memcpy(buf, xdev->debug_layout.layout, xdev->debug_layout.size); - printk(KERN_INFO "%s %s Mem-copied %llx bytes \n", DRV_NAME, __FUNCTION__, xdev->debug_layout.size); - return xdev->debug_layout.size; -} - -static DEVICE_ATTR_RO(debug_ip_layout); - - -//--- -int xocl_init_sysfs(struct device *dev) -{ - int result = device_create_file(dev, &dev_attr_xclbinid); - if(result) - return result; - result = device_create_file(dev, &dev_attr_dr_base_addr); - if(result) - return result; - result = device_create_file(dev, &dev_attr_connectivity); - if(result) - return result; - result = device_create_file(dev, &dev_attr_ip_layout); - if(result) - return result; - result = device_create_file(dev, &dev_attr_debug_ip_layout); - if(result) - return result; - result = device_create_file(dev, &dev_attr_mem_topology); - return result; -} - -void xocl_fini_sysfs(struct device *dev) -{ - printk(KERN_INFO "%s %s Cleaning up sys files \n", DRV_NAME, __FUNCTION__); - device_remove_file(dev, &dev_attr_xclbinid); - device_remove_file(dev, &dev_attr_dr_base_addr); - device_remove_file(dev, &dev_attr_mem_topology); - device_remove_file(dev, &dev_attr_connectivity); - device_remove_file(dev, &dev_attr_ip_layout); - device_remove_file(dev, &dev_attr_debug_ip_layout); -} diff --git a/sdk/linux_kernel_drivers/xocl/xocl_test.c b/sdk/linux_kernel_drivers/xocl/xocl_test.c deleted file mode 100644 index 94c1fee4..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_test.c +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (C) 2018 Xilinx, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "xocl_drv.h" - -int xocl_test_interval = 5; -bool xocl_test_on = true; - -/** - * TODO: - * Test drm_send_event() with event object initialized with drm_event_reserve_init() - * to send events for CUs - */ -static int xocl_test_thread_main(void *data) -{ -#if 0 - struct timeval now; - struct drm_xocl_dev *xdev = (struct drm_xocl_dev *)data; - int irq = 0; - int count = 0; - while (!kthread_should_stop()) { - ssleep(xocl_test_interval); - do_gettimeofday(&now); - DRM_INFO("irq[%d] tv_sec[%ld]tv_usec[%ld]\n", irq, now.tv_sec, now.tv_usec); - xocl_user_event(irq, xdev); - irq++; - irq &= 0xf; - count++; - } - printk(KERN_INFO "The xocl test thread has terminated."); -#endif - return 0; -} - -int xocl_init_test_thread(struct drm_xocl_dev *xdev) -{ - int ret = 0; -#if 0 - xdev->exec.test_kthread = kthread_run(xocl_test_thread_main, (void *)xdev, "xocl-test-thread"); - DRM_DEBUG(__func__); - if (IS_ERR(xdev->exec.test_kthread)) { - DRM_ERROR(__func__); - ret = PTR_ERR(xdev->exec.test_kthread); - xdev->exec.test_kthread = NULL; - } -#endif - return ret; -} - -int xocl_fini_test_thread(struct drm_xocl_dev *xdev) -{ - int ret = 0; -#if 0 - if (!xdev->exec.test_kthread) - return 0; - ret = kthread_stop(xdev->exec.test_kthread); - ssleep(xocl_test_interval); - xdev->exec.test_kthread = NULL; - DRM_DEBUG(__func__); -#endif - return ret; -} diff --git a/sdk/linux_kernel_drivers/xocl/xocl_xdma.c b/sdk/linux_kernel_drivers/xocl/xocl_xdma.c deleted file mode 100644 index edc47f27..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_xdma.c +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (C) 2015-2018 Xilinx, Inc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "xocl_drv.h" -#include "xocl_xdma.h" -#include "libxdma_api.h" - -static irqreturn_t xocl_xdma_user_isr(int irq, void *arg) -{ - struct drm_xocl_dev *xdev = (struct drm_xocl_dev *)arg; - xocl_user_event(irq, xdev); - return IRQ_HANDLED; -} - -int xdma_init_glue(struct drm_xocl_dev *xdev) -{ - int ret = 0; - int user = 0; - unsigned short mask = ~0; - xdev->xdma_handle = (struct xdma_dev *) xdma_device_open(DRV_NAME, xdev->ddev->pdev, &user, - &xdev->channel, &xdev->channel); - if (xdev->xdma_handle == NULL) { - DRM_INFO("%s: XDMA Device Open failed. \n", DRV_NAME); - ret = -ENOENT; // TBD: Get the error code from XDMA API. - } - ret = xdma_user_isr_register(xdev->xdma_handle, mask, xocl_xdma_user_isr, xdev); - if (ret) - xdma_device_close(xdev->ddev->pdev, xdev->xdma_handle); - else - DRM_INFO("%s: XDMA Device Open successful. \n", DRV_NAME); - return ret; -} - -void xdma_fini_glue(struct drm_xocl_dev *xdev) -{ - unsigned short mask = ~0; - xdma_user_isr_register(xdev->xdma_handle, mask, NULL, xdev); - xdma_device_close(xdev->ddev->pdev, xdev->xdma_handle); - xdev->xdma_handle = NULL; - DRM_INFO("%s: XDMA Device Close successful. \n", DRV_NAME); -} - - -ssize_t xdma_migrate_bo(const struct drm_xocl_dev *xdev, struct sg_table *sgt, bool write, - u64 paddr, int channel) -{ - struct page *pg; - struct scatterlist *sg = sgt->sgl; - int nents = sgt->orig_nents; - pid_t pid = current->pid; - const char* dirstr = write ? "to" : "from"; - int i = 0; - ssize_t ret; - unsigned long long pgaddr; - DRM_DEBUG("%s TID %d, Channel:" - "%d, Offset: 0x%llx, Direction: %d\n", __func__, pid, channel, paddr, write ? 1 : 0); - ret = xdma_xfer_submit(xdev->xdma_handle, channel, write ? 1 : 0, paddr, sgt, false, 10000); - if (ret >= 0) - return ret; - - DRM_ERROR("DMA failed %s device addr 0x%llx, tid %d, channel %d\n", dirstr, paddr, pid, channel); - DRM_ERROR("Dumping SG Page Table\n"); - for (i = 0; i < nents; i++, sg = sg_next(sg)) { - if (!sg) - break; - pg = sg_page(sg); - if (!pg) - continue; - pgaddr = page_to_phys(pg); - DRM_ERROR("%i, 0x%llx\n", i, pgaddr); - } - return ret; -} - - -int xdma_user_interrupt_config(struct drm_xocl_dev *xdev, int user_intr_number, bool enable) -{ - const unsigned int mask = 1 << user_intr_number; - return enable ? xdma_user_isr_enable(xdev->xdma_handle, mask) : xdma_user_isr_disable(xdev->xdma_handle, mask); -} diff --git a/sdk/linux_kernel_drivers/xocl/xocl_xdma.h b/sdk/linux_kernel_drivers/xocl/xocl_xdma.h deleted file mode 100644 index 5e6d1d64..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_xdma.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (C) 2015-2018 Xilinx, Inc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _XCL_XOCL_XDMA_H_ -#define _XCL_XOCL_XDMA_H_ - -#include -#include -#include -#include - -int xdma_init_glue(struct drm_xocl_dev *xdev); -void xdma_fini_glue(struct drm_xocl_dev *xdev); -ssize_t xdma_migrate_bo(const struct drm_xocl_dev *xdev, struct sg_table *sgt, bool write, - u64 paddr, int channel); -int xdma_user_interrupt_config(struct drm_xocl_dev *xdev, int user_intr_number, bool enable); -#endif - -// 67d7842dbbe25473c3c32b93c0da8047785f30d78e8a024de1b57352245f9689 diff --git a/sdk/linux_kernel_drivers/xocl/xocl_xvc.c b/sdk/linux_kernel_drivers/xocl/xocl_xvc.c deleted file mode 100644 index dc543c5c..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_xvc.c +++ /dev/null @@ -1,330 +0,0 @@ -/******************************************************************************* - * - * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - * - * The full GNU General Public License is included in this distribution in - * the file called "LICENSE". - * - * Karen Xie - * Sonal Santan - * - ******************************************************************************/ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xocl_xvc.h" -#include "xvc_pcie_ioctl.h" - -#define DEFAULT_XVC_BAR_OFFSET 0xC0000 // DSA 4.1 and 5.0 -#define DEFAULT_XVC_BAR 0 - -#define COMPLETION_LOOP_MAX 100 - -#define XVC_BAR_LENGTH_REG 0x0 -#define XVC_BAR_TMS_REG 0x4 -#define XVC_BAR_TDI_REG 0x8 -#define XVC_BAR_TDO_REG 0xC -#define XVC_BAR_CTRL_REG 0x10 - -#define XVC_DEV_NAME "xvc" - -static dev_t xvc_dev; -static int instance = 0; -static struct class *xvc_class = NULL; - -#ifdef __REG_DEBUG__ -/* SECTION: Function definitions */ -static inline void __write_register(const char *fn, u32 value, void *base, - unsigned int off) -{ - pr_info("%s: 0x%p, W reg 0x%lx, 0x%x.\n", fn, base, off, value); - iowrite32(value, base + off); -} - -static inline u32 __read_register(const char *fn, void *base, unsigned int off) -{ - u32 v = ioread32(base + off); - - pr_info("%s: 0x%p, R reg 0x%lx, 0x%x.\n", fn, base, off, v); - return v; -} -#define write_register(v,base,off) __write_register(__func__, v, base, off) -#define read_register(base,off) __read_register(__func__, base, off) - -#else -#define write_register(v,base,off) iowrite32(v, (base) + (off)) -#define read_register(base,off) ioread32((base) + (off)) -#endif /* #ifdef __REG_DEBUG__ */ - - -static int xvc_shift_bits(void *base, u32 tms_bits, u32 tdi_bits, - u32 *tdo_bits) -{ - u32 control; - int count; - - /* set tms bit */ - write_register(tms_bits, base, XVC_BAR_TMS_REG); - /* set tdi bits and shift data out */ - write_register(tdi_bits, base, XVC_BAR_TDI_REG); - /* enable shift operation */ - write_register(0x1, base, XVC_BAR_CTRL_REG); - - /* poll for completion */ - count = COMPLETION_LOOP_MAX; - while (count) { - /* read control reg to check shift operation completion */ - control = read_register(base, XVC_BAR_CTRL_REG); - if ((control & 0x01) == 0) - break; - - count--; - } - - if (!count) { - pr_warn("XVC bar transaction timed out (0x%0X)\n", control); - return -ETIMEDOUT; - } - - /* read tdo bits back out */ - *tdo_bits = read_register(base, XVC_BAR_TDO_REG); - - return 0; -} - -static long xvc_ioctl_helper(struct xocl_xvc *xvc, const void __user *arg) -{ - struct xil_xvc_ioc xvc_obj; - unsigned int opcode; - unsigned int total_bits; - unsigned int total_bytes; - unsigned int bits, bits_left; - unsigned char *buffer = NULL; - unsigned char *tms_buf = NULL; - unsigned char *tdi_buf = NULL; - unsigned char *tdo_buf = NULL; - void __iomem *iobase = xvc->bar + DEFAULT_XVC_BAR_OFFSET; - int rv; - - rv = copy_from_user((void *)&xvc_obj, arg, - sizeof(struct xil_xvc_ioc)); - /* anything not copied ? */ - if (rv) { - pr_info("copy_from_user xvc_obj failed: %d.\n", rv); - goto cleanup; - } - - opcode = xvc_obj.opcode; - - /* Invalid operation type, no operation performed */ - if (opcode != 0x01 && opcode != 0x02) { - pr_info("UNKNOWN opcode 0x%x.\n", opcode); - return -EINVAL; - } - - total_bits = xvc_obj.length; - total_bytes = (total_bits + 7) >> 3; - - buffer = (char *)kmalloc(total_bytes * 3, GFP_KERNEL); - if (!buffer) { - pr_info("OOM %u, op 0x%x, len %u bits, %u bytes.\n", - 3 * total_bytes, opcode, total_bits, total_bytes); - rv = -ENOMEM; - goto cleanup; - } - tms_buf = buffer; - tdi_buf = tms_buf + total_bytes; - tdo_buf = tdi_buf + total_bytes; - - rv = copy_from_user((void *)tms_buf, xvc_obj.tms_buf, total_bytes); - if (rv) { - pr_info("copy tmfs_buf failed: %d/%u.\n", rv, total_bytes); - goto cleanup; - } - rv = copy_from_user((void *)tdi_buf, xvc_obj.tdi_buf, total_bytes); - if (rv) { - pr_info("copy tdi_buf failed: %d/%u.\n", rv, total_bytes); - goto cleanup; - } - - /* set length register to 32 initially if more than one - * word-transaction is to be done */ - if (total_bits >= 32) - write_register(0x20, iobase, XVC_BAR_LENGTH_REG); - - for (bits = 0, bits_left = total_bits; bits < total_bits; bits += 32, - bits_left -= 32) { - unsigned int bytes = bits >> 3; - unsigned int shift_bytes = 4; - u32 tms_store = 0; - u32 tdi_store = 0; - u32 tdo_store = 0; - - if (bits_left < 32) { - /* set number of bits to shift out */ - write_register(bits_left, iobase, XVC_BAR_LENGTH_REG); - shift_bytes = (bits_left + 7) >> 3; - } - - memcpy(&tms_store, tms_buf + bytes, shift_bytes); - memcpy(&tdi_store, tdi_buf + bytes, shift_bytes); - - /* Shift data out and copy to output buffer */ - rv = xvc_shift_bits(iobase, tms_store, tdi_store, &tdo_store); - if (rv < 0) - goto cleanup; - - memcpy(tdo_buf + bytes, &tdo_store, shift_bytes); - } - - /* if testing bar access swap tdi and tdo bufferes to "loopback" */ - if (opcode == 0x2) { - char *tmp = tdo_buf; - - tdo_buf = tdi_buf; - tdi_buf = tmp; - } - - rv = copy_to_user((void *)xvc_obj.tdo_buf, tdo_buf, total_bytes); - if (rv) { - pr_info("copy back tdo_buf failed: %d/%u.\n", rv, total_bytes); - rv = -EFAULT; - goto cleanup; - } - -cleanup: - if (buffer) - kfree(buffer); - - mmiowb(); - - return rv; -} - -long xvc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct xocl_xvc *xvc = filp->private_data; - return xvc_ioctl_helper(xvc, (void __user *)arg); -} - -static int char_open(struct inode *inode, struct file *file) -{ - struct xocl_xvc *xvc = NULL; - - /* pointer to containing structure of the character device inode */ - xvc = container_of(inode->i_cdev, struct xocl_xvc, sys_cdev); - /* create a reference to our char device in the opened file */ - file->private_data = xvc; - return 0; -} - -/* - * Called when the device goes from used to unused. - */ -static int char_close(struct inode *inode, struct file *file) -{ - return 0; -} - - -/* - * character device file operations for the XVC - */ -static const struct file_operations xvc_fops = { - .owner = THIS_MODULE, - .open = char_open, - .release = char_close, - .unlocked_ioctl = xvc_ioctl, -}; - -int xocl_xvc_device_init(struct xocl_xvc *xvc, struct device *dev) -{ - int err; -#ifdef __XVC_BAR_NUM__ - xcdev->bar = __XVC_BAR_NUM__; -#endif -#ifdef __XVC_BAR_OFFSET__ - xcdev->base = __XVC_BAR_OFFSET__; -#else - xvc->base = XVC_BAR_OFFSET_DFLT; -#endif - pr_info("xcdev 0x%p, offset 0x%lx.\n", - xvc, xvc->base); - - cdev_init(&xvc->sys_cdev, &xvc_fops); - xvc->sys_cdev.owner = THIS_MODULE; - xvc->instance = instance++; - xvc->sys_cdev.dev = MKDEV(MAJOR(xvc_dev), xvc->instance); - err = cdev_add(&xvc->sys_cdev, xvc->sys_cdev.dev, 1); - if (err) - return err; - - xvc->sys_device = device_create(xvc_class, dev, - xvc->sys_cdev.dev, - NULL, XVC_DEV_NAME "%d", xvc->instance); - if (IS_ERR(xvc->sys_device)) { - err = PTR_ERR(xvc->sys_device); - cdev_del(&xvc->sys_cdev); - } - - if (!err) - pr_info("XVC device instance %d initialized\n", xvc->instance); - return err; -} - - -int xocl_xvc_device_fini(struct xocl_xvc *xvc) -{ - device_destroy(xvc_class, xvc->sys_cdev.dev); - cdev_del(&xvc->sys_cdev); - return 0; -} - -int xocl_xvc_chardev_init() -{ - int err = 0; - - err = alloc_chrdev_region(&xvc_dev, 0, 16, XVC_DEV_NAME); - if (err < 0) - goto err_register_chrdev; - - xvc_class = class_create(THIS_MODULE, XVC_DEV_NAME); - if (IS_ERR(xvc_class)) { - err = PTR_ERR(xvc_class); - goto err_class_create; - } - return 0; - -err_class_create: - unregister_chrdev_region(xvc_dev, 16); -err_register_chrdev: - return err; -} - -void xocl_xvc_chardev_exit() -{ - unregister_chrdev_region(xvc_dev, 16); - class_destroy(xvc_class); -} diff --git a/sdk/linux_kernel_drivers/xocl/xocl_xvc.h b/sdk/linux_kernel_drivers/xocl/xocl_xvc.h deleted file mode 100644 index 76b62c8e..00000000 --- a/sdk/linux_kernel_drivers/xocl/xocl_xvc.h +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - * - * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - * - * The full GNU General Public License is included in this distribution in - * the file called "LICENSE". - * - * Karen Xie - * Sonal Santan - * - ******************************************************************************/ - -#ifndef _XCL_XOCL_XVC_DRV_H_ -#define _XCL_XOCL_XVC_DRV_H_ - -#define XVC_BAR_OFFSET_DFLT 0x40000 - -struct xocl_xvc { - unsigned long base; /* bar access offset */ - unsigned int instance; - struct cdev sys_cdev; - struct device *sys_device; - void *__iomem bar; -}; - -int xocl_xvc_chardev_init(void); -void xocl_xvc_chardev_exit(void); -int xocl_xvc_device_init(struct xocl_xvc *xvc, struct device *dev); -int xocl_xvc_device_fini(struct xocl_xvc *xvc); - -#endif diff --git a/sdk/linux_kernel_drivers/xocl/xvc_pcie_ioctl.h b/sdk/linux_kernel_drivers/xocl/xvc_pcie_ioctl.h deleted file mode 100644 index c81d813b..00000000 --- a/sdk/linux_kernel_drivers/xocl/xvc_pcie_ioctl.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (C) 2017-2018 Xilinx, Inc - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _XIL_XVC_IOCALLS_POSIX_H_ -#define _XIL_XVC_IOCALLS_POSIX_H_ - -#ifndef _WINDOWS -// TODO: Windows build support -#include -#endif - -#define XIL_XVC_MAGIC 0x58564344 // "XVCD" - -struct xil_xvc_ioc { - unsigned opcode; - unsigned length; - unsigned char *tms_buf; - unsigned char *tdi_buf; - unsigned char *tdo_buf; -}; - -#define XDMA_IOCXVC _IOWR(XIL_XVC_MAGIC, 1, struct xil_xvc_ioc) - -#endif // _XIL_XVC_IOCALLS_POSIX_H_ -// 67d7842dbbe25473c3c32b93c0da8047785f30d78e8a024de1b57352245f9689 diff --git a/shared/bin/set_common_env_vars.sh b/shared/bin/set_common_env_vars.sh index c249a253..52a07815 100644 --- a/shared/bin/set_common_env_vars.sh +++ b/shared/bin/set_common_env_vars.sh @@ -75,3 +75,6 @@ PYTHONPATH=$python_lib:$PYTHONPATH export PATH=$(echo $PATH | sed -e 's/\(^\|:\)[^:]\+\/shared\/bin\/scripts\(:\|$\)/:/g; s/^://; s/:$//') PATH=$AWS_FPGA_REPO_DIR/shared/bin/scripts:$PATH + +# Enable xilinx licensing +export XILINX_ENABLE_AWS_WHITELIST=095707098027 diff --git a/shared/bin/set_common_functions.sh b/shared/bin/set_common_functions.sh index c7a05c91..94bd19bb 100644 --- a/shared/bin/set_common_functions.sh +++ b/shared/bin/set_common_functions.sh @@ -270,7 +270,7 @@ function patch_AR73068 { elif [[ "${base_vivado_version}" =~ "Vivado v2017.4" ]]; then patch_AR73068_2017_4 else - warn_msg "Unknown Vivado version: ${base_vivado_version}. Not applying Xilinx Patch AR73068" + info_msg "Xilinx Patch AR73068 not applicable for Vivado version: ${base_vivado_version}." fi } diff --git a/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py b/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py index 32a5e014..861d72d7 100644 --- a/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py +++ b/shared/lib/aws_fpga_test_utils/AwsFpgaTestBase.py @@ -414,7 +414,7 @@ def get_sdaccel_example_run_cmd(examplePath, xilinxVersion): run_cmd += " {}".format(((description.get("cmd_args", None).replace(".xclbin",".hw.xilinx_aws-vu9p-f1-04261818_dynamic_5_0.awsxclbin")).replace("PROJECT",".")).replace("BUILD","./xclbin")) assert run_cmd is not None, "Could not find run_cmd(em_cmd) or (host_exe) in the example description here {}".format(examplePath) - + return run_cmd @staticmethod @@ -663,6 +663,10 @@ def assert_non_zero_file(filter): filenames = glob.glob(filter) + # Removing .link.xclbin found in Vitis2020.1 + + filenames = [x for x in filenames if ".link." not in x] + assert len(filenames) > 0, "No {} file found in {}".format(filter, os.getcwd()) assert len(filenames) == 1, "More than 1 {} file found: {}\n{}".format(filter, len(filenames), filenames) diff --git a/shared/lib/check_src_headers.py b/shared/lib/check_src_headers.py index 8d390a3c..329896eb 100755 --- a/shared/lib/check_src_headers.py +++ b/shared/lib/check_src_headers.py @@ -554,7 +554,7 @@ def check_headers(dir): "sdk/linux_kernel_drivers/xocl/LICENSE$", "sdk/apps/virtual-ethernet/scripts/pktgen-ena-range.pkt", "sdk/apps/virtual-ethernet/scripts/pktgen-ena.pkt", - + "SDAccel/userspace/src/test", "SDAccel/examples/aws/kernel_3ddr_bandwidth/description.json", "SDAccel/examples/aws/helloworld_ocl_runtime/helloworld", @@ -576,6 +576,7 @@ def check_headers(dir): "SDAccel/examples/xilinx", "Vitis/aws_platform", "Vitis/examples/xilinx", + "Vitis/docs/Alveo_to_AWS_F1_Migration/example", ]) file_path_list = sorted(file_provider.get_files(dir)) diff --git a/supported_vivado_versions.txt b/supported_vivado_versions.txt index 38d9300d..26e509fb 100644 --- a/supported_vivado_versions.txt +++ b/supported_vivado_versions.txt @@ -1,12 +1,3 @@ -Vivado v2017.4 (64-bit) -Vivado v2017.4.op (64-bit) -Vivado v2018.2_AR71275_op (64-bit) -Vivado v2018.2_AR71715 (64-bit) -Vivado v2018.2.op (64-bit) -Vivado v2018.2 (64-bit) -Vivado v2018.3.op (64-bit) -Vivado v2018.3 (64-bit) -Vivado v2018.3_AR72667 (64-bit) Vivado v2019.1.op (64-bit) Vivado v2019.1 (64-bit) Vivado v2019.1_AR73068 (64-bit) @@ -15,3 +6,4 @@ Vivado v2019.1_AR72668 (64-bit) Vivado v2019.2 (64-bit) Vivado v2019.2_AR73068_op (64-bit) Vivado v2019.2_AR73068 (64-bit) +Vivado v2020.1 (64-bit) diff --git a/vitis_runtime_setup.sh b/vitis_runtime_setup.sh index 57a0b7a0..c6fb0681 100644 --- a/vitis_runtime_setup.sh +++ b/vitis_runtime_setup.sh @@ -152,7 +152,7 @@ check_kernel_ver check_xdma_driver check_edma_driver -if [[ "$VIVADO_TOOL_VERSION" =~ .*2019\.2.* ]]; then +if [[ "$VIVADO_TOOL_VERSION" =~ .*2019\.2.* || "$VIVADO_TOOL_VERSION" =~ .*2020\.1.* ]]; then info_msg "Xilinx Vivado version is $VIVADO_TOOL_VERSION" if [ $override == 1 ]; then @@ -193,7 +193,7 @@ if [[ "$VIVADO_TOOL_VERSION" =~ .*2019\.2.* ]]; then return 1 fi else - err_msg "Xilinx Vivado version is $VIVADO_TOOL_VERSION , only 2019.2 is supported for Vitis " + err_msg "Xilinx Vivado version is $VIVADO_TOOL_VERSION , only 2019.2 or 2020.1 are supported for Vitis " return 1 fi @@ -203,4 +203,4 @@ setup_runtime info_msg "Starting MPD" systemctl is-active --quiet mpd || sudo systemctl start mpd -info_msg "Vitis runtime check PASSED" \ No newline at end of file +info_msg "Vitis runtime check PASSED" diff --git a/vitis_setup.sh b/vitis_setup.sh index 8a4dc548..61948b83 100644 --- a/vitis_setup.sh +++ b/vitis_setup.sh @@ -171,7 +171,7 @@ info_msg " XILINX_VITIS is set to $XILINX_VITIS" # Update Xilinx Vitis Examples from GitHub info_msg "Using Vitis $RELEASE_VER" -if [[ $RELEASE_VER =~ .*2019\.2.* ]]; then +if [[ $RELEASE_VER =~ .*2019\.2.* || $RELEASE_VER =~ .*2020\.1.* ]]; then info_msg "Updating Xilinx Vitis Examples $RELEASE_VER" git submodule update --init -- Vitis/examples/xilinx_$RELEASE_VER export VIVADO_TOOL_VER=$RELEASE_VER @@ -183,7 +183,7 @@ if [[ $RELEASE_VER =~ .*2019\.2.* ]]; then fi ln -sf $VITIS_DIR/examples/xilinx_$RELEASE_VER $VITIS_DIR/examples/xilinx else - echo " $RELEASE_VER is not supported (2019.2 is supported).\n" + echo " $RELEASE_VER is not supported (2019.2 or 2020.1 is supported).\n" return 2 fi From 56f37f193ec87fa7e9a95abd25c99a5359c69495 Mon Sep 17 00:00:00 2001 From: adam kaminski Date: Wed, 23 Sep 2020 14:31:11 -0400 Subject: [PATCH 23/31] Removed duplicate FAQ questions (#503) Q: Can I delete an AFI? and Q: Can I share an AFI with other AWS accounts? --- FAQs.md | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/FAQs.md b/FAQs.md index 18707026..493a49a5 100644 --- a/FAQs.md +++ b/FAQs.md @@ -139,21 +139,6 @@ Yes, use [delete-fpga-image](./hdk/docs/delete_fpga_image.md) to delete an AFI i Use [delete-fpga-image](./hdk/docs/delete_fpga_image.md) carefully. Once all AFIs of the same global AFI ID are deleted, the AFIs cannot be recovered from deletion. Review [IAM policy best practices](http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) to restrict access to this API. -**Q: Can I share an AFI with other AWS accounts?** - -Yes, sharing allows accounts other than the owner account to load and use an AFI. Use [modify-fpga-image-attribute](./hdk/docs/fpga_image_attributes.md) API to update `loadPermission` attribute to grant/remove AFI load permission. AWS AFIs support two load permission types: -* `UserId`: share AFI with specific AWS accounts using account IDs. -* `UserGroups`: only supports `all` group to make an AFI public or private. - -Use [reset-fpga-image-attribute](./hdk/docs/fpga_image_attributes.md) API to revoke all load permissions. - -**Q: Can I delete an AFI?** - -Yes, use [delete-fpga-image](./hdk/docs/delete_fpga_image.md) to delete an AFI in a specific region. Deleting an AFI in one region does not affect AFIs in other regions. - -Use [delete-fpga-image](./hdk/docs/delete_fpga_image.md) carefully. Once all AFIs of the same global AFI ID are deleted, the AFIs cannot be recovered from deletion. Review [IAM policy best practices](http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) to resrict access to this API. - - **Q: How do I increase my AFI limit?** AFI limit increases may be requested by opening up a Support Case from your [EC2 Support Console](https://console.aws.amazon.com/support/cases#/create) From 8b5c86b151349f35a16e7ac07c71d551d7a9cd02 Mon Sep 17 00:00:00 2001 From: iomartin Date: Wed, 23 Sep 2020 13:25:08 -0600 Subject: [PATCH 24/31] Add syntax highlight + link on Markdowns (#497) * Add code syntax highlight Add syntax highlight to C and Python codes * Add hyperlink on XDMA README --- .../doc/Virtual_Ethernet_Application_Guide.md | 4 ++-- sdk/linux_kernel_drivers/xdma/README.md | 4 ++-- .../xdma/user_defined_interrupts_README.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sdk/apps/virtual-ethernet/doc/Virtual_Ethernet_Application_Guide.md b/sdk/apps/virtual-ethernet/doc/Virtual_Ethernet_Application_Guide.md index 5f772f40..b13f484c 100644 --- a/sdk/apps/virtual-ethernet/doc/Virtual_Ethernet_Application_Guide.md +++ b/sdk/apps/virtual-ethernet/doc/Virtual_Ethernet_Application_Guide.md @@ -328,7 +328,7 @@ lspci -D | grep "1d0f:ec20" Within `/dpdk/drivers/net/spp` there is a file called `spp_ethdev.c`. Your Vendor and Device ID should be added to the following table in `spp_ethdev.c` and then DPDK should be recompiled. -``` +```C static const struct rte_pci_id pci_id_spp_map[] = { { RTE_PCI_DEVICE(PCI_VENDOR_ID_AMAZON, PCI_DEVICE_ID_SDE_LOOPBACK_CL) }, { RTE_PCI_DEVICE(, ) }, @@ -345,7 +345,7 @@ make Within `/dpdk/usertools` there is a file called `dpdk-devbind.py`. Your Vendor and Device ID should be added to the following table in `dpdk-devbind.py`. -``` +```python aws_fpga_sde = {'Class': '05', 'Vendor': '1d0f', 'Device': 'f002', 'SVendor': None, 'SDevice': None} = {'Class': '05', 'Vendor': '', 'Device': '', diff --git a/sdk/linux_kernel_drivers/xdma/README.md b/sdk/linux_kernel_drivers/xdma/README.md index 52519c27..1a818d3a 100644 --- a/sdk/linux_kernel_drivers/xdma/README.md +++ b/sdk/linux_kernel_drivers/xdma/README.md @@ -42,7 +42,7 @@ Before diving into the detail specification of the XDMA, here’s a short, intui The Program below uses standard Linux system call `open()` to create a file descriptor (fd), mapping to a pair of XDMA channels (one for `read()` and one for `write()`). The XDMA hardware engine is named the `XDMA Core`. The XDMA write channel is called H2C (Host to Core). The XDMA read channel is called C2H (Core to Host). The Core refers to the FPGA and the Host refers to the instance CPU. -``` +```C #include #include #include @@ -199,7 +199,7 @@ Only the POLLIN mask is supported and is used to notify that an event has occurr Refer to [User-defined interrupts events README](./user_defined_interrupts_README.md) for more details. -The application MUST issue a `pread` of the ready file descriptor to return and clear the `events_irq` variable within the XDMA driver in order to be notified of future user interrupts. An example of using `poll` and `pread` for user defined interrupts is provided within the test_dram_dma.c `interrupt_example()`. +The application MUST issue a `pread` of the ready file descriptor to return and clear the `events_irq` variable within the XDMA driver in order to be notified of future user interrupts. An example of using `poll` and `pread` for user defined interrupts is provided within the [test_dram_dma.c](../../../hdk/cl/examples/cl_dram_dma/software/runtime/test_dram_dma.c) `interrupt_example()`. ## Concurrency and Multi-Threading diff --git a/sdk/linux_kernel_drivers/xdma/user_defined_interrupts_README.md b/sdk/linux_kernel_drivers/xdma/user_defined_interrupts_README.md index aa8709f1..f8968d99 100644 --- a/sdk/linux_kernel_drivers/xdma/user_defined_interrupts_README.md +++ b/sdk/linux_kernel_drivers/xdma/user_defined_interrupts_README.md @@ -34,7 +34,7 @@ The driver needs to be installed once, regardless of how many FPGA slots are ava The next example shows how an application can register to two events (aka user-defined interrupts) on slot 0 -``` +```C fd4=open(“/dev/xdma0_events_4”, O_RDONLY); fd6=open(“/dev/xdma0_events_6”, O_RDONLY); From 288bee0d9f22d94261cef721d8b33137b65c0bd3 Mon Sep 17 00:00:00 2001 From: Karen Xie Date: Tue, 6 Oct 2020 15:54:29 -0700 Subject: [PATCH 25/31] xdma: driver update (#498) * xdma: driver update * xdma: add back F1 specific device ids * xdma: update license header check * keep enable_credit_mp disabled * back out experimental aio code --- sdk/linux_kernel_drivers/xdma/10-xdma.rules | 0 sdk/linux_kernel_drivers/xdma/Makefile | 1 + sdk/linux_kernel_drivers/xdma/cdev_bypass.c | 33 +- sdk/linux_kernel_drivers/xdma/cdev_ctrl.c | 53 +- sdk/linux_kernel_drivers/xdma/cdev_ctrl.h | 19 +- sdk/linux_kernel_drivers/xdma/cdev_events.c | 6 +- sdk/linux_kernel_drivers/xdma/cdev_sgdma.c | 278 +++--- sdk/linux_kernel_drivers/xdma/cdev_sgdma.h | 24 +- sdk/linux_kernel_drivers/xdma/cdev_xvc.c | 77 +- sdk/linux_kernel_drivers/xdma/cdev_xvc.h | 12 +- sdk/linux_kernel_drivers/xdma/libxdma.c | 957 +++++++++++--------- sdk/linux_kernel_drivers/xdma/libxdma.h | 47 +- sdk/linux_kernel_drivers/xdma/libxdma_api.h | 30 +- sdk/linux_kernel_drivers/xdma/version.h | 7 +- sdk/linux_kernel_drivers/xdma/xdma_cdev.c | 212 +++-- sdk/linux_kernel_drivers/xdma/xdma_cdev.h | 7 +- sdk/linux_kernel_drivers/xdma/xdma_ioctl.h | 78 -- sdk/linux_kernel_drivers/xdma/xdma_mod.c | 129 +-- sdk/linux_kernel_drivers/xdma/xdma_mod.h | 7 +- shared/lib/check_src_headers.py | 9 +- 20 files changed, 1076 insertions(+), 910 deletions(-) mode change 100755 => 100644 sdk/linux_kernel_drivers/xdma/10-xdma.rules mode change 100755 => 100644 sdk/linux_kernel_drivers/xdma/Makefile mode change 100755 => 100644 sdk/linux_kernel_drivers/xdma/libxdma.c mode change 100755 => 100644 sdk/linux_kernel_drivers/xdma/libxdma.h mode change 100755 => 100644 sdk/linux_kernel_drivers/xdma/version.h delete mode 100755 sdk/linux_kernel_drivers/xdma/xdma_ioctl.h mode change 100755 => 100644 sdk/linux_kernel_drivers/xdma/xdma_mod.c mode change 100755 => 100644 sdk/linux_kernel_drivers/xdma/xdma_mod.h diff --git a/sdk/linux_kernel_drivers/xdma/10-xdma.rules b/sdk/linux_kernel_drivers/xdma/10-xdma.rules old mode 100755 new mode 100644 diff --git a/sdk/linux_kernel_drivers/xdma/Makefile b/sdk/linux_kernel_drivers/xdma/Makefile old mode 100755 new mode 100644 index 182051b7..2427268a --- a/sdk/linux_kernel_drivers/xdma/Makefile +++ b/sdk/linux_kernel_drivers/xdma/Makefile @@ -42,6 +42,7 @@ all : clean: $(MAKE) -C $(BUILDSYSTEM_DIR) M=$(PWD) clean + @/bin/rm -f *.ko modules.order *.mod.c *.o *.o.ur-safe .*.o.cmd install: all $(MAKE) -C $(BUILDSYSTEM_DIR) M=$(PWD) modules_install diff --git a/sdk/linux_kernel_drivers/xdma/cdev_bypass.c b/sdk/linux_kernel_drivers/xdma/cdev_bypass.c index 9ab445ea..5e40526b 100644 --- a/sdk/linux_kernel_drivers/xdma/cdev_bypass.c +++ b/sdk/linux_kernel_drivers/xdma/cdev_bypass.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,11 +21,12 @@ * Karen Xie * ******************************************************************************/ +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ #include "libxdma_api.h" #include "xdma_cdev.h" -#define write_register(v,mem,off) iowrite32(v, mem) +#define write_register(v, mem, off) iowrite32(v, mem) static int copy_desc_data(struct xdma_transfer *transfer, char __user *buf, size_t *buf_offset, size_t buf_size) @@ -34,8 +35,15 @@ static int copy_desc_data(struct xdma_transfer *transfer, char __user *buf, int copy_err; int rc = 0; - BUG_ON(!buf); - BUG_ON(!buf_offset); + if (!buf) { + pr_err("Invalid user buffer\n"); + return -EINVAL; + } + + if (!buf_offset) { + pr_err("Invalid user buffer offset\n"); + return -EINVAL; + } /* Fill user buffer with descriptor data */ for (i = 0; i < transfer->desc_num; i++) { @@ -76,7 +84,7 @@ static ssize_t char_bypass_read(struct file *file, char __user *buf, xdev = xcdev->xdev; engine = xcdev->engine; - dbg_sg("In char_bypass_read()\n"); + dbg_sg("In %s()\n", __func__); if (count & 3) { dbg_sg("Buffer size must be a multiple of 4 bytes\n"); @@ -119,7 +127,7 @@ static ssize_t char_bypass_write(struct file *file, const char __user *buf, struct xdma_cdev *xcdev = (struct xdma_cdev *)file->private_data; u32 desc_data; - u32 *bypass_addr; + void __iomem *bypass_addr; size_t buf_offset = 0; int rc = 0; int copy_err; @@ -145,18 +153,21 @@ static ssize_t char_bypass_write(struct file *file, const char __user *buf, return -ENODEV; } - dbg_sg("In char_bypass_write()\n"); + dbg_sg("In %s()\n", __func__); spin_lock(&engine->lock); /* Write descriptor data to the bypass BAR */ - bypass_addr = (u32 *)xdev->bar[xdev->bypass_bar_idx]; - bypass_addr += engine->bypass_offset; + bypass_addr = xdev->bar[xdev->bypass_bar_idx]; + bypass_addr = (void __iomem *)( + (u32 __iomem *)bypass_addr + engine->bypass_offset + ); while (buf_offset < count) { copy_err = copy_from_user(&desc_data, &buf[buf_offset], sizeof(u32)); if (!copy_err) { - write_register(desc_data, bypass_addr, bypass_addr - engine->bypass_offset); + write_register(desc_data, bypass_addr, + bypass_addr - engine->bypass_offset); buf_offset += sizeof(u32); rc = buf_offset; } else { @@ -188,5 +199,5 @@ static const struct file_operations bypass_fops = { void cdev_bypass_init(struct xdma_cdev *xcdev) { - cdev_init(&xcdev->cdev, &bypass_fops); + cdev_init(&xcdev->cdev, &bypass_fops); } diff --git a/sdk/linux_kernel_drivers/xdma/cdev_ctrl.c b/sdk/linux_kernel_drivers/xdma/cdev_ctrl.c index 404bbd7f..9fa7a352 100644 --- a/sdk/linux_kernel_drivers/xdma/cdev_ctrl.c +++ b/sdk/linux_kernel_drivers/xdma/cdev_ctrl.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,6 +21,7 @@ * Karen Xie * ******************************************************************************/ + #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ #include @@ -28,6 +29,12 @@ #include "xdma_cdev.h" #include "cdev_ctrl.h" +#if KERNEL_VERSION(5, 0, 0) <= LINUX_VERSION_CODE +#define xlx_access_ok(X, Y, Z) access_ok(Y, Z) +#else +#define xlx_access_ok(X, Y, Z) access_ok(X, Y, Z) +#endif + /* * character device file operations for control bus (through control bridge) */ @@ -36,13 +43,13 @@ static ssize_t char_ctrl_read(struct file *fp, char __user *buf, size_t count, { struct xdma_cdev *xcdev = (struct xdma_cdev *)fp->private_data; struct xdma_dev *xdev; - void *reg; + void __iomem *reg; u32 w; int rv; rv = xcdev_check(__func__, xcdev, 0); if (rv < 0) - return rv; + return rv; xdev = xcdev->xdev; /* only 32-bit aligned and 32-bit multiples */ @@ -52,8 +59,8 @@ static ssize_t char_ctrl_read(struct file *fp, char __user *buf, size_t count, reg = xdev->bar[xcdev->bar] + *pos; //w = read_register(reg); w = ioread32(reg); - dbg_sg("char_ctrl_read(@%p, count=%ld, pos=%d) value = 0x%08x\n", reg, - (long)count, (int)*pos, w); + dbg_sg("%s(@%p, count=%ld, pos=%d) value = 0x%08x\n", + __func__, reg, (long)count, (int)*pos, w); rv = copy_to_user(buf, &w, 4); if (rv) dbg_sg("Copy to userspace failed but continuing\n"); @@ -67,13 +74,13 @@ static ssize_t char_ctrl_write(struct file *file, const char __user *buf, { struct xdma_cdev *xcdev = (struct xdma_cdev *)file->private_data; struct xdma_dev *xdev; - void *reg; + void __iomem *reg; u32 w; int rv; rv = xcdev_check(__func__, xcdev, 0); if (rv < 0) - return rv; + return rv; xdev = xcdev->xdev; /* only 32-bit aligned and 32-bit multiples */ @@ -83,12 +90,11 @@ static ssize_t char_ctrl_write(struct file *file, const char __user *buf, /* first address is BAR base plus file position offset */ reg = xdev->bar[xcdev->bar] + *pos; rv = copy_from_user(&w, buf, 4); - if (rv) { + if (rv) pr_info("copy from user failed %d/4, but continuing.\n", rv); - } - dbg_sg("char_ctrl_write(0x%08x @%p, count=%ld, pos=%d)\n", w, reg, - (long)count, (int)*pos); + dbg_sg("%s(0x%08x @%p, count=%ld, pos=%d)\n", + __func__, w, reg, (long)count, (int)*pos); //write_register(w, reg); iowrite32(w, reg); *pos += 4; @@ -133,9 +139,13 @@ long char_ctrl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) rv = xcdev_check(__func__, xcdev, 0); if (rv < 0) - return rv; - xdev = xcdev->xdev; + return rv; + xdev = xcdev->xdev; + if (!xdev) { + pr_info("cmd %u, xdev NULL.\n", cmd); + return -EINVAL; + } pr_info("cmd 0x%x, xdev 0x%p, pdev 0x%p.\n", cmd, xdev, xdev->pdev); if (_IOC_TYPE(cmd) != XDMA_IOC_MAGIC) { @@ -145,10 +155,10 @@ long char_ctrl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } if (_IOC_DIR(cmd) & _IOC_READ) - result = !access_ok(VERIFY_WRITE, (void __user *)arg, + result = !xlx_access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) - result = !access_ok(VERIFY_READ, (void __user *)arg, + result = !xlx_access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); if (result) { @@ -158,7 +168,7 @@ long char_ctrl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) switch (cmd) { case XDMA_IOCINFO: - if (copy_from_user((void *)&ioctl_obj, (void *) arg, + if (copy_from_user((void *)&ioctl_obj, (void __user *) arg, sizeof(struct xdma_ioc_base))) { pr_err("copy_from_user failed.\n"); return -EFAULT; @@ -169,20 +179,11 @@ long char_ctrl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ioctl_obj.magic, XDMA_XCL_MAGIC); return -ENOTTY; } - return version_ioctl(xcdev, (void __user *)arg); case XDMA_IOCOFFLINE: - if (!xdev) { - pr_info("cmd %u, xdev NULL.\n", cmd); - return -EINVAL; - } xdma_device_offline(xdev->pdev, xdev); break; case XDMA_IOCONLINE: - if (!xdev) { - pr_info("cmd %u, xdev NULL.\n", cmd); - return -EINVAL; - } xdma_device_online(xdev->pdev, xdev); break; default: @@ -205,7 +206,7 @@ int bridge_mmap(struct file *file, struct vm_area_struct *vma) rv = xcdev_check(__func__, xcdev, 0); if (rv < 0) - return rv; + return rv; xdev = xcdev->xdev; off = vma->vm_pgoff << PAGE_SHIFT; diff --git a/sdk/linux_kernel_drivers/xdma/cdev_ctrl.h b/sdk/linux_kernel_drivers/xdma/cdev_ctrl.h index 47e697cd..e0a9047b 100644 --- a/sdk/linux_kernel_drivers/xdma/cdev_ctrl.h +++ b/sdk/linux_kernel_drivers/xdma/cdev_ctrl.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,6 +21,7 @@ * Karen Xie * ******************************************************************************/ + #ifndef _XDMA_IOCALLS_POSIX_H_ #define _XDMA_IOCALLS_POSIX_H_ @@ -64,14 +65,14 @@ struct xdma_ioc_base { }; struct xdma_ioc_info { - struct xdma_ioc_base base; - unsigned short vendor; - unsigned short device; - unsigned short subsystem_vendor; - unsigned short subsystem_device; - unsigned int dma_engine_version; - unsigned int driver_version; - unsigned long long feature_id; + struct xdma_ioc_base base; + unsigned short vendor; + unsigned short device; + unsigned short subsystem_vendor; + unsigned short subsystem_device; + unsigned int dma_engine_version; + unsigned int driver_version; + unsigned long long feature_id; unsigned short domain; unsigned char bus; unsigned char dev; diff --git a/sdk/linux_kernel_drivers/xdma/cdev_events.c b/sdk/linux_kernel_drivers/xdma/cdev_events.c index 514aaf43..2b468ed7 100644 --- a/sdk/linux_kernel_drivers/xdma/cdev_events.c +++ b/sdk/linux_kernel_drivers/xdma/cdev_events.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -39,7 +39,7 @@ static ssize_t char_events_read(struct file *file, char __user *buf, rv = xcdev_check(__func__, xcdev, 0); if (rv < 0) - return rv; + return rv; user_irq = xcdev->user_irq; if (!user_irq) { pr_info("xcdev 0x%p, user_irq NULL.\n", xcdev); @@ -88,7 +88,7 @@ static unsigned int char_events_poll(struct file *file, poll_table *wait) rv = xcdev_check(__func__, xcdev, 0); if (rv < 0) - return rv; + return rv; user_irq = xcdev->user_irq; if (!user_irq) { pr_info("xcdev 0x%p, user_irq NULL.\n", xcdev); diff --git a/sdk/linux_kernel_drivers/xdma/cdev_sgdma.c b/sdk/linux_kernel_drivers/xdma/cdev_sgdma.c index 31854f92..2b615bb1 100644 --- a/sdk/linux_kernel_drivers/xdma/cdev_sgdma.c +++ b/sdk/linux_kernel_drivers/xdma/cdev_sgdma.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -23,6 +23,7 @@ ******************************************************************************/ #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ +#include #include #include "libxdma_api.h" #include "xdma_cdev.h" @@ -56,12 +57,9 @@ static loff_t char_sgdma_llseek(struct file *file, loff_t off, int whence) if (newpos < 0) return -EINVAL; file->f_pos = newpos; - dbg_fops("char_sgdma_llseek: pos=%lld\n", (signed long long)newpos); -#if 0 - pr_err("0x%p, off 0x%lld, whence %d -> pos %lld.\n", + dbg_fops("0x%p, off %lld, whence %d -> pos %lld.\n", file, (signed long long)off, whence, (signed long long)off); -#endif return newpos; } @@ -84,7 +82,10 @@ static loff_t char_sgdma_llseek(struct file *file, loff_t off, int whence) static int check_transfer_align(struct xdma_engine *engine, const char __user *buf, size_t count, loff_t pos, int sync) { - BUG_ON(!engine); + if (!engine) { + pr_err("Invalid DMA engine\n"); + return -EINVAL; + } /* AXI ST or AXI MM non-incremental addressing mode? */ if (engine->non_incr_addr) { @@ -175,17 +176,16 @@ static int char_sgdma_map_user_buf_to_sgl(struct xdma_io_cb *cb, bool write) { struct sg_table *sgt = &cb->sgt; unsigned long len = cb->len; - char *buf = cb->buf; + char __user *buf = cb->buf; struct scatterlist *sg; - unsigned int pages_nr = (((unsigned long)buf + len + PAGE_SIZE -1) - + unsigned int pages_nr = (((unsigned long)buf + len + PAGE_SIZE - 1) - ((unsigned long)buf & PAGE_MASK)) >> PAGE_SHIFT; int i; int rv; - if (pages_nr == 0) { + if (pages_nr == 0) return -EINVAL; - } if (sg_alloc_table(sgt, pages_nr, GFP_KERNEL)) { pr_err("sgl OOM.\n"); @@ -211,8 +211,8 @@ static int char_sgdma_map_user_buf_to_sgl(struct xdma_io_cb *cb, bool write) if (rv != pages_nr) { pr_err("unable to pin down all %u user pages, %d.\n", pages_nr, rv); - rv = -EFAULT; cb->pages_nr = rv; + rv = -EFAULT; goto err_out; } @@ -228,9 +228,9 @@ static int char_sgdma_map_user_buf_to_sgl(struct xdma_io_cb *cb, bool write) sg = sgt->sgl; for (i = 0; i < pages_nr; i++, sg = sg_next(sg)) { - //unsigned int offset = (uintptr_t)buf & ~PAGE_MASK; unsigned int offset = offset_in_page(buf); - unsigned int nbytes = min_t(unsigned int, PAGE_SIZE - offset, len); + unsigned int nbytes = min_t(unsigned int, + PAGE_SIZE - offset, len); flush_dcache_page(cb->pages[i]); sg_set_page(sg, cb->pages[i], nbytes, offset); @@ -239,7 +239,11 @@ static int char_sgdma_map_user_buf_to_sgl(struct xdma_io_cb *cb, bool write) len -= nbytes; } - BUG_ON(len); + if (len) { + pr_err("Invalid user buffer length. Cannot map to sgl\n"); + return -EINVAL; + } + cb->pages_nr = pages_nr; return 0; @@ -249,7 +253,7 @@ static int char_sgdma_map_user_buf_to_sgl(struct xdma_io_cb *cb, bool write) return rv; } -static ssize_t char_sgdma_read_write(struct file *file, char __user *buf, +static ssize_t char_sgdma_read_write(struct file *file, const char __user *buf, size_t count, loff_t *pos, bool write) { int rv; @@ -283,7 +287,7 @@ static ssize_t char_sgdma_read_write(struct file *file, char __user *buf, } memset(&cb, 0, sizeof(struct xdma_io_cb)); - cb.buf = buf; + cb.buf = (char __user *)buf; cb.len = count; rv = char_sgdma_map_user_buf_to_sgl(&cb, write); if (rv < 0) @@ -291,10 +295,6 @@ static ssize_t char_sgdma_read_write(struct file *file, char __user *buf, res = xdma_xfer_submit(xdev, engine->channel, write, *pos, &cb.sgt, 0, sgdma_timeout * 1000); - //pr_err("xfer_submit return=%lld.\n", (s64)res); - - //interrupt_status(xdev); - char_sgdma_unmap_user_buf(&cb, write); return res; @@ -302,138 +302,134 @@ static ssize_t char_sgdma_read_write(struct file *file, char __user *buf, static ssize_t char_sgdma_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) + size_t count, loff_t *pos) { - return char_sgdma_read_write(file, (char *)buf, count, pos, 1); + return char_sgdma_read_write(file, (char *)buf, count, pos, 1); } static ssize_t char_sgdma_read(struct file *file, char __user *buf, - size_t count, loff_t *pos) + size_t count, loff_t *pos) { - struct xdma_cdev *xcdev = (struct xdma_cdev *)file->private_data; - struct xdma_engine *engine; - int rv; - - rv = xcdev_check(__func__, xcdev, 1); - if (rv < 0) - return rv; - - engine = xcdev->engine; - - if (engine->streaming && engine->dir == DMA_FROM_DEVICE) { - rv = xdma_cyclic_transfer_setup(engine); - if (rv < 0 && rv != -EBUSY) - return rv; - /* 600 sec. timeout */ - return xdma_engine_read_cyclic(engine, buf, count, 600000); - } - - return char_sgdma_read_write(file, (char *)buf, count, pos, 0); + return char_sgdma_read_write(file, (char *)buf, count, pos, 0); } static int ioctl_do_perf_start(struct xdma_engine *engine, unsigned long arg) { - int rv; - struct xdma_dev *xdev; - - BUG_ON(!engine); - xdev = engine->xdev; - BUG_ON(!xdev); - - /* performance measurement already running on this engine? */ - if (engine->xdma_perf) { - dbg_perf("IOCTL_XDMA_PERF_START failed!\n"); - dbg_perf("Perf measurement already seems to be running!\n"); - return -EBUSY; - } - engine->xdma_perf = kzalloc(sizeof(struct xdma_performance_ioctl), - GFP_KERNEL); + int rv; + struct xdma_dev *xdev; - if (!engine->xdma_perf) - return -ENOMEM; + if (!engine || !engine->xdev) { + pr_err("Invalid DMA engine 0x%p, 0x%p.\n", + engine, engine ? engine->xdev : NULL); + return -EINVAL; + } - rv = copy_from_user(engine->xdma_perf, - (struct xdma_performance_ioctl *)arg, - sizeof(struct xdma_performance_ioctl)); + xdev = engine->xdev; - if (rv < 0) { - dbg_perf("Failed to copy from user space 0x%lx\n", arg); - return -EINVAL; - } - if (engine->xdma_perf->version != IOCTL_XDMA_PERF_V1) { - dbg_perf("Unsupported IOCTL version %d\n", - engine->xdma_perf->version); - return -EINVAL; - } + /* if performance measurement already running on this engine */ + if (engine->xdma_perf) { + dbg_perf("Perf measurement already seems to be running!\n"); + return -EBUSY; + } + + engine->xdma_perf = kzalloc(sizeof(struct xdma_performance_ioctl), + GFP_KERNEL); + if (!engine->xdma_perf) + return -ENOMEM; + + rv = copy_from_user(engine->xdma_perf, + (struct xdma_performance_ioctl *)arg, + sizeof(struct xdma_performance_ioctl)); + if (rv < 0) { + dbg_perf("Failed to copy from user space 0x%lx\n", arg); + return -EINVAL; + } + if (engine->xdma_perf->version != IOCTL_XDMA_PERF_V1) { + dbg_perf("Unsupported IOCTL version %d\n", + engine->xdma_perf->version); + return -EINVAL; + } enable_perf(engine); - dbg_perf("transfer_size = %d\n", engine->xdma_perf->transfer_size); - /* initialize wait queue */ - init_waitqueue_head(&engine->xdma_perf_wq); - xdma_performance_submit(xdev, engine); + dbg_perf("transfer_size = %d\n", engine->xdma_perf->transfer_size); + + /* initialize wait queue */ + init_waitqueue_head(&engine->xdma_perf_wq); + + rv = xdma_performance_submit(xdev, engine); + if (rv < 0) + pr_err("Failed to submit dma performance\n"); - return 0; + return 0; } static int ioctl_do_perf_stop(struct xdma_engine *engine, unsigned long arg) { - struct xdma_transfer *transfer = NULL; - int rv; - - dbg_perf("IOCTL_XDMA_PERF_STOP\n"); + struct xdma_transfer *transfer = NULL; + int rv; - /* no performance measurement running on this engine? */ - if (!engine->xdma_perf) { - dbg_perf("No measurement in progress\n"); - return -EINVAL; - } + if (!engine) { + pr_err("DMA engine NULL.\n"); + return -EINVAL; + } - /* stop measurement */ - transfer = engine_cyclic_stop(engine); - dbg_perf("Waiting for measurement to stop\n"); + dbg_perf("IOCTL_XDMA_PERF_STOP\n"); - if (engine->xdma_perf) { - get_perf_stats(engine); + /* if no performance measurement running on this engine */ + if (!engine->xdma_perf) { + dbg_perf("No measurement in progress\n"); + return -EINVAL; + } - rv = copy_to_user((void __user *)arg, engine->xdma_perf, - sizeof(struct xdma_performance_ioctl)); - if (rv) { - dbg_perf("Error copying result to user\n"); - return -EINVAL; - } - } else { - dbg_perf("engine->xdma_perf == NULL?\n"); + /* stop measurement */ + dbg_perf("Waiting for measurement to stop\n"); + transfer = engine_cyclic_stop(engine); + if (!transfer) { + pr_err("Failed to stop cyclic transfer\n"); + return -EINVAL; } - kfree(engine->xdma_perf); - engine->xdma_perf = NULL; + get_perf_stats(engine); + rv = copy_to_user((void __user *)arg, engine->xdma_perf, + sizeof(struct xdma_performance_ioctl)); + if (rv) { + dbg_perf("Error copying result to user\n"); + return -EINVAL; + } + + kfree(transfer); + kfree(engine->xdma_perf); + engine->xdma_perf = NULL; - return 0; + return 0; } static int ioctl_do_perf_get(struct xdma_engine *engine, unsigned long arg) { - int rc; + int rc; - BUG_ON(!engine); + if (!engine) { + pr_err("DMA engine NULL.\n"); + return -EINVAL; + } - dbg_perf("IOCTL_XDMA_PERF_GET\n"); + dbg_perf("IOCTL_XDMA_PERF_GET\n"); - if (engine->xdma_perf) { + if (engine->xdma_perf) { get_perf_stats(engine); - rc = copy_to_user((void __user *)arg, engine->xdma_perf, - sizeof(struct xdma_performance_ioctl)); - if (rc) { - dbg_perf("Error copying result to user\n"); - return -EINVAL; - } - } else { - dbg_perf("engine->xdma_perf == NULL?\n"); - return -EPROTO; - } + rc = copy_to_user((void __user *)arg, engine->xdma_perf, + sizeof(struct xdma_performance_ioctl)); + if (rc) { + dbg_perf("Error copying result to user\n"); + return -EINVAL; + } + } else { + dbg_perf("engine->xdma_perf == NULL?\n"); + return -EPROTO; + } - return 0; + return 0; } static int ioctl_do_addrmode_set(struct xdma_engine *engine, unsigned long arg) @@ -446,7 +442,10 @@ static int ioctl_do_addrmode_get(struct xdma_engine *engine, unsigned long arg) int rv; unsigned long src; - BUG_ON(!engine); + if (!engine) { + pr_err("DMA engine NULL.\n"); + return -EINVAL; + } src = !!engine->non_incr_addr; dbg_perf("IOCTL_XDMA_ADDRMODE_GET\n"); @@ -455,22 +454,24 @@ static int ioctl_do_addrmode_get(struct xdma_engine *engine, unsigned long arg) return rv; } -static int ioctl_do_align_get(struct xdma_engine *engine, unsigned long arg) +static int ioctl_do_align_get(struct xdma_engine *engine, unsigned long arg) { - BUG_ON(!engine); + if (!engine) { + pr_err("DMA engine NULL.\n"); + return -EINVAL; + } dbg_perf("IOCTL_XDMA_ALIGN_GET\n"); return put_user(engine->addr_align, (int __user *)arg); } static long char_sgdma_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) + unsigned long arg) { struct xdma_cdev *xcdev = (struct xdma_cdev *)file->private_data; struct xdma_dev *xdev; struct xdma_engine *engine; - - int rv = 0; + int rv = 0; rv = xcdev_check(__func__, xcdev, 1); if (rv < 0) @@ -480,15 +481,15 @@ static long char_sgdma_ioctl(struct file *file, unsigned int cmd, engine = xcdev->engine; switch (cmd) { - case IOCTL_XDMA_PERF_START: - rv = ioctl_do_perf_start(engine, arg); - break; - case IOCTL_XDMA_PERF_STOP: - rv = ioctl_do_perf_stop(engine, arg); - break; - case IOCTL_XDMA_PERF_GET: - rv = ioctl_do_perf_get(engine, arg); - break; + case IOCTL_XDMA_PERF_START: + rv = ioctl_do_perf_start(engine, arg); + break; + case IOCTL_XDMA_PERF_STOP: + rv = ioctl_do_perf_stop(engine, arg); + break; + case IOCTL_XDMA_PERF_GET: + rv = ioctl_do_perf_get(engine, arg); + break; case IOCTL_XDMA_ADDRMODE_SET: rv = ioctl_do_addrmode_set(engine, arg); break; @@ -498,13 +499,13 @@ static long char_sgdma_ioctl(struct file *file, unsigned int cmd, case IOCTL_XDMA_ALIGN_GET: rv = ioctl_do_align_get(engine, arg); break; - default: - dbg_perf("Unsupported operation\n"); - rv = -EINVAL; - break; - } + default: + dbg_perf("Unsupported operation 0x%x.\n", cmd); + rv = -EINVAL; + break; + } - return rv; + return rv; } static int char_sgdma_open(struct inode *inode, struct file *file) @@ -520,8 +521,7 @@ static int char_sgdma_open(struct inode *inode, struct file *file) if (engine->streaming && engine->dir == DMA_FROM_DEVICE) { if (engine->device_open == 1) return -EBUSY; - else - engine->device_open = 1; + engine->device_open = 1; } return 0; diff --git a/sdk/linux_kernel_drivers/xdma/cdev_sgdma.h b/sdk/linux_kernel_drivers/xdma/cdev_sgdma.h index c67bf99f..4f0a38cc 100644 --- a/sdk/linux_kernel_drivers/xdma/cdev_sgdma.h +++ b/sdk/linux_kernel_drivers/xdma/cdev_sgdma.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,6 +21,7 @@ * Karen Xie * ******************************************************************************/ + #ifndef _XDMA_IOCALLS_POSIX_H_ #define _XDMA_IOCALLS_POSIX_H_ @@ -50,17 +51,16 @@ * _IOC_SIZE(nr) returns size */ -struct xdma_performance_ioctl -{ - /* IOCTL_XDMA_IOCTL_Vx */ - uint32_t version; - uint32_t transfer_size; - /* measurement */ - uint32_t stopped; - uint32_t iterations; - uint64_t clock_cycle_count; - uint64_t data_cycle_count; - uint64_t pending_count; +struct xdma_performance_ioctl { + /* IOCTL_XDMA_IOCTL_Vx */ + uint32_t version; + uint32_t transfer_size; + /* measurement */ + uint32_t stopped; + uint32_t iterations; + uint64_t clock_cycle_count; + uint64_t data_cycle_count; + uint64_t pending_count; }; diff --git a/sdk/linux_kernel_drivers/xdma/cdev_xvc.c b/sdk/linux_kernel_drivers/xdma/cdev_xvc.c index adafa7fc..e346bc79 100644 --- a/sdk/linux_kernel_drivers/xdma/cdev_xvc.c +++ b/sdk/linux_kernel_drivers/xdma/cdev_xvc.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,6 +21,7 @@ * Karen Xie * ******************************************************************************/ + #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ #include "xdma_cdev.h" @@ -36,30 +37,30 @@ #ifdef __REG_DEBUG__ /* SECTION: Function definitions */ -inline void __write_register(const char *fn, u32 value, void *base, +inline void __write_register(const char *fn, u32 value, void __iomem *base, unsigned int off) { - pr_info("%s: 0x%p, W reg 0x%lx, 0x%x.\n", fn, base, off, value); - iowrite32(value, base + off); + pr_info("%s: 0x%p, W reg 0x%lx, 0x%x.\n", fn, base, off, value); + iowrite32(value, base + off); } -inline u32 __read_register(const char *fn, void *base, unsigned int off) +inline u32 __read_register(const char *fn, void __iomem *base, unsigned int off) { u32 v = ioread32(base + off); - pr_info("%s: 0x%p, R reg 0x%lx, 0x%x.\n", fn, base, off, v); - return v; + pr_info("%s: 0x%p, R reg 0x%lx, 0x%x.\n", fn, base, off, v); + return v; } -#define write_register(v,base,off) __write_register(__func__, v, base, off) -#define read_register(base,off) __read_register(__func__, base, off) +#define write_register(v, base, off) __write_register(__func__, v, base, off) +#define read_register(base, off) __read_register(__func__, base, off) #else -#define write_register(v,base,off) iowrite32(v, (base) + (off)) -#define read_register(base,off) ioread32((base) + (off)) +#define write_register(v, base, off) iowrite32(v, (base) + (off)) +#define read_register(base, off) ioread32((base) + (off)) #endif /* #ifdef __REG_DEBUG__ */ -static int xvc_shift_bits(void *base, u32 tms_bits, u32 tdi_bits, +static int xvc_shift_bits(void __iomem *base, u32 tms_bits, u32 tdi_bits, u32 *tdo_bits) { u32 control; @@ -96,7 +97,7 @@ static int xvc_shift_bits(void *base, u32 tms_bits, u32 tdi_bits, static long xvc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - struct xdma_cdev *xcdev = (struct xdma_cdev *)filp->private_data; + struct xdma_cdev *xcdev = (struct xdma_cdev *)filp->private_data; struct xdma_dev *xdev; struct xvc_ioc xvc_obj; unsigned int opcode; @@ -113,6 +114,7 @@ static long xvc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) rv = xcdev_check(__func__, xcdev, 0); if (rv < 0) return rv; + xdev = xcdev->xdev; if (cmd != XDMA_IOCXVC) { @@ -139,7 +141,7 @@ static long xvc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) total_bits = xvc_obj.length; total_bytes = (total_bits + 7) >> 3; - buffer = (char *)kmalloc(total_bytes * 3, GFP_KERNEL); + buffer = kmalloc(total_bytes * 3, GFP_KERNEL); if (!buffer) { pr_info("OOM %u, op 0x%x, len %u bits, %u bytes.\n", 3 * total_bytes, opcode, total_bits, total_bytes); @@ -150,12 +152,16 @@ static long xvc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) tdi_buf = tms_buf + total_bytes; tdo_buf = tdi_buf + total_bytes; - rv = copy_from_user((void *)tms_buf, xvc_obj.tms_buf, total_bytes); + rv = copy_from_user((void *)tms_buf, + (const char __user *)xvc_obj.tms_buf, + total_bytes); if (rv) { pr_info("copy tmfs_buf failed: %d/%u.\n", rv, total_bytes); goto cleanup; } - rv = copy_from_user((void *)tdi_buf, xvc_obj.tdi_buf, total_bytes); + rv = copy_from_user((void *)tdi_buf, + (const char __user *)xvc_obj.tdi_buf, + total_bytes); if (rv) { pr_info("copy tdi_buf failed: %d/%u.\n", rv, total_bytes); goto cleanup; @@ -166,7 +172,8 @@ static long xvc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) iobase = xdev->bar[xcdev->bar] + xcdev->base; /* set length register to 32 initially if more than one - * word-transaction is to be done */ + * word-transaction is to be done + */ if (total_bits >= 32) write_register(0x20, iobase, XVC_BAR_LENGTH_REG); @@ -177,7 +184,7 @@ static long xvc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) u32 tms_store = 0; u32 tdi_store = 0; u32 tdo_store = 0; - + if (bits_left < 32) { /* set number of bits to shift out */ write_register(bits_left, iobase, XVC_BAR_LENGTH_REG); @@ -190,33 +197,35 @@ static long xvc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* Shift data out and copy to output buffer */ rv = xvc_shift_bits(iobase, tms_store, tdi_store, &tdo_store); if (rv < 0) - goto cleanup; + break; memcpy(tdo_buf + bytes, &tdo_store, shift_bytes); } + if (rv < 0) + goto unlock; + /* if testing bar access swap tdi and tdo bufferes to "loopback" */ if (opcode == 0x2) { - char *tmp = tdo_buf; + unsigned char *tmp = tdo_buf; tdo_buf = tdi_buf; tdi_buf = tmp; } - rv = copy_to_user((void *)xvc_obj.tdo_buf, tdo_buf, total_bytes); - if (rv) { + rv = copy_to_user(xvc_obj.tdo_buf, (const void *)tdo_buf, total_bytes); + if (rv) pr_info("copy back tdo_buf failed: %d/%u.\n", rv, total_bytes); - rv = -EFAULT; - goto cleanup; - } - -cleanup: - if (buffer) - kfree(buffer); - mmiowb(); +unlock: +#if KERNEL_VERSION(5, 1, 0) >= LINUX_VERSION_CODE + wmb(); +#endif spin_unlock(&xcdev->lock); +cleanup: + kfree(buffer); + return rv; } @@ -224,10 +233,10 @@ static long xvc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) * character device file operations for the XVC */ static const struct file_operations xvc_fops = { - .owner = THIS_MODULE, - .open = char_open, - .release = char_close, - .unlocked_ioctl = xvc_ioctl, + .owner = THIS_MODULE, + .open = char_open, + .release = char_close, + .unlocked_ioctl = xvc_ioctl, }; void cdev_xvc_init(struct xdma_cdev *xcdev) diff --git a/sdk/linux_kernel_drivers/xdma/cdev_xvc.h b/sdk/linux_kernel_drivers/xdma/cdev_xvc.h index de9473a3..9a2b8689 100644 --- a/sdk/linux_kernel_drivers/xdma/cdev_xvc.h +++ b/sdk/linux_kernel_drivers/xdma/cdev_xvc.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,14 +21,14 @@ * Karen Xie * ******************************************************************************/ + #ifndef __XVC_IOCTL_H__ #define __XVC_IOCTL_H__ #include /* - * !!! TODO !!! - * need a better way set the bar offset dynamicly + * the bar offset can be changed at compile time via xvc_bar_offset */ #define XVC_BAR_OFFSET_DFLT 0x40000 /* DSA 4.0 */ @@ -37,9 +37,9 @@ struct xvc_ioc { unsigned int opcode; unsigned int length; - unsigned char *tms_buf; - unsigned char *tdi_buf; - unsigned char *tdo_buf; + const char __user *tms_buf; + const char __user *tdi_buf; + void __user *tdo_buf; }; #define XDMA_IOCXVC _IOWR(XVC_MAGIC, 1, struct xvc_ioc) diff --git a/sdk/linux_kernel_drivers/xdma/libxdma.c b/sdk/linux_kernel_drivers/xdma/libxdma.c old mode 100755 new mode 100644 index 32523e50..9dc519b6 --- a/sdk/linux_kernel_drivers/xdma/libxdma.c +++ b/sdk/linux_kernel_drivers/xdma/libxdma.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -36,23 +36,6 @@ #include "libxdma_api.h" #include "cdev_sgdma.h" -/* SECTION: Module licensing */ - -#ifdef __LIBXDMA_MOD__ -#include "version.h" -#define DRV_MODULE_NAME "libxdma" -#define DRV_MODULE_DESC "Xilinx XDMA Base Driver" -#define DRV_MODULE_RELDATE "Feb. 2017" - -static char version[] = - DRV_MODULE_DESC " " DRV_MODULE_NAME " v" DRV_MODULE_VERSION "\n"; - -MODULE_AUTHOR("Xilinx, Inc."); -MODULE_DESCRIPTION(DRV_MODULE_DESC); -MODULE_VERSION(DRV_MODULE_VERSION); -MODULE_LICENSE("GPL v2"); -#endif - /* Module Parameters */ static unsigned int poll_mode; module_param(poll_mode, uint, 0644); @@ -123,19 +106,18 @@ static inline void xdev_list_remove(struct xdma_dev *xdev) struct xdma_dev *xdev_find_by_pdev(struct pci_dev *pdev) { - struct xdma_dev *xdev, *tmp; - - mutex_lock(&xdev_mutex); - list_for_each_entry_safe(xdev, tmp, &xdev_list, list_head) { - if (xdev->pdev == pdev) { - mutex_unlock(&xdev_mutex); - return xdev; - } - } - mutex_unlock(&xdev_mutex); - return NULL; + struct xdma_dev *xdev, *tmp; + + mutex_lock(&xdev_mutex); + list_for_each_entry_safe(xdev, tmp, &xdev_list, list_head) { + if (xdev->pdev == pdev) { + mutex_unlock(&xdev_mutex); + return xdev; + } + } + mutex_unlock(&xdev_mutex); + return NULL; } -EXPORT_SYMBOL_GPL(xdev_find_by_pdev); static inline int debug_check_dev_hndl(const char *fname, struct pci_dev *pdev, void *hndl) @@ -167,9 +149,9 @@ inline void __write_register(const char *fn, u32 value, void *iomem, unsigned lo pr_err("%s: w reg 0x%lx(0x%p), 0x%x.\n", fn, off, iomem, value); iowrite32(value, iomem); } -#define write_register(v,mem,off) __write_register(__func__, v, mem, off) +#define write_register(v, mem, off) __write_register(__func__, v, mem, off) #else -#define write_register(v,mem,off) iowrite32(v, mem) +#define write_register(v, mem, off) iowrite32(v, mem) #endif inline u32 read_register(void *iomem) @@ -200,7 +182,7 @@ static void check_nonzero_interrupt_status(struct xdma_dev *xdev) w = read_register(®->channel_int_enable); if (w) - pr_info("%s xdma%d channel_int_enable = 0x%08x\n", + pr_info("%s xdma%d channel_int_enable = 0x%08x\n", dev_name(&xdev->pdev->dev), xdev->idx, w); w = read_register(®->user_int_request); @@ -296,14 +278,16 @@ void enable_perf(struct xdma_engine *engine) dbg_perf("IOCTL_XDMA_PERF_START\n"); } -EXPORT_SYMBOL_GPL(enable_perf); void get_perf_stats(struct xdma_engine *engine) { u32 hi; u32 lo; - BUG_ON(!engine); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return; + } if (!engine->xdma_perf) { pr_info("%s perf struct not set up.\n", engine->name); @@ -327,13 +311,15 @@ void get_perf_stats(struct xdma_engine *engine) lo = read_register(&engine->regs->perf_pnd_lo); engine->xdma_perf->pending_count = build_u64(hi, lo); } -EXPORT_SYMBOL_GPL(get_perf_stats); static void engine_reg_dump(struct xdma_engine *engine) { u32 w; - BUG_ON(!engine); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return; + } w = read_register(&engine->regs->identifier); pr_info("%s: ioread32(0x%p) = 0x%08x (id).\n", @@ -391,8 +377,8 @@ static void engine_status_dump(struct xdma_engine *engine) if ((v & XDMA_STAT_DESC_COMPLETED)) len += sprintf(buf + len, "DESC_COMPL,"); - /* common H2C & C2H */ - if ((v & XDMA_STAT_COMMON_ERR_MASK)) { + /* common H2C & C2H */ + if ((v & XDMA_STAT_COMMON_ERR_MASK)) { if ((v & XDMA_STAT_ALIGN_MISMATCH)) len += sprintf(buf + len, "ALIGN_MISMATCH "); if ((v & XDMA_STAT_MAGIC_STOPPED)) @@ -404,7 +390,7 @@ static void engine_status_dump(struct xdma_engine *engine) buf[len - 1] = ','; } - if ((engine->dir == DMA_TO_DEVICE)) { + if (engine->dir == DMA_TO_DEVICE) { /* H2C only */ if ((v & XDMA_STAT_H2C_R_ERR_MASK)) { len += sprintf(buf + len, "R:"); @@ -442,8 +428,8 @@ static void engine_status_dump(struct xdma_engine *engine) } } - /* common H2C & C2H */ - if ((v & XDMA_STAT_DESC_ERR_MASK)) { + /* common H2C & C2H */ + if ((v & XDMA_STAT_DESC_ERR_MASK)) { len += sprintf(buf + len, "DESC_ERR:"); if ((v & XDMA_STAT_DESC_UNSUPP_REQ)) len += sprintf(buf + len, "UNSUPP_REQ "); @@ -462,26 +448,24 @@ static void engine_status_dump(struct xdma_engine *engine) pr_info("%s\n", buffer); } -static u32 engine_status_read(struct xdma_engine *engine, bool clear, bool dump) +static void engine_status_read(struct xdma_engine *engine, bool clr, bool dump) { - u32 value; - - BUG_ON(!engine); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return; + } if (dump) engine_reg_dump(engine); /* read status register */ - if (clear) - value = engine->status = - read_register(&engine->regs->status_rc); + if (clr) + engine->status = read_register(&engine->regs->status_rc); else - value = engine->status = read_register(&engine->regs->status); + engine->status = read_register(&engine->regs->status); if (dump) engine_status_dump(engine); - - return value; } /** @@ -492,7 +476,10 @@ static void xdma_engine_stop(struct xdma_engine *engine) { u32 w; - BUG_ON(!engine); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return; + } dbg_tfr("xdma_engine_stop(engine=%p)\n", engine); w = 0; @@ -526,7 +513,10 @@ static void engine_start_mode_config(struct xdma_engine *engine) { u32 w; - BUG_ON(!engine); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return; + } /* If a perf test is running, enable the engine interrupts */ if (engine->xdma_perf) { @@ -559,11 +549,10 @@ static void engine_start_mode_config(struct xdma_engine *engine) if ((engine->streaming && (engine->dir == DMA_FROM_DEVICE)) || (engine->xdma_perf)) w |= (u32)XDMA_CTRL_IE_IDLE_STOPPED; - - /* set non-incremental addressing mode */ - if (engine->non_incr_addr) - w |= (u32)XDMA_CTRL_NON_INCR_ADDR; } + /* set non-incremental addressing mode */ + if (engine->non_incr_addr) + w |= (u32)XDMA_CTRL_NON_INCR_ADDR; dbg_tfr("iowrite32(0x%08x to 0x%p) (control)\n", w, (void *)&engine->regs->control); @@ -601,13 +590,22 @@ static struct xdma_transfer *engine_start(struct xdma_engine *engine) int extra_adj = 0; /* engine must be idle */ - BUG_ON(engine->running); + if (unlikely(!engine || engine->running)) { + pr_err("engine 0x%p running.\n", engine); + return NULL; + } /* engine transfer queue must not be empty */ - BUG_ON(list_empty(&engine->transfer_list)); + if (unlikely(list_empty(&engine->transfer_list))) { + pr_err("engine %s queue empty.\n", engine->name); + return NULL; + } /* inspect first transfer queued on the engine */ transfer = list_entry(engine->transfer_list.next, struct xdma_transfer, entry); - BUG_ON(!transfer); + if (unlikely(!transfer)) { + pr_err("engine %s no xfer queued.\n", engine->name); + return NULL; + } /* engine is no longer shutdown */ engine->shutdown = ENGINE_SHUTDOWN_NONE; @@ -645,8 +643,9 @@ static struct xdma_transfer *engine_start(struct xdma_engine *engine) dbg_tfr("ioread32(0x%p) (dummy read flushes writes).\n", &engine->regs->status); +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 1, 0) mmiowb(); - +#endif engine_start_mode_config(engine); engine_status_read(engine, 0, 0); @@ -679,7 +678,10 @@ static void engine_service_shutdown(struct xdma_engine *engine) struct xdma_transfer *engine_transfer_completion(struct xdma_engine *engine, struct xdma_transfer *transfer) { - BUG_ON(!engine); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return NULL; + } if (unlikely(!transfer)) { pr_info("%s: xfer empty.\n", engine->name); @@ -696,12 +698,9 @@ struct xdma_transfer *engine_transfer_completion(struct xdma_engine *engine, struct xdma_transfer *engine_service_transfer_list(struct xdma_engine *engine, struct xdma_transfer *transfer, u32 *pdesc_completed) { - BUG_ON(!engine); - BUG_ON(!pdesc_completed); - - if (unlikely(!transfer)) { - pr_info("%s xfer empty, pdesc completed %u.\n", - engine->name, *pdesc_completed); + if (unlikely(!engine || !pdesc_completed || !transfer)) { + pr_err("engine 0x%p, pdesc_completed 0x%p, xfer 0x%p.\n", + engine, pdesc_completed, transfer); return NULL; } @@ -752,16 +751,16 @@ static void engine_err_handle(struct xdma_engine *engine, */ if (engine->status & XDMA_STAT_BUSY) { value = read_register(&engine->regs->status); - if ((value & XDMA_STAT_BUSY) && printk_ratelimit()) - pr_info("%s has errors but is still BUSY\n", - engine->name); + if ((value & XDMA_STAT_BUSY)) + printk_ratelimited(KERN_INFO + "%s has errors but is still BUSY\n", + engine->name); } - if (printk_ratelimit()) { - pr_info("%s, s 0x%x, aborted xfer 0x%p, cmpl %d/%d\n", + printk_ratelimited(KERN_INFO + "%s, s 0x%x, aborted xfer 0x%p, cmpl %d/%d\n", engine->name, engine->status, transfer, desc_completed, transfer->desc_num); - } /* mark transfer as failed */ transfer->state = TRANSFER_STATE_FAILED; @@ -771,72 +770,71 @@ static void engine_err_handle(struct xdma_engine *engine, struct xdma_transfer *engine_service_final_transfer(struct xdma_engine *engine, struct xdma_transfer *transfer, u32 *pdesc_completed) { - BUG_ON(!engine); - BUG_ON(!pdesc_completed); - - /* inspect the current transfer */ - if (unlikely(!transfer)) { - pr_info("%s xfer empty, pdesc completed %u.\n", - engine->name, *pdesc_completed); + if (unlikely(!engine || !pdesc_completed || !transfer)) { + pr_err("engine 0x%p, pdesc_completed 0x%p, xfer 0x%p.\n", + engine, pdesc_completed, transfer); return NULL; - } else { - if (((engine->dir == DMA_FROM_DEVICE) && - (engine->status & XDMA_STAT_C2H_ERR_MASK)) || - ((engine->dir == DMA_TO_DEVICE) && - (engine->status & XDMA_STAT_H2C_ERR_MASK))) { - pr_info("engine %s, status error 0x%x.\n", - engine->name, engine->status); - engine_status_dump(engine); - engine_err_handle(engine, transfer, *pdesc_completed); - goto transfer_del; - } + } + /* inspect the current transfer */ + if (((engine->dir == DMA_FROM_DEVICE) && + (engine->status & XDMA_STAT_C2H_ERR_MASK)) || + ((engine->dir == DMA_TO_DEVICE) && + (engine->status & XDMA_STAT_H2C_ERR_MASK))) { + pr_info("engine %s, status error 0x%x.\n", + engine->name, engine->status); + engine_status_dump(engine); + engine_err_handle(engine, transfer, *pdesc_completed); + goto transfer_del; + } - if (engine->status & XDMA_STAT_BUSY) - pr_debug("engine %s is unexpectedly busy - ignoring\n", - engine->name); + if (engine->status & XDMA_STAT_BUSY) + pr_debug("engine %s is unexpectedly busy - ignoring\n", + engine->name); - /* the engine stopped on current transfer? */ - if (*pdesc_completed < transfer->desc_num) { - transfer->state = TRANSFER_STATE_FAILED; - pr_info("%s, xfer 0x%p, stopped half-way, %d/%d.\n", - engine->name, transfer, *pdesc_completed, - transfer->desc_num); - } else { - dbg_tfr("engine %s completed transfer\n", engine->name); - dbg_tfr("Completed transfer ID = 0x%p\n", transfer); - dbg_tfr("*pdesc_completed=%d, transfer->desc_num=%d", - *pdesc_completed, transfer->desc_num); - - if (!transfer->cyclic) { - /* - * if the engine stopped on this transfer, - * it should be the last - */ - WARN_ON(*pdesc_completed > transfer->desc_num); - } - /* mark transfer as succesfully completed */ - transfer->state = TRANSFER_STATE_COMPLETED; + /* the engine stopped on current transfer? */ + if (*pdesc_completed < transfer->desc_num) { + transfer->state = TRANSFER_STATE_FAILED; + pr_info("%s, xfer 0x%p, stopped half-way, %d/%d.\n", + engine->name, transfer, *pdesc_completed, + transfer->desc_num); + } else { + dbg_tfr("engine %s completed transfer\n", engine->name); + dbg_tfr("Completed transfer ID = 0x%p\n", transfer); + dbg_tfr("*pdesc_completed=%d, transfer->desc_num=%d", + *pdesc_completed, transfer->desc_num); + + if (!transfer->cyclic) { + /* + * if the engine stopped on this transfer, + * it should be the last + */ + WARN_ON(*pdesc_completed > transfer->desc_num); } + /* mark transfer as succesfully completed */ + transfer->state = TRANSFER_STATE_COMPLETED; + } transfer_del: - /* remove completed transfer from list */ - list_del(engine->transfer_list.next); - /* add to dequeued number of descriptors during this run */ - engine->desc_dequeued += transfer->desc_num; + /* remove completed transfer from list */ + list_del(engine->transfer_list.next); + /* add to dequeued number of descriptors during this run */ + engine->desc_dequeued += transfer->desc_num; - /* - * Complete transfer - sets transfer to NULL if an asynchronous - * transfer has completed - */ - transfer = engine_transfer_completion(engine, transfer); - } + /* + * Complete transfer - sets transfer to NULL if an asynchronous + * transfer has completed + */ + transfer = engine_transfer_completion(engine, transfer); return transfer; } static void engine_service_perf(struct xdma_engine *engine, u32 desc_completed) { - BUG_ON(!engine); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return; + } /* performance measurement is running? */ if (engine->xdma_perf) { @@ -864,7 +862,10 @@ static void engine_transfer_dequeue(struct xdma_engine *engine) { struct xdma_transfer *transfer; - BUG_ON(!engine); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return; + } /* pick first transfer on the queue (was submitted to the engine) */ transfer = list_entry(engine->transfer_list.next, struct xdma_transfer, @@ -886,9 +887,12 @@ static int engine_ring_process(struct xdma_engine *engine) int start; int eop_count = 0; - BUG_ON(!engine); + if (unlikely(!engine || !engine->cyclic_result)) { + pr_err("engine 0x%p, cyclic_result 0x%p.\n", + engine, engine ? engine->cyclic_result : NULL); + return -EINVAL; + } result = engine->cyclic_result; - BUG_ON(!result); /* where we start receiving in the ring buffer */ start = engine->rx_tail; @@ -929,8 +933,11 @@ static int engine_service_cyclic_polled(struct xdma_engine *engine) struct xdma_poll_wb *writeback_data; u32 sched_limit = 0; - BUG_ON(!engine); - BUG_ON(engine->magic != MAGIC_ENGINE); + if (unlikely(!engine || (engine->magic != MAGIC_ENGINE))) { + pr_err("bad engine 0x%p, magic 0x%lx.\n", + engine, engine ? engine->magic : 0UL); + return -EINVAL; + } writeback_data = (struct xdma_poll_wb *)engine->poll_mode_addr_virt; @@ -948,6 +955,11 @@ static int engine_service_cyclic_polled(struct xdma_engine *engine) } eop_count = engine_ring_process(engine); + if (eop_count < 0) { + pr_err("%s failed to process engine ring\n", + engine->name); + return eop_count; + } } if (eop_count == 0) { @@ -969,8 +981,11 @@ static int engine_service_cyclic_interrupt(struct xdma_engine *engine) int eop_count = 0; struct xdma_transfer *xfer; - BUG_ON(!engine); - BUG_ON(engine->magic != MAGIC_ENGINE); + if (unlikely(!engine || (engine->magic != MAGIC_ENGINE))) { + pr_err("bad engine 0x%p, magic 0x%lx.\n", + engine, engine ? engine->magic : 0UL); + return -EINVAL; + } engine_status_read(engine, 1, 0); @@ -981,14 +996,12 @@ static int engine_service_cyclic_interrupt(struct xdma_engine *engine) */ xfer = &engine->cyclic_req->xfer; if(enable_credit_mp){ - if (eop_count > 0) { - //engine->eop_found = 1; - } wake_up_interruptible(&xfer->wq); }else{ if (eop_count > 0) { /* awake task on transfer's wait queue */ - dbg_tfr("wake_up_interruptible() due to %d EOP's\n", eop_count); + dbg_tfr("wake_up_interruptible() due to %d EOP's\n", + eop_count); engine->eop_found = 1; wake_up_interruptible(&xfer->wq); } @@ -1013,8 +1026,11 @@ static int engine_service_cyclic(struct xdma_engine *engine) dbg_tfr("engine_service_cyclic()"); - BUG_ON(!engine); - BUG_ON(engine->magic != MAGIC_ENGINE); + if (unlikely(!engine || (engine->magic != MAGIC_ENGINE))) { + pr_err("bad engine 0x%p, magic 0x%lx.\n", + engine, engine ? engine->magic : 0UL); + return -EINVAL; + } if (poll_mode) rc = engine_service_cyclic_polled(engine); @@ -1029,7 +1045,10 @@ static void engine_service_resume(struct xdma_engine *engine) { struct xdma_transfer *transfer_started; - BUG_ON(!engine); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return; + } /* engine stopped? */ if (!engine->running) { @@ -1037,8 +1056,14 @@ static void engine_service_resume(struct xdma_engine *engine) if (!list_empty(&engine->transfer_list)) { /* (re)start engine */ transfer_started = engine_start(engine); - pr_info("re-started %s engine with pending xfer 0x%p\n", + if (!transfer_started) { + pr_err("%s failed to start dma engine\n", + engine->name); + return; + } + dbg_tfr("re-started %s engine with pending xfer 0x%p\n", engine->name, transfer_started); + /* engine was requested to be shutdown? */ } else if (engine->shutdown & ENGINE_SHUTDOWN_REQUEST) { engine->shutdown |= ENGINE_SHUTDOWN_IDLE; @@ -1074,7 +1099,10 @@ static int engine_service(struct xdma_engine *engine, int desc_writeback) int rv = 0; struct xdma_poll_wb *wb_data; - BUG_ON(!engine); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return -EINVAL; + } /* If polling detected an error, signal to the caller */ if (err_flag) @@ -1142,7 +1170,7 @@ static int engine_service(struct xdma_engine *engine, int desc_writeback) transfer = engine_service_final_transfer(engine, transfer, &desc_count); /* Before starting engine again, clear the writeback data */ - if (poll_mode) { + if (poll_mode) { wb_data = (struct xdma_poll_wb *)engine->poll_mode_addr_virt; wb_data->completed_desc_count = 0; } @@ -1160,7 +1188,11 @@ static void engine_service_work(struct work_struct *work) unsigned long flags; engine = container_of(work, struct xdma_engine, work); - BUG_ON(engine->magic != MAGIC_ENGINE); + if (unlikely(!engine || (engine->magic != MAGIC_ENGINE))) { + pr_err("bad engine 0x%p, magic 0x%lx.\n", + engine, engine ? engine->magic : 0UL); + return; + } /* lock the engine */ spin_lock_irqsave(&engine->lock, flags); @@ -1185,15 +1217,18 @@ static void engine_service_work(struct work_struct *work) spin_unlock_irqrestore(&engine->lock, flags); } -static u32 engine_service_wb_monitor(struct xdma_engine *engine, - u32 expected_wb) +static int engine_service_wb_monitor(struct xdma_engine *engine, + u32 expected_wb, u32 *wb) { struct xdma_poll_wb *wb_data; u32 desc_wb = 0; u32 sched_limit = 0; unsigned long timeout; - BUG_ON(!engine); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return -EINVAL; + } wb_data = (struct xdma_poll_wb *)engine->poll_mode_addr_virt; /* @@ -1235,7 +1270,8 @@ static u32 engine_service_wb_monitor(struct xdma_engine *engine, sched_limit++; } - return desc_wb; + *wb = desc_wb; + return 0; } static int engine_service_poll(struct xdma_engine *engine, @@ -1246,8 +1282,11 @@ static int engine_service_poll(struct xdma_engine *engine, unsigned long flags; int rv = 0; - BUG_ON(!engine); - BUG_ON(engine->magic != MAGIC_ENGINE); + if (unlikely(!engine || (engine->magic != MAGIC_ENGINE))) { + pr_err("bad engine 0x%p, magic 0x%lx.\n", + engine, engine ? engine->magic : 0UL); + return -EINVAL; + } writeback_data = (struct xdma_poll_wb *)engine->poll_mode_addr_virt; @@ -1263,15 +1302,16 @@ static int engine_service_poll(struct xdma_engine *engine, * determined before the function is called */ - desc_wb = engine_service_wb_monitor(engine, expected_desc_count); + rv = engine_service_wb_monitor(engine, expected_desc_count, &desc_wb); + if (rv < 0) + return rv; spin_lock_irqsave(&engine->lock, flags); dbg_tfr("%s service.\n", engine->name); - if (engine->cyclic_req) { + if (engine->cyclic_req) rv = engine_service_cyclic(engine); - } else { + else rv = engine_service(engine, desc_wb); - } spin_unlock_irqrestore(&engine->lock, flags); return rv; @@ -1281,7 +1321,10 @@ static irqreturn_t user_irq_service(int irq, struct xdma_user_irq *user_irq) { unsigned long flags; - BUG_ON(!user_irq); + if (unlikely(!user_irq)) { + pr_err("user_irq NULL.\n"); + return IRQ_NONE; + } if (user_irq->handler) return user_irq->handler(user_irq->user_idx, user_irq->dev); @@ -1309,16 +1352,14 @@ static irqreturn_t xdma_isr(int irq, void *dev_id) struct xdma_dev *xdev; struct interrupt_regs *irq_regs; - dbg_irq("(irq=%d, dev 0x%p) <<<< ISR.\n", irq, dev_id); - BUG_ON(!dev_id); - xdev = (struct xdma_dev *)dev_id; - - if (!xdev) { - WARN_ON(!xdev); - dbg_irq("xdma_isr(irq=%d) xdev=%p ??\n", irq, xdev); + if (unlikely(!dev_id)) { + pr_err("irq %d, xdev NULL.\n", irq); return IRQ_NONE; } + dbg_irq("(irq=%d, dev 0x%p) <<<< ISR.\n", irq, dev_id); + xdev = (struct xdma_dev *)dev_id; + irq_regs = (struct interrupt_regs *)(xdev->bar[xdev->config_bar_idx] + XDMA_OFS_INT_CTRL); @@ -1360,8 +1401,8 @@ static irqreturn_t xdma_isr(int irq, void *dev_id) struct xdma_engine *engine = &xdev->engine_h2c[channel]; /* engine present and its interrupt fired? */ - if((engine->irq_bitmask & mask) && - (engine->magic == MAGIC_ENGINE)) { + if ((engine->irq_bitmask & mask) && + (engine->magic == MAGIC_ENGINE)) { mask &= ~engine->irq_bitmask; dbg_tfr("schedule_work, %s.\n", engine->name); schedule_work(&engine->work); @@ -1379,8 +1420,8 @@ static irqreturn_t xdma_isr(int irq, void *dev_id) struct xdma_engine *engine = &xdev->engine_c2h[channel]; /* engine present and its interrupt fired? */ - if((engine->irq_bitmask & mask) && - (engine->magic == MAGIC_ENGINE)) { + if ((engine->irq_bitmask & mask) && + (engine->magic == MAGIC_ENGINE)) { mask &= ~engine->irq_bitmask; dbg_tfr("schedule_work, %s.\n", engine->name); schedule_work(&engine->work); @@ -1401,12 +1442,15 @@ static irqreturn_t xdma_user_irq(int irq, void *dev_id) { struct xdma_user_irq *user_irq; - dbg_irq("(irq=%d) <<<< INTERRUPT SERVICE ROUTINE\n", irq); + if (unlikely(!dev_id)) { + pr_err("irq %d, dev_id NULL.\n", irq); + return IRQ_NONE; + } - BUG_ON(!dev_id); + dbg_irq("(irq=%d) <<<< INTERRUPT SERVICE ROUTINE\n", irq); user_irq = (struct xdma_user_irq *)dev_id; - return user_irq_service(irq, user_irq); + return user_irq_service(irq, user_irq); } /* @@ -1420,15 +1464,18 @@ static irqreturn_t xdma_channel_irq(int irq, void *dev_id) struct xdma_engine *engine; struct interrupt_regs *irq_regs; + if (unlikely(!dev_id)) { + pr_err("irq %d, dev_id NULL.\n", irq); + return IRQ_NONE; + } dbg_irq("(irq=%d) <<<< INTERRUPT service ROUTINE\n", irq); - BUG_ON(!dev_id); engine = (struct xdma_engine *)dev_id; xdev = engine->xdev; - if (!xdev) { - WARN_ON(!xdev); - dbg_irq("xdma_channel_irq(irq=%d) xdev=%p ??\n", irq, xdev); + if (unlikely(!xdev)) { + pr_err("xdma_channel_irq(irq=%d) engine 0x%p, xdev NULL.\n", + irq, engine); return IRQ_NONE; } @@ -1446,10 +1493,6 @@ static irqreturn_t xdma_channel_irq(int irq, void *dev_id) /* Schedule the bottom half */ schedule_work(&engine->work); - /* - * RTO - need to protect access here if multiple MSI-X are used for - * user interrupts - */ xdev->irq_count++; return IRQ_HANDLED; } @@ -1541,6 +1584,7 @@ static int is_config_bar(struct xdma_dev *xdev, int idx) return flag; } +#ifndef XDMA_CONFIG_BAR_NUM static void identify_bars(struct xdma_dev *xdev, int *bar_id_list, int num_bars, int config_bar_pos) { @@ -1558,8 +1602,10 @@ static void identify_bars(struct xdma_dev *xdev, int *bar_id_list, int num_bars, * correctly with both 32-bit and 64-bit BARs. */ - BUG_ON(!xdev); - BUG_ON(!bar_id_list); + if (unlikely(!xdev || !bar_id_list)) { + pr_err("xdev 0x%p, bar_id_list 0x%p.\n", xdev, bar_id_list); + return; + } dbg_init("xdev 0x%p, bars %d, config at %d.\n", xdev, num_bars, config_bar_pos); @@ -1604,6 +1650,7 @@ static void identify_bars(struct xdma_dev *xdev, int *bar_id_list, int num_bars, num_bars, config_bar_pos, xdev->user_bar_idx, xdev->bypass_bar_idx); } +#endif /* map_bars() -- map device regions into kernel virtual address space * @@ -1613,6 +1660,24 @@ static void identify_bars(struct xdma_dev *xdev, int *bar_id_list, int num_bars, static int map_bars(struct xdma_dev *xdev, struct pci_dev *dev) { int rv; + +#ifdef XDMA_CONFIG_BAR_NUM + rv = map_single_bar(xdev, dev, XDMA_CONFIG_BAR_NUM); + if (rv <= 0) { + pr_info("%s, map config bar %d failed, %d.\n", + dev_name(&dev->dev), XDMA_CONFIG_BAR_NUM, rv); + return -EINVAL; + } + + if (is_config_bar(xdev, XDMA_CONFIG_BAR_NUM) == 0) { + pr_info("%s, unable to identify config bar %d.\n", + dev_name(&dev->dev), XDMA_CONFIG_BAR_NUM); + return -EINVAL; + } + xdev->config_bar_idx = XDMA_CONFIG_BAR_NUM; + + return 0; +#else int i; int bar_id_list[XDMA_BAR_NUM]; int bar_id_idx = 0; @@ -1661,20 +1726,21 @@ static int map_bars(struct xdma_dev *xdev, struct pci_dev *dev) /* unwind; unmap any BARs that we did map */ unmap_bars(xdev, dev); return rv; +#endif } /* - * MSI-X interrupt: + * MSI-X interrupt: * vectors, followed by vectors */ /* - * RTO - code to detect if MSI/MSI-X capability exists is derived + * code to detect if MSI/MSI-X capability exists is derived * from linux/pci/msi.c - pci_msi_check_device */ #ifndef arch_msi_check_device -int arch_msi_check_device(struct pci_dev *dev, int nvec, int type) +static int arch_msi_check_device(struct pci_dev *dev, int nvec, int type) { return 0; } @@ -1718,8 +1784,10 @@ static int enable_msi_msix(struct xdma_dev *xdev, struct pci_dev *pdev) { int rv = 0; - BUG_ON(!xdev); - BUG_ON(!pdev); + if (unlikely(!xdev || !pdev)) { + pr_err("xdev 0x%p, pdev 0x%p.\n", xdev, pdev); + return -EINVAL; + } if (!interrupt_mode && msi_msix_capable(pdev, PCI_CAP_ID_MSIX)) { int req_nvec = xdev->c2h_channel_max + xdev->h2c_channel_max + @@ -1859,7 +1927,7 @@ static void irq_msix_channel_teardown(struct xdma_dev *xdev) prog_irq_msix_channel(xdev, 1); - engine = xdev->engine_h2c; + engine = xdev->engine_h2c; for (i = 0; i < xdev->h2c_channel_max; i++, j++, engine++) { if (!engine->msix_irq_line) break; @@ -1868,7 +1936,7 @@ static void irq_msix_channel_teardown(struct xdma_dev *xdev) free_irq(engine->msix_irq_line, engine); } - engine = xdev->engine_c2h; + engine = xdev->engine_c2h; for (i = 0; i < xdev->c2h_channel_max; i++, j++, engine++) { if (!engine->msix_irq_line) break; @@ -1881,15 +1949,19 @@ static void irq_msix_channel_teardown(struct xdma_dev *xdev) static int irq_msix_channel_setup(struct xdma_dev *xdev) { int i; - int j = xdev->h2c_channel_max; + int j; int rv = 0; u32 vector; struct xdma_engine *engine; - BUG_ON(!xdev); + if (unlikely(!xdev)) { + pr_err("xdev NULL.\n"); + return -EINVAL; + } if (!xdev->msix_enabled) return 0; + j = xdev->h2c_channel_max; engine = xdev->engine_h2c; for (i = 0; i < xdev->h2c_channel_max; i++, engine++) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) @@ -1932,15 +2004,19 @@ static int irq_msix_channel_setup(struct xdma_dev *xdev) static void irq_msix_user_teardown(struct xdma_dev *xdev) { int i; - int j = xdev->h2c_channel_max + xdev->c2h_channel_max; + int j; - BUG_ON(!xdev); + if (unlikely(!xdev)) { + pr_err("xdev NULL.\n"); + return; + } if (!xdev->msix_enabled) return; prog_irq_msix_user(xdev, 1); + j = xdev->h2c_channel_max + xdev->c2h_channel_max; for (i = 0; i < xdev->user_max; i++, j++) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) u32 vector = pci_irq_vector(xdev->pdev, j); @@ -1956,7 +2032,7 @@ static int irq_msix_user_setup(struct xdma_dev *xdev) { int i; int j = xdev->h2c_channel_max + xdev->c2h_channel_max; - int rv = 0; + int rv = 0; /* vectors set in probe_scan_for_msi() */ for (i = 0; i < xdev->user_max; i++, j++) { @@ -1974,7 +2050,7 @@ static int irq_msix_user_setup(struct xdma_dev *xdev) } pr_info("%d-USR-%d, IRQ#%d with 0x%p\n", xdev->idx, i, vector, &xdev->user_irq[i]); - } + } /* If any errors occur, free IRQs that were successfully requested */ if (rv) { @@ -2016,17 +2092,17 @@ static int irq_legacy_setup(struct xdma_dev *xdev, struct pci_dev *pdev) dbg_init("Legacy Interrupt register value = %d\n", val); if (val > 1) { val--; - w = (val<<24) | (val<<16) | (val<<8)| val; + w = (val << 24) | (val << 16) | (val << 8)| val; /* Program IRQ Block Channel vactor and IRQ Block User vector * with Legacy interrupt value */ - reg = xdev->bar[xdev->config_bar_idx] + 0x2080; // IRQ user + reg = xdev->bar[xdev->config_bar_idx] + 0x2080; // IRQ user write_register(w, reg, 0x2080); - write_register(w, reg+0x4, 0x2084); - write_register(w, reg+0x8, 0x2088); - write_register(w, reg+0xC, 0x208C); - reg = xdev->bar[xdev->config_bar_idx] + 0x20A0; // IRQ Block + write_register(w, reg + 0x4, 0x2084); + write_register(w, reg + 0x8, 0x2088); + write_register(w, reg + 0xC, 0x208C); + reg = xdev->bar[xdev->config_bar_idx] + 0x20A0; // IRQ Block write_register(w, reg, 0x20A0); - write_register(w, reg+0x4, 0x20A4); + write_register(w, reg + 0x4, 0x20A4); } xdev->irq_line = (int)pdev->irq; @@ -2077,10 +2153,14 @@ static void dump_desc(struct xdma_desc *desc_virt) { int j; u32 *p = (u32 *)desc_virt; - static char * const field_name[] = { - "magic|extra_adjacent|control", "bytes", "src_addr_lo", - "src_addr_hi", "dst_addr_lo", "dst_addr_hi", "next_addr", - "next_addr_pad"}; + static char * const field_name[] = { "magic|extra_adjacent|control", + "bytes", + "src_addr_lo", + "src_addr_hi", + "dst_addr_lo", + "dst_addr_hi", + "next_addr", + "next_addr_pad"}; char *dummy; /* remove warning about unused variable when debug printing is off */ @@ -2112,21 +2192,19 @@ static void transfer_dump(struct xdma_transfer *transfer) } #endif /* __LIBXDMA_DEBUG__ */ -/* xdma_desc_alloc() - Allocate cache-coherent array of N descriptors. - * - * Allocates an array of 'number' descriptors in contiguous PCI bus addressable - * memory. Chains the descriptors as a singly-linked list; the descriptor's - * next * pointer specifies the bus address of the next descriptor. +/* transfer_desc_init() - Chains the descriptors as a singly-linked list * + * Each descriptor's next * pointer specifies the bus address + * of the next descriptor. + * Terminates the last descriptor to form a singly-linked list * - * @dev Pointer to pci_dev - * @number Number of descriptors to be allocated - * @desc_bus_p Pointer where to store the first descriptor bus address - * - * @return Virtual address of the first descriptor + * @transfer Pointer to SG DMA transfers + * @count Number of descriptors allocated in continuous PCI bus addressable + * memory * + * @return 0 on success, EINVAL on failure */ -static void transfer_desc_init(struct xdma_transfer *transfer, int count) +static int transfer_desc_init(struct xdma_transfer *transfer, int count) { struct xdma_desc *desc_virt = transfer->desc_virt; dma_addr_t desc_bus = transfer->desc_bus; @@ -2135,7 +2213,10 @@ static void transfer_desc_init(struct xdma_transfer *transfer, int count) int extra_adj; u32 temp_control; - BUG_ON(count > XDMA_TRANSFER_MAX_DESC); + if (unlikely(count > XDMA_TRANSFER_MAX_DESC)) { + pr_err("xfer 0x%p, too many desc 0x%x.\n", transfer, count); + return -EINVAL; + } /* create singly-linked list for SG DMA controller */ for (i = 0; i < count - 1; i++) { @@ -2171,6 +2252,8 @@ static void transfer_desc_init(struct xdma_transfer *transfer, int count) temp_control = DESC_MAGIC; desc_virt[i].control = cpu_to_le32(temp_control); + + return 0; } /* xdma_desc_link() - Link two descriptors @@ -2188,8 +2271,7 @@ static void xdma_desc_link(struct xdma_desc *first, struct xdma_desc *second, * remember reserved control in first descriptor, but zero * extra_adjacent! */ - /* RTO - what's this about? Shouldn't it be 0x0000c0ffUL? */ - u32 control = le32_to_cpu(first->control) & 0x0000f0ffUL; + u32 control = le32_to_cpu(first->control) & 0x00FFC0FFUL; /* second descriptor given? */ if (second) { /* @@ -2215,42 +2297,35 @@ static void xdma_desc_link(struct xdma_desc *first, struct xdma_desc *second, /* xdma_desc_adjacent -- Set how many descriptors are adjacent to this one */ static void xdma_desc_adjacent(struct xdma_desc *desc, int next_adjacent) { - int extra_adj = 0; /* remember reserved and control bits */ - u32 control = le32_to_cpu(desc->control) & 0x0000f0ffUL; - u32 max_adj_4k = 0; + u32 control = le32_to_cpu(desc->control) & 0xFFFFC0FFUL; + + if (next_adjacent) + next_adjacent = next_adjacent - 1; + if (next_adjacent > MAX_EXTRA_ADJ) + next_adjacent = MAX_EXTRA_ADJ; + control |= (next_adjacent << 8); - if (next_adjacent > 0) { - extra_adj = next_adjacent - 1; - if (extra_adj > MAX_EXTRA_ADJ){ - extra_adj = MAX_EXTRA_ADJ; - } - max_adj_4k = (0x1000 - ((le32_to_cpu(desc->next_lo))&0xFFF))/32 - 1; - if (extra_adj>max_adj_4k) { - extra_adj = max_adj_4k; - } - if(extra_adj<0){ - printk("Warning: extra_adj<0, converting it to 0\n"); - extra_adj = 0; - } - } - /* merge adjacent and control field */ - control |= 0xAD4B0000UL | (extra_adj << 8); /* write control and next_adjacent */ desc->control = cpu_to_le32(control); } /* xdma_desc_control -- Set complete control field of a descriptor. */ -static void xdma_desc_control_set(struct xdma_desc *first, u32 control_field) +static int xdma_desc_control_set(struct xdma_desc *first, u32 control_field) { /* remember magic and adjacent number */ u32 control = le32_to_cpu(first->control) & ~(LS_BYTE_MASK); - BUG_ON(control_field & ~(LS_BYTE_MASK)); + if (unlikely(control_field & ~(LS_BYTE_MASK))) { + pr_err("control_field bad 0x%x.\n", control_field); + return -EINVAL; + } /* merge adjacent and control field */ control |= control_field; /* write control and next_adjacent */ first->control = cpu_to_le32(control); + + return 0; } /* xdma_desc_clear -- Clear bits in control field of a descriptor. */ @@ -2259,26 +2334,12 @@ static void xdma_desc_control_clear(struct xdma_desc *first, u32 clear_mask) /* remember magic and adjacent number */ u32 control = le32_to_cpu(first->control); - BUG_ON(clear_mask & ~(LS_BYTE_MASK)); - /* merge adjacent and control field */ control &= (~clear_mask); /* write control and next_adjacent */ first->control = cpu_to_le32(control); } -/* xdma_desc_done - recycle cache-coherent linked list of descriptors. - * - * @dev Pointer to pci_dev - * @number Number of descriptors to be allocated - * @desc_virt Pointer to (i.e. virtual address of) first descriptor in list - * @desc_bus Bus address of first descriptor in list - */ -static inline void xdma_desc_done(struct xdma_desc *desc_virt) -{ - memset(desc_virt, 0, XDMA_TRANSFER_MAX_DESC * sizeof(struct xdma_desc)); -} - /* xdma_desc() - Fill a descriptor with the transfer details * * @desc pointer to descriptor to be filled @@ -2320,9 +2381,15 @@ static void transfer_abort(struct xdma_engine *engine, { struct xdma_transfer *head; - BUG_ON(!engine); - BUG_ON(!transfer); - BUG_ON(transfer->desc_num == 0); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return; + } + if (unlikely(!transfer || (transfer->desc_num == 0))) { + pr_err("engine %s, xfer 0x%p, desc 0.\n", + engine->name, transfer); + return; + } pr_info("abort transfer 0x%p, desc %d, engine desc queued %d.\n", transfer, transfer->desc_num, engine->desc_dequeued); @@ -2354,10 +2421,16 @@ static int transfer_queue(struct xdma_engine *engine, struct xdma_dev *xdev; unsigned long flags; - BUG_ON(!engine); - BUG_ON(!engine->xdev); - BUG_ON(!transfer); - BUG_ON(transfer->desc_num == 0); + if (unlikely(!engine || !engine->xdev)) { + pr_err("bad engine 0x%p, xdev 0x%p.\n", + engine, engine ? engine->xdev : NULL); + return -EINVAL; + } + if (unlikely(!transfer || (transfer->desc_num == 0))) { + pr_err("engine %s, xfer 0x%p, desc 0.\n", + engine->name, transfer); + return -EINVAL; + } dbg_tfr("transfer_queue(transfer=0x%p).\n", transfer); xdev = engine->xdev; @@ -2473,8 +2546,10 @@ static void engine_free_resource(struct xdma_engine *engine) static void engine_destroy(struct xdma_dev *xdev, struct xdma_engine *engine) { - BUG_ON(!xdev); - BUG_ON(!engine); + if (unlikely(!xdev || !engine)) { + pr_err("xdev 0x%p, engine 0x%p.\n", xdev, engine); + return; + } dbg_sg("Shutting down engine %s%d", engine->name, engine->channel); @@ -2514,26 +2589,26 @@ struct xdma_transfer *engine_cyclic_stop(struct xdma_engine *engine) /* pick first transfer on the queue (was submitted to engine) */ transfer = list_entry(engine->transfer_list.next, struct xdma_transfer, entry); - BUG_ON(!transfer); xdma_engine_stop(engine); + engine->running = 0; - if (transfer->cyclic) { + if (transfer && transfer->cyclic) { if (engine->xdma_perf) dbg_perf("Stopping perf transfer on %s\n", engine->name); else dbg_perf("Stopping cyclic transfer on %s\n", engine->name); - /* make sure the handler sees correct transfer state */ - transfer->cyclic = 1; - /* - * set STOP flag and interrupt on completion, on the - * last descriptor - */ - xdma_desc_control_set( - transfer->desc_virt + transfer->desc_num - 1, - XDMA_DESC_COMPLETED | XDMA_DESC_STOPPED); + + /* free up the buffer allocated for perf run */ + if (engine->perf_buf_virt) + dma_free_coherent(&engine->xdev->pdev->dev, + engine->xdma_perf->transfer_size, + engine->perf_buf_virt, + engine->perf_buf_bus); + engine->perf_buf_virt = NULL; + list_del(&transfer->entry); } else { dbg_sg("(engine=%p) running transfer is not cyclic\n", engine); @@ -2543,7 +2618,6 @@ struct xdma_transfer *engine_cyclic_stop(struct xdma_engine *engine) } return transfer; } -EXPORT_SYMBOL_GPL(engine_cyclic_stop); static int engine_writeback_setup(struct xdma_engine *engine) { @@ -2551,9 +2625,11 @@ static int engine_writeback_setup(struct xdma_engine *engine) struct xdma_dev *xdev; struct xdma_poll_wb *writeback; - BUG_ON(!engine); + if (unlikely(!engine || !engine->xdev)) { + pr_err("engine 0x%p, xdev NULL.\n", engine); + return -EINVAL; + } xdev = engine->xdev; - BUG_ON(!xdev); /* * RTO - doing the allocation per engine is wasteful since a full page @@ -2755,7 +2831,7 @@ static int engine_init(struct xdma_engine *engine, struct xdma_dev *xdev, static void transfer_destroy(struct xdma_dev *xdev, struct xdma_transfer *xfer) { /* free descriptors */ - xdma_desc_done(xfer->desc_virt); + memset(xfer->desc_virt, 0, xfer->desc_num * sizeof(struct xdma_desc)); if (xfer->last_in_request && (xfer->flags & XFER_FLAG_NEED_UNMAP)) { struct sg_table *sgt = xfer->sgt; @@ -2803,6 +2879,7 @@ static int transfer_init(struct xdma_engine *engine, struct xdma_request_cb *req int i = 0; int last = 0; u32 control; + int rv; memset(xfer, 0, sizeof(*xfer)); @@ -2815,7 +2892,9 @@ static int transfer_init(struct xdma_engine *engine, struct xdma_request_cb *req xfer->desc_virt = engine->desc; xfer->desc_bus = engine->desc_bus; - transfer_desc_init(xfer, desc_max); + rv = transfer_desc_init(xfer, desc_max); + if (rv < 0) + return rv; dbg_sg("transfer->desc_bus = 0x%llx.\n", (u64)xfer->desc_bus); @@ -2828,7 +2907,9 @@ static int transfer_init(struct xdma_engine *engine, struct xdma_request_cb *req control = XDMA_DESC_STOPPED; control |= XDMA_DESC_EOP; control |= XDMA_DESC_COMPLETED; - xdma_desc_control_set(xfer->desc_virt + last, control); + rv = xdma_desc_control_set(xfer->desc_virt + last, control); + if (rv < 0) + return rv; xfer->desc_num = xfer->desc_adjacent = desc_max; @@ -2940,9 +3021,19 @@ static struct xdma_request_cb * xdma_init_request(struct sg_table *sgt, tlen = 0; } j++; + if (j > max) + break; } } - BUG_ON(j > max); + + if (unlikely(j > max)) { + pr_err("too many sdesc %d > %d\n", j, max); +#ifdef __LIBXDMA_DEBUG__ + xdma_request_cb_dump(req); +#endif + xdma_request_free(req); + return NULL; + } req->sw_desc_cnt = j; #ifdef __LIBXDMA_DEBUG__ @@ -2988,8 +3079,11 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr, return -EINVAL; } - BUG_ON(!engine); - BUG_ON(engine->magic != MAGIC_ENGINE); + if (unlikely(!engine || (engine->magic != MAGIC_ENGINE))) { + pr_err("bad engine 0x%p, magic 0x%lx.\n", + engine, engine ? engine->magic : 0UL); + return -EINVAL; + } xdev = engine->xdev; if (xdma_device_flag_check(xdev, XDEV_FLAG_OFFLINE)) { @@ -3012,7 +3106,10 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr, } sgt->nents = nents; } else { - BUG_ON(!sgt->nents); + if (unlikely(!sgt->nents)) { + pr_err("%s, sgt NOT dma_mapped.\n", engine->name); + return -EINVAL; + } } req = xdma_init_request(sgt, ep_addr); @@ -3026,17 +3123,16 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr, sg = sgt->sgl; nents = req->sw_desc_cnt; + mutex_lock(&engine->desc_lock); + while (nents) { unsigned long flags; struct xdma_transfer *xfer; - /* one transfer at a time */ - spin_lock(&engine->desc_lock); - /* build transfer */ rv = transfer_init(engine, req); if (rv < 0) { - spin_unlock(&engine->desc_lock); + mutex_unlock(&engine->desc_lock); goto unmap_sgl; } xfer = &req->xfer; @@ -3061,7 +3157,7 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr, rv = transfer_queue(engine, xfer); if (rv < 0) { - spin_unlock(&engine->desc_lock); + mutex_unlock(&engine->desc_lock); pr_info("unable to submit %s, %d.\n", engine->name, rv); goto unmap_sgl; } @@ -3128,11 +3224,11 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr, } transfer_destroy(xdev, xfer); - spin_unlock(&engine->desc_lock); if (rv < 0) - goto unmap_sgl; + break; } /* while (sg) */ + mutex_unlock(&engine->desc_lock); unmap_sgl: if (!dma_mapped && sgt->nents) { @@ -3148,33 +3244,43 @@ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr, return done; } -EXPORT_SYMBOL_GPL(xdma_xfer_submit); int xdma_performance_submit(struct xdma_dev *xdev, struct xdma_engine *engine) { - u8 *buffer_virt; u32 max_consistent_size = 128 * 32 * 1024; /* 1024 pages, 4MB */ - dma_addr_t buffer_bus; /* bus address */ struct xdma_transfer *transfer; u64 ep_addr = 0; int num_desc_in_a_loop = 128; int size_in_desc = engine->xdma_perf->transfer_size; int size = size_in_desc * num_desc_in_a_loop; + int free_desc = 0; int i; + int rv = -ENOMEM; - BUG_ON(size_in_desc > max_consistent_size); + if (unlikely(size_in_desc > max_consistent_size)) { + pr_err("%s, size too big %d > %u.\n", + engine->name, size_in_desc, max_consistent_size); + return -EINVAL; + } if (size > max_consistent_size) { size = max_consistent_size; num_desc_in_a_loop = size / size_in_desc; } - buffer_virt = dma_alloc_coherent(&xdev->pdev->dev, size, - &buffer_bus, GFP_KERNEL); + engine->perf_buf_virt = dma_alloc_coherent(&xdev->pdev->dev, size, + &engine->perf_buf_bus, GFP_KERNEL); + if (unlikely(!engine->perf_buf_virt)) { + pr_err("engine %s perf buf OOM.\n", engine->name); + return -ENOMEM; + } /* allocate transfer data structure */ transfer = kzalloc(sizeof(struct xdma_transfer), GFP_KERNEL); - BUG_ON(!transfer); + if (unlikely(!transfer)) { + pr_err("engine %s transfer OOM.\n", engine->name); + goto free_buffer; + } /* 0 = write engine (to_dev=0) , 1 = read engine (to_dev=1) */ transfer->dir = engine->dir; @@ -3186,21 +3292,28 @@ int xdma_performance_submit(struct xdma_dev *xdev, struct xdma_engine *engine) engine->desc = dma_alloc_coherent(&xdev->pdev->dev, num_desc_in_a_loop * sizeof(struct xdma_desc), &engine->desc_bus, GFP_KERNEL); - BUG_ON(!engine->desc); + if (unlikely(!engine->desc)) { + pr_err("%s desc OOM.\n", engine->name); + goto free_xfer; + } dbg_init("device %s, engine %s pre-alloc desc 0x%p,0x%llx.\n", dev_name(&xdev->pdev->dev), engine->name, engine->desc, engine->desc_bus); + free_desc = 1; } transfer->desc_virt = engine->desc; transfer->desc_bus = engine->desc_bus; - transfer_desc_init(transfer, transfer->desc_num); + rv = transfer_desc_init(transfer, transfer->desc_num); + if (rv < 0) + goto free_desc; dbg_sg("transfer->desc_bus = 0x%llx.\n", (u64)transfer->desc_bus); for (i = 0; i < transfer->desc_num; i++) { struct xdma_desc *desc = transfer->desc_virt + i; - dma_addr_t rc_bus_addr = buffer_bus + size_in_desc * i; + dma_addr_t rc_bus_addr = engine->perf_buf_bus + + size_in_desc * i; /* fill in descriptor entry with transfer details */ xdma_desc_set(desc, rc_bus_addr, ep_addr, size_in_desc, @@ -3208,7 +3321,12 @@ int xdma_performance_submit(struct xdma_dev *xdev, struct xdma_engine *engine) } /* stop engine and request interrupt on last descriptor */ - xdma_desc_control_set(transfer->desc_virt, 0); + rv = xdma_desc_control_set(transfer->desc_virt, 0); + if (rv < 0) { + pr_err("%s: Failed to set desc control\n", engine->name); + goto free_desc; + } + /* create a linked loop */ xdma_desc_link(transfer->desc_virt + transfer->desc_num - 1, transfer->desc_virt, transfer->desc_bus); @@ -3218,16 +3336,34 @@ int xdma_performance_submit(struct xdma_dev *xdev, struct xdma_engine *engine) /* initialize wait queue */ init_waitqueue_head(&transfer->wq); - //printk("=== Descriptor print for PERF \n"); - //transfer_dump(transfer); - dbg_perf("Queueing XDMA I/O %s request for performance measurement.\n", engine->dir ? "write (to dev)" : "read (from dev)"); - transfer_queue(engine, transfer); + rv = transfer_queue(engine, transfer); + if (rv < 0) + goto free_desc; + return 0; +free_desc: + if (free_desc && engine->desc) + dma_free_coherent(&xdev->pdev->dev, + num_desc_in_a_loop * sizeof(struct xdma_desc), + engine->desc, engine->desc_bus); + engine->desc = NULL; + +free_xfer: + if (transfer) { + list_del(&transfer->entry); + kfree(transfer); + } + +free_buffer: + if (engine->perf_buf_virt) + dma_free_coherent(&xdev->pdev->dev, size_in_desc, + engine->perf_buf_virt, engine->perf_buf_bus); + engine->perf_buf_virt = NULL; + return rv; } -EXPORT_SYMBOL_GPL(xdma_performance_submit); static struct xdma_dev *alloc_dev_instance(struct pci_dev *pdev) { @@ -3235,12 +3371,15 @@ static struct xdma_dev *alloc_dev_instance(struct pci_dev *pdev) struct xdma_dev *xdev; struct xdma_engine *engine; - BUG_ON(!pdev); + if (unlikely(!pdev)) { + pr_err("pdev NULL.\n"); + return NULL; + } /* allocate zeroed device book keeping structure */ xdev = kzalloc(sizeof(struct xdma_dev), GFP_KERNEL); if (!xdev) { - pr_info("OOM, xdma_dev.\n"); + pr_info("xdev OOM.\n"); return NULL; } spin_lock_init(&xdev->lock); @@ -3267,7 +3406,7 @@ static struct xdma_dev *alloc_dev_instance(struct pci_dev *pdev) engine = xdev->engine_h2c; for (i = 0; i < XDMA_CHANNEL_NUM_MAX; i++, engine++) { spin_lock_init(&engine->lock); - spin_lock_init(&engine->desc_lock); + mutex_init(&engine->desc_lock); INIT_LIST_HEAD(&engine->transfer_list); init_waitqueue_head(&engine->shutdown_wq); init_waitqueue_head(&engine->xdma_perf_wq); @@ -3276,7 +3415,7 @@ static struct xdma_dev *alloc_dev_instance(struct pci_dev *pdev) engine = xdev->engine_c2h; for (i = 0; i < XDMA_CHANNEL_NUM_MAX; i++, engine++) { spin_lock_init(&engine->lock); - spin_lock_init(&engine->desc_lock); + mutex_init(&engine->desc_lock); INIT_LIST_HEAD(&engine->transfer_list); init_waitqueue_head(&engine->shutdown_wq); init_waitqueue_head(&engine->xdma_perf_wq); @@ -3289,8 +3428,10 @@ static int request_regions(struct xdma_dev *xdev, struct pci_dev *pdev) { int rv; - BUG_ON(!xdev); - BUG_ON(!pdev); + if (unlikely(!xdev || !pdev)) { + pr_err("xdev 0x%p, pdev 0x%p.\n", xdev, pdev); + return -EINVAL; + } dbg_init("pci_request_regions()\n"); rv = pci_request_regions(pdev, xdev->mod_name); @@ -3308,7 +3449,10 @@ static int request_regions(struct xdma_dev *xdev, struct pci_dev *pdev) static int set_dma_mask(struct pci_dev *pdev) { - BUG_ON(!pdev); + if (unlikely(!pdev)) { + pr_err("pdev NULL.\n"); + return -EINVAL; + } dbg_init("sizeof(dma_addr_t) == %ld\n", sizeof(dma_addr_t)); /* 64-bit addressing capability for XDMA? */ @@ -3338,7 +3482,10 @@ static u32 get_engine_channel_id(struct engine_regs *regs) { u32 value; - BUG_ON(!regs); + if (unlikely(!regs)) { + pr_err("regs NULL.\n"); + return 0xFFFFFFFF; + } value = read_register(®s->identifier); @@ -3349,7 +3496,10 @@ static u32 get_engine_id(struct engine_regs *regs) { u32 value; - BUG_ON(!regs); + if (unlikely(!regs)) { + pr_err("regs NULL.\n"); + return 0xFFFFFFFF; + } value = read_register(®s->identifier); return (value & 0xffff0000U) >> 16; @@ -3360,7 +3510,10 @@ static void remove_engines(struct xdma_dev *xdev) struct xdma_engine *engine; int i; - BUG_ON(!xdev); + if (unlikely(!xdev)) { + pr_err("xdev NULL.\n"); + return; + } /* iterate over channels */ for (i = 0; i < xdev->h2c_channel_max; i++) { @@ -3439,7 +3592,10 @@ static int probe_engines(struct xdma_dev *xdev) int i; int rv = 0; - BUG_ON(!xdev); + if (unlikely(!xdev)) { + pr_err("xdev NULL.\n"); + return -EINVAL; + } /* iterate over channels */ for (i = 0; i < xdev->h2c_channel_max; i++) { @@ -3460,12 +3616,12 @@ static int probe_engines(struct xdma_dev *xdev) } #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) -static void pci_enable_relaxed_ordering(struct pci_dev *pdev) +static void pci_enable_capability(struct pci_dev *pdev, int cap) { - pcie_capability_set_word(pdev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_RELAX_EN); + pcie_capability_set_word(pdev, PCI_EXP_DEVCTL, cap); } #else -static void pci_enable_relaxed_ordering(struct pci_dev *pdev) +static void pci_enable_capability(struct pci_dev *pdev, int cap) { u16 v; int pos; @@ -3473,50 +3629,12 @@ static void pci_enable_relaxed_ordering(struct pci_dev *pdev) pos = pci_pcie_cap(pdev); if (pos > 0) { pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &v); - v |= PCI_EXP_DEVCTL_RELAX_EN; + v |= cap; pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, v); } } #endif -static void pci_check_extended_tag(struct xdma_dev *xdev, struct pci_dev *pdev) -{ - u16 cap; - u32 v; - void *__iomem reg; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) - pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &cap); -#else - int pos; - - pos = pci_pcie_cap(pdev); - if (pos > 0) - pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &cap); - else { - pr_info("pdev 0x%p, unable to access pcie cap.\n", pdev); - return; - } -#endif - - if ((cap & PCI_EXP_DEVCTL_EXT_TAG)) - return; - - /* extended tag not enabled */ - pr_info("0x%p EXT_TAG disabled.\n", pdev); - - if (xdev->config_bar_idx < 0) { - pr_info("pdev 0x%p, xdev 0x%p, config bar UNKNOWN.\n", - pdev, xdev); - return; - } - - reg = xdev->bar[xdev->config_bar_idx] + XDMA_OFS_CONFIG + 0x4C; - v = read_register(reg); - v = (v & 0xFF) | (((u32)32) << 8); - write_register(v, reg, XDMA_OFS_CONFIG + 0x4C); -} - void *xdma_device_open(const char *mname, struct pci_dev *pdev, int *user_max, int *h2c_channel_max, int *c2h_channel_max) { @@ -3556,9 +3674,10 @@ void *xdma_device_open(const char *mname, struct pci_dev *pdev, int *user_max, pci_check_intr_pend(pdev); /* enable relaxed ordering */ - pci_enable_relaxed_ordering(pdev); + pci_enable_capability(pdev, PCI_EXP_DEVCTL_RELAX_EN); - pci_check_extended_tag(xdev, pdev); + /* enable extended tag */ + pci_enable_capability(pdev, PCI_EXP_DEVCTL_EXT_TAG); /* force MRRS to be 512 */ rv = pcie_set_readrq(pdev, 512); @@ -3631,7 +3750,6 @@ void *xdma_device_open(const char *mname, struct pci_dev *pdev, int *user_max, kfree(xdev); return NULL; } -EXPORT_SYMBOL_GPL(xdma_device_open); void xdma_device_close(struct pci_dev *pdev, void *dev_hndl) { @@ -3676,7 +3794,6 @@ void xdma_device_close(struct pci_dev *pdev, void *dev_hndl) kfree(xdev); } -EXPORT_SYMBOL_GPL(xdma_device_close); void xdma_device_offline(struct pci_dev *pdev, void *dev_hndl) { @@ -3690,11 +3807,11 @@ void xdma_device_offline(struct pci_dev *pdev, void *dev_hndl) if (debug_check_dev_hndl(__func__, pdev, dev_hndl) < 0) return; -pr_info("pdev 0x%p, xdev 0x%p.\n", pdev, xdev); + pr_info("pdev 0x%p, xdev 0x%p.\n", pdev, xdev); xdma_device_flag_set(xdev, XDEV_FLAG_OFFLINE); /* wait for all engines to be idle */ - for (i = 0; i < xdev->h2c_channel_max; i++) { + for (i = 0; i < xdev->h2c_channel_max; i++) { unsigned long flags; engine = &xdev->engine_h2c[i]; @@ -3709,7 +3826,7 @@ pr_info("pdev 0x%p, xdev 0x%p.\n", pdev, xdev); } } - for (i = 0; i < xdev->c2h_channel_max; i++) { + for (i = 0; i < xdev->c2h_channel_max; i++) { unsigned long flags; engine = &xdev->engine_c2h[i]; @@ -3731,7 +3848,6 @@ pr_info("pdev 0x%p, xdev 0x%p.\n", pdev, xdev); pr_info("xdev 0x%p, done.\n", xdev); } -EXPORT_SYMBOL_GPL(xdma_device_offline); void xdma_device_online(struct pci_dev *pdev, void *dev_hndl) { @@ -3778,9 +3894,8 @@ pr_info("pdev 0x%p, xdev 0x%p.\n", pdev, xdev); } xdma_device_flag_clear(xdev, XDEV_FLAG_OFFLINE); -pr_info("xdev 0x%p, done.\n", xdev); + pr_info("xdev 0x%p, done.\n", xdev); } -EXPORT_SYMBOL_GPL(xdma_device_online); int xdma_device_restart(struct pci_dev *pdev, void *dev_hndl) { @@ -3795,7 +3910,6 @@ int xdma_device_restart(struct pci_dev *pdev, void *dev_hndl) pr_info("NOT implemented, 0x%p.\n", xdev); return -EINVAL; } -EXPORT_SYMBOL_GPL(xdma_device_restart); int xdma_user_isr_register(void *dev_hndl, unsigned int mask, irq_handler_t handler, void *dev) @@ -3822,7 +3936,6 @@ int xdma_user_isr_register(void *dev_hndl, unsigned int mask, return 0; } -EXPORT_SYMBOL_GPL(xdma_user_isr_register); int xdma_user_isr_enable(void *dev_hndl, unsigned int mask) { @@ -3841,7 +3954,6 @@ int xdma_user_isr_enable(void *dev_hndl, unsigned int mask) return 0; } -EXPORT_SYMBOL_GPL(xdma_user_isr_enable); int xdma_user_isr_disable(void *dev_hndl, unsigned int mask) { @@ -3859,23 +3971,7 @@ int xdma_user_isr_disable(void *dev_hndl, unsigned int mask) return 0; } -EXPORT_SYMBOL_GPL(xdma_user_isr_disable); - -#ifdef __LIBXDMA_MOD__ -static int __init xdma_base_init(void) -{ - printk(KERN_INFO "%s", version); - return 0; -} -static void __exit xdma_base_exit(void) -{ - return; -} - -module_init(xdma_base_init); -module_exit(xdma_base_exit); -#endif /* makes an existing transfer cyclic */ static void xdma_transfer_cyclic(struct xdma_transfer *transfer) { @@ -3892,11 +3988,13 @@ static int transfer_monitor_cyclic(struct xdma_engine *engine, struct xdma_result *result; int rc = 0; - BUG_ON(!engine); - BUG_ON(!transfer); + if (unlikely(!engine || !engine->cyclic_result || !transfer)) { + pr_err("engine 0x%p, cyclic_result 0x%p, xfer 0x%p.\n", + engine, engine->cyclic_result, transfer); + return -EINVAL; + } result = engine->cyclic_result; - BUG_ON(!result); if (poll_mode) { int i ; @@ -3956,8 +4054,10 @@ static int copy_cyclic_to_user(struct xdma_engine *engine, int pkt_length, struct scatterlist *sg; int more = pkt_length; - BUG_ON(!engine); - BUG_ON(!buf); + if (unlikely(!buf || !engine)) { + pr_err("engine 0x%p, buf 0x%p.\n", engine, buf); + return -EINVAL; + } dbg_tfr("%s, pkt_len %d, head %d, user buf idx %u.\n", engine->name, pkt_length, head, engine->user_buffer_index); @@ -4021,9 +4121,11 @@ static int complete_cyclic(struct xdma_engine *engine, char __user *buf, int num_credit = 0; unsigned long flags; - BUG_ON(!engine); + if (unlikely(!engine || !engine->cyclic_result)) { + pr_err("engine 0x%p, cyclic_result NULL.\n", engine); + return -EINVAL; + } result = engine->cyclic_result; - BUG_ON(!result); spin_lock_irqsave(&engine->lock, flags); @@ -4104,11 +4206,17 @@ ssize_t xdma_engine_read_cyclic(struct xdma_engine *engine, char __user *buf, int rc_len = 0; struct xdma_transfer *transfer; - BUG_ON(!engine); - BUG_ON(engine->magic != MAGIC_ENGINE); + if (unlikely(!engine || (engine->magic != MAGIC_ENGINE))) { + pr_err("bad engine 0x%p, magic 0x%lx.\n", + engine, engine ? engine->magic : 0UL); + return -EINVAL; + } + if (unlikely(!engine->cyclic_req)) { + pr_err("engine %s, cyclic_req NULL.\n", engine->name); + return -EINVAL; + } transfer = &engine->cyclic_req->xfer; - BUG_ON(!transfer); engine->user_buffer_index = 0; @@ -4207,9 +4315,11 @@ int xdma_cyclic_transfer_setup(struct xdma_engine *engine) int i; int rc; - BUG_ON(!engine); + if (unlikely(!engine || !engine->xdev)) { + pr_err("engine 0x%p, xdev NULL.\n", engine); + return -EINVAL; + } xdev = engine->xdev; - BUG_ON(!xdev); if (engine->cyclic_req) { pr_info("%s: exclusive access already taken.\n", @@ -4272,18 +4382,17 @@ int xdma_cyclic_transfer_setup(struct xdma_engine *engine) transfer_dump(xfer); #endif - if(enable_credit_mp){ - //write_register(RX_BUF_PAGES,&engine->sgdma_regs->credits); + if (enable_credit_mp) write_register(128, &engine->sgdma_regs->credits, 0); - } spin_unlock_irqrestore(&engine->lock, flags); /* start cyclic transfer */ - transfer_queue(engine, xfer); - - return 0; + rc = transfer_queue(engine, xfer); + if (!rc) + return 0; + spin_lock_irqsave(&engine->lock, flags); /* unwind on errors */ err_out: if (engine->cyclic_req) { @@ -4304,10 +4413,12 @@ int xdma_cyclic_transfer_setup(struct xdma_engine *engine) return rc; } - static int cyclic_shutdown_polled(struct xdma_engine *engine) { - BUG_ON(!engine); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return -EINVAL; + } spin_lock(&engine->lock); @@ -4336,18 +4447,13 @@ static int cyclic_shutdown_interrupt(struct xdma_engine *engine) { int rc; - BUG_ON(!engine); + if (unlikely(!engine)) { + pr_err("engine NULL.\n"); + return -EINVAL; + } rc = wait_event_interruptible_timeout(engine->shutdown_wq, !engine->running, msecs_to_jiffies(10000)); - -#if 0 - if (rc) { - dbg_tfr("wait_event_interruptible=%d\n", rc); - return rc; - } -#endif - if (engine->running) { pr_info("%s still running?!, %d\n", engine->name, rc); return -EINVAL; @@ -4364,6 +4470,10 @@ int xdma_cyclic_transfer_teardown(struct xdma_engine *engine) unsigned long flags; transfer = engine_cyclic_stop(engine); + if (transfer == NULL) { + pr_err("Failed to stop cyclic engine\n"); + return -EINVAL; + } spin_lock_irqsave(&engine->lock, flags); if (transfer) { @@ -4378,16 +4488,20 @@ int xdma_cyclic_transfer_teardown(struct xdma_engine *engine) spin_unlock_irqrestore(&engine->lock, flags); /* wait for engine to be no longer running */ - if (poll_mode) + if (poll_mode) rc = cyclic_shutdown_polled(engine); else rc = cyclic_shutdown_interrupt(engine); + if (rc < 0) { + pr_err("Failed to shutdown cyclic transfers\n"); + return rc; + } /* obtain spin lock to atomically remove resources */ spin_lock_irqsave(&engine->lock, flags); if (engine->cyclic_req) { - xdma_request_free(engine->cyclic_req); + xdma_request_free(engine->cyclic_req); engine->cyclic_req = NULL; } @@ -4413,7 +4527,7 @@ int engine_addrmode_set(struct xdma_engine *engine, unsigned long arg) dbg_perf("IOCTL_XDMA_ADDRMODE_SET\n"); rv = get_user(dst, (int __user *)arg); - if (rv == 0) { + if (rv == 0) { engine->non_incr_addr = !!dst; if (engine->non_incr_addr) write_register(w, &engine->regs->control_w1s, @@ -4428,4 +4542,3 @@ int engine_addrmode_set(struct xdma_engine *engine, unsigned long arg) return rv; } - diff --git a/sdk/linux_kernel_drivers/xdma/libxdma.h b/sdk/linux_kernel_drivers/xdma/libxdma.h old mode 100755 new mode 100644 index 07d016c2..1fbee5aa --- a/sdk/linux_kernel_drivers/xdma/libxdma.h +++ b/sdk/linux_kernel_drivers/xdma/libxdma.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -36,26 +36,32 @@ #include #include +/* + * if the config bar is fixed, the driver does not neeed to search through + * all of the bars + */ +//#define XDMA_CONFIG_BAR_NUM 1 + /* Switch debug printing on/off */ -#define XDMA_DEBUG 0 +#define XDMA_DEBUG 0 /* SECTION: Preprocessor macros/constants */ -#define XDMA_BAR_NUM (6) +#define XDMA_BAR_NUM (6) /* maximum amount of register space to map */ -#define XDMA_BAR_SIZE (0x8000UL) +#define XDMA_BAR_SIZE (0x8000UL) /* Use this definition to poll several times between calls to schedule */ -#define NUM_POLLS_PER_SCHED 100 +#define NUM_POLLS_PER_SCHED 100 -#define XDMA_CHANNEL_NUM_MAX (4) +#define XDMA_CHANNEL_NUM_MAX (4) /* * interrupts per engine, rad2_vul.sv:237 * .REG_IRQ_OUT (reg_irq_from_ch[(channel*2) +: 2]), */ -#define XDMA_ENG_IRQ_NUM (1) -#define MAX_EXTRA_ADJ (15) -#define RX_STATUS_EOP (1) +#define XDMA_ENG_IRQ_NUM (1) +#define MAX_EXTRA_ADJ (0x3F) +#define RX_STATUS_EOP (1) /* Target internal components on XDMA control BAR */ #define XDMA_OFS_INT_CTRL (0x2000UL) @@ -65,7 +71,7 @@ #define XDMA_TRANSFER_MAX_DESC (2048) /* maximum size of a single DMA transfer descriptor */ -#define XDMA_DESC_BLEN_BITS 28 +#define XDMA_DESC_BLEN_BITS 28 #define XDMA_DESC_BLEN_MAX ((1 << (XDMA_DESC_BLEN_BITS)) - 1) /* bits of the SG DMA control register */ @@ -157,7 +163,7 @@ #define XDMA_ID_C2H 0x1fc1U /* for C2H AXI-ST mode */ -#define CYCLIC_RX_PAGES_MAX 256 +#define CYCLIC_RX_PAGES_MAX 256 #define LS_BYTE_MASK 0x000000FFUL @@ -442,7 +448,8 @@ struct xdma_engine { int max_extra_adj; /* descriptor prefetch capability */ int desc_dequeued; /* num descriptors of completed transfers */ u32 status; /* last known status of device */ - u32 interrupt_enable_mask_value;/* only used for MSIX mode to store per-engine interrupt mask value */ + /* only used for MSIX mode to store per-engine interrupt mask value */ + u32 interrupt_enable_mask_value; /* Transfer list management */ struct list_head transfer_list; /* queue of transfers */ @@ -452,6 +459,10 @@ struct xdma_engine { dma_addr_t cyclic_result_bus; /* bus addr for transfer */ struct xdma_request_cb *cyclic_req; struct sg_table cyclic_sgt; + + u8 *perf_buf_virt; + dma_addr_t perf_buf_bus; /* bus address */ + u8 eop_found; /* used only for cyclic(rx:c2h) */ int rx_tail; /* follows the HW */ @@ -473,7 +484,7 @@ struct xdma_engine { u32 irq_bitmask; /* IRQ bit mask for this engine */ struct work_struct work; /* Work queue for interrupt handling */ - spinlock_t desc_lock; /* protects concurrent access */ + struct mutex desc_lock; /* protects concurrent access */ dma_addr_t desc_bus; struct xdma_desc *desc; @@ -490,14 +501,14 @@ struct xdma_user_irq { wait_queue_head_t events_wq; /* wait queue to sync waiting threads */ irq_handler_t handler; - void *dev; + void *dev; }; /* XDMA PCIe device specific book-keeping */ #define XDEV_FLAG_OFFLINE 0x1 struct xdma_dev { struct list_head list_head; - struct list_head rcu_node; + struct list_head rcu_node; unsigned long magic; /* structure ID for sanity checks */ struct pci_dev *pdev; /* pci device struct from probe() */ @@ -509,7 +520,7 @@ struct xdma_dev { unsigned int flags; /* PCIe BAR management */ - void *__iomem bar[XDMA_BAR_NUM]; /* addresses for mapped BARs */ + void __iomem *bar[XDMA_BAR_NUM]; /* addresses for mapped BARs */ int user_bar_idx; /* BAR index of user logic */ int config_bar_idx; /* BAR index of XDMA config logic */ int bypass_bar_idx; /* BAR index of XDMA bypass logic */ @@ -605,8 +616,8 @@ void get_perf_stats(struct xdma_engine *engine); int xdma_cyclic_transfer_setup(struct xdma_engine *engine); int xdma_cyclic_transfer_teardown(struct xdma_engine *engine); -ssize_t xdma_engine_read_cyclic(struct xdma_engine *, char __user *, size_t, - int); +ssize_t xdma_engine_read_cyclic(struct xdma_engine *engine, char __user *buf, + size_t count, int timeout_ms); int engine_addrmode_set(struct xdma_engine *engine, unsigned long arg); #endif /* XDMA_LIB_H */ diff --git a/sdk/linux_kernel_drivers/xdma/libxdma_api.h b/sdk/linux_kernel_drivers/xdma/libxdma_api.h index bf043eb1..d4ed4ec5 100644 --- a/sdk/linux_kernel_drivers/xdma/libxdma_api.h +++ b/sdk/linux_kernel_drivers/xdma/libxdma_api.h @@ -1,12 +1,24 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver + * Copyright(c) 2015 - 2020 Xilinx, Inc. * - * Copyright(c) Sidebranch. - * Copyright(c) Xilinx, Inc. + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "LICENSE". * * Karen Xie - * Leon Woestenberg * ******************************************************************************/ @@ -70,10 +82,7 @@ void xdma_device_close(struct pci_dev *pdev, void *dev_handle); /* * xdma_device_restart - restart the fpga * @pdev: ptr to struct pci_dev - * TODO: - * may need more refining on the parameter list * return < 0 in case of error - * TODO: exact error code will be defined later */ int xdma_device_restart(struct pci_dev *pdev, void *dev_handle); @@ -94,7 +103,6 @@ int xdma_device_restart(struct pci_dev *pdev, void *dev_handle); * @name: to be passed to the handler, ignored if handler is NULL` * @dev: to be passed to the handler, ignored if handler is NULL` * return < 0 in case of error - * TODO: exact error code will be defined later */ int xdma_user_isr_register(void *dev_hndl, unsigned int mask, irq_handler_t handler, void *dev); @@ -104,7 +112,6 @@ int xdma_user_isr_register(void *dev_hndl, unsigned int mask, * @pdev: ptr to the the pci_dev struct * @mask: bitmask of user interrupts (0 ~ 15)to be registered * return < 0 in case of error - * TODO: exact error code will be defined later */ int xdma_user_isr_enable(void *dev_hndl, unsigned int mask); int xdma_user_isr_disable(void *dev_hndl, unsigned int mask); @@ -121,15 +128,8 @@ int xdma_user_isr_disable(void *dev_hndl, unsigned int mask); * @timeout: timeout in mili-seconds, *currently ignored * return # of bytes transfered or * < 0 in case of error - * TODO: exact error code will be defined later */ ssize_t xdma_xfer_submit(void *dev_hndl, int channel, bool write, u64 ep_addr, struct sg_table *sgt, bool dma_mapped, int timeout_ms); - - -/////////////////////missing API//////////////////// - -//xdma_get_channle_state - if no interrupt on DMA hang is available -//xdma_channle_restart #endif diff --git a/sdk/linux_kernel_drivers/xdma/version.h b/sdk/linux_kernel_drivers/xdma/version.h old mode 100755 new mode 100644 index 64b91799..5ed57832 --- a/sdk/linux_kernel_drivers/xdma/version.h +++ b/sdk/linux_kernel_drivers/xdma/version.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,12 +21,13 @@ * Karen Xie * ******************************************************************************/ + #ifndef __XDMA_VERSION_H__ #define __XDMA_VERSION_H__ -#define DRV_MOD_MAJOR 2017 +#define DRV_MOD_MAJOR 2020 #define DRV_MOD_MINOR 1 -#define DRV_MOD_PATCHLEVEL 47 +#define DRV_MOD_PATCHLEVEL 01 #define DRV_MODULE_VERSION \ __stringify(DRV_MOD_MAJOR) "." \ diff --git a/sdk/linux_kernel_drivers/xdma/xdma_cdev.c b/sdk/linux_kernel_drivers/xdma/xdma_cdev.c index 8a331161..a5c3ac55 100644 --- a/sdk/linux_kernel_drivers/xdma/xdma_cdev.c +++ b/sdk/linux_kernel_drivers/xdma/xdma_cdev.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,11 +21,14 @@ * Karen Xie * ******************************************************************************/ + #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ #include "xdma_cdev.h" -struct class *g_xdma_class; +static struct class *g_xdma_class; + +struct kmem_cache *cdev_cache; enum cdev_type { CHAR_USER, @@ -52,12 +55,12 @@ static const char * const devnode_names[] = { }; enum xpdev_flags_bits { - XDF_CDEV_USER, - XDF_CDEV_CTRL, - XDF_CDEV_XVC, - XDF_CDEV_EVENT, - XDF_CDEV_SG, - XDF_CDEV_BYPASS, + XDF_CDEV_USER, + XDF_CDEV_CTRL, + XDF_CDEV_XVC, + XDF_CDEV_EVENT, + XDF_CDEV_SG, + XDF_CDEV_BYPASS, }; static inline void xpdev_flag_set(struct xdma_pci_dev *xpdev, @@ -79,16 +82,18 @@ static inline int xpdev_flag_test(struct xdma_pci_dev *xpdev, } #ifdef __XDMA_SYSFS__ -ssize_t show_device_numbers(struct device *dev, struct device_attribute *attr, - char *buf) +ssize_t xdma_dev_instance_show(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct xdma_pci_dev *xpdev = (struct xdma_pci_dev *)dev_get_drvdata(dev); + struct xdma_pci_dev *xpdev = + (struct xdma_pci_dev *)dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%d\t%d\n", xpdev->major, xpdev->xdev->idx); } -static DEVICE_ATTR(xdma_dev_instance, S_IRUGO, show_device_numbers, NULL); +static DEVICE_ATTR_RO(xdma_dev_instance); #endif static int config_kobject(struct xdma_cdev *xcdev, enum cdev_type type) @@ -102,7 +107,10 @@ static int config_kobject(struct xdma_cdev *xcdev, enum cdev_type type) case CHAR_XDMA_C2H: case CHAR_BYPASS_H2C: case CHAR_BYPASS_C2H: - BUG_ON(!engine); + if (!engine) { + pr_err("Invalid DMA engine\n"); + return rv; + } rv = kobject_set_name(&xcdev->cdev.kobj, devnode_names[type], xdev->idx, engine->channel); break; @@ -133,22 +141,23 @@ int xcdev_check(const char *fname, struct xdma_cdev *xcdev, bool check_engine) if (!xcdev || xcdev->magic != MAGIC_CHAR) { pr_info("%s, xcdev 0x%p, magic 0x%lx.\n", - fname, xcdev, xcdev ? xcdev->magic : 0xFFFFFFFF); + fname, xcdev, xcdev ? xcdev->magic : 0xFFFFFFFF); return -EINVAL; } - xdev = xcdev->xdev; + xdev = xcdev->xdev; if (!xdev || xdev->magic != MAGIC_DEVICE) { pr_info("%s, xdev 0x%p, magic 0x%lx.\n", - fname, xdev, xdev ? xdev->magic : 0xFFFFFFFF); + fname, xdev, xdev ? xdev->magic : 0xFFFFFFFF); return -EINVAL; } if (check_engine) { - struct xdma_engine *engine = xcdev->engine; + struct xdma_engine *engine = xcdev->engine; + if (!engine || engine->magic != MAGIC_ENGINE) { pr_info("%s, engine 0x%p, magic 0x%lx.\n", fname, - engine, engine ? engine->magic : 0xFFFFFFFF); + engine, engine ? engine->magic : 0xFFFFFFFF); return -EINVAL; } } @@ -162,7 +171,11 @@ int char_open(struct inode *inode, struct file *file) /* pointer to containing structure of the character device inode */ xcdev = container_of(inode->i_cdev, struct xdma_cdev, cdev); - BUG_ON(xcdev->magic != MAGIC_CHAR); + if (xcdev->magic != MAGIC_CHAR) { + pr_err("xcdev 0x%p inode 0x%lx magic mismatch 0x%lx\n", + xcdev, inode->i_ino, xcdev->magic); + return -EINVAL; + } /* create a reference to our char device in the opened file */ file->private_data = xcdev; @@ -177,13 +190,30 @@ int char_close(struct inode *inode, struct file *file) struct xdma_dev *xdev; struct xdma_cdev *xcdev = (struct xdma_cdev *)file->private_data; - BUG_ON(!xcdev); - BUG_ON(xcdev->magic != MAGIC_CHAR); + if (!xcdev) { + pr_err("char device with inode 0x%lx xcdev NULL\n", + inode->i_ino); + return -EINVAL; + } + + if (xcdev->magic != MAGIC_CHAR) { + pr_err("xcdev 0x%p magic mismatch 0x%lx\n", + xcdev, xcdev->magic); + return -EINVAL; + } /* fetch device specific data stored earlier during open */ xdev = xcdev->xdev; - BUG_ON(!xdev); - BUG_ON(xdev->magic != MAGIC_DEVICE); + if (!xdev) { + pr_err("char device with inode 0x%lx xdev NULL\n", + inode->i_ino); + return -EINVAL; + } + + if (xdev->magic != MAGIC_DEVICE) { + pr_err("xdev 0x%p magic mismatch 0x%lx\n", xdev, xdev->magic); + return -EINVAL; + } return 0; } @@ -197,40 +227,52 @@ int char_close(struct inode *inode, struct file *file) static int create_sys_device(struct xdma_cdev *xcdev, enum cdev_type type) { - struct xdma_dev *xdev = xcdev->xdev; - struct xdma_engine *engine = xcdev->engine; - int last_param; + struct xdma_dev *xdev = xcdev->xdev; + struct xdma_engine *engine = xcdev->engine; + int last_param; - if (type == CHAR_EVENTS) - last_param = xcdev->bar; - else - last_param = engine ? engine->channel : 0; + if (type == CHAR_EVENTS) + last_param = xcdev->bar; + else + last_param = engine ? engine->channel : 0; - xcdev->sys_device = device_create(g_xdma_class, &xdev->pdev->dev, - xcdev->cdevno, NULL, devnode_names[type], xdev->idx, - last_param); + xcdev->sys_device = device_create(g_xdma_class, &xdev->pdev->dev, + xcdev->cdevno, NULL, devnode_names[type], xdev->idx, + last_param); - if (!xcdev->sys_device) { - pr_err("device_create(%s) failed\n", devnode_names[type]); - return -1; - } + if (!xcdev->sys_device) { + pr_err("device_create(%s) failed\n", devnode_names[type]); + return -1; + } - return 0; + return 0; } static int destroy_xcdev(struct xdma_cdev *cdev) { if (!cdev) { pr_warn("cdev NULL.\n"); - return 0; + return -EINVAL; } if (cdev->magic != MAGIC_CHAR) { pr_warn("cdev 0x%p magic mismatch 0x%lx\n", cdev, cdev->magic); - return 0; + return -EINVAL; + } + + if (!cdev->xdev) { + pr_err("xdev NULL\n"); + return -EINVAL; + } + + if (!g_xdma_class) { + pr_err("g_xdma_class NULL\n"); + return -EINVAL; + } + + if (!cdev->sys_device) { + pr_err("cdev sys_device NULL\n"); + return -EINVAL; } - BUG_ON(!cdev->xdev); - BUG_ON(!g_xdma_class); - BUG_ON(!cdev->sys_device); if (cdev->sys_device) device_destroy(g_xdma_class, cdev->cdevno); @@ -341,58 +383,91 @@ static int create_xcdev(struct xdma_pci_dev *xpdev, struct xdma_cdev *xcdev, del_cdev: cdev_del(&xcdev->cdev); unregister_region: - unregister_chrdev_region(dev, XDMA_MINOR_COUNT); + unregister_chrdev_region(xcdev->cdevno, XDMA_MINOR_COUNT); return rv; } void xpdev_destroy_interfaces(struct xdma_pci_dev *xpdev) { - int i; - + int i = 0; + int rv; #ifdef __XDMA_SYSFS__ - device_remove_file(&xpdev->pdev->dev, &dev_attr_xdma_dev_instance); + device_remove_file(&xpdev->pdev->dev, &dev_attr_xdma_dev_instance); #endif if (xpdev_flag_test(xpdev, XDF_CDEV_SG)) { /* iterate over channels */ - for (i = 0; i < xpdev->h2c_channel_max; i++) + for (i = 0; i < xpdev->h2c_channel_max; i++) { /* remove SG DMA character device */ - destroy_xcdev(&xpdev->sgdma_h2c_cdev[i]); - for (i = 0; i < xpdev->c2h_channel_max; i++) - destroy_xcdev(&xpdev->sgdma_c2h_cdev[i]); + rv = destroy_xcdev(&xpdev->sgdma_h2c_cdev[i]); + if (rv < 0) + pr_err("Failed to destroy h2c xcdev %d error :0x%x\n", + i, rv); + } + for (i = 0; i < xpdev->c2h_channel_max; i++) { + rv = destroy_xcdev(&xpdev->sgdma_c2h_cdev[i]); + if (rv < 0) + pr_err("Failed to destroy c2h xcdev %d error 0x%x\n", + i, rv); + } } if (xpdev_flag_test(xpdev, XDF_CDEV_EVENT)) { - for (i = 0; i < xpdev->user_max; i++) - destroy_xcdev(&xpdev->events_cdev[i]); + for (i = 0; i < xpdev->user_max; i++) { + rv = destroy_xcdev(&xpdev->events_cdev[i]); + if (rv < 0) + pr_err("Failed to destroy cdev event %d error 0x%x\n", + i, rv); + } } /* remove control character device */ if (xpdev_flag_test(xpdev, XDF_CDEV_CTRL)) { - destroy_xcdev(&xpdev->ctrl_cdev); + rv = destroy_xcdev(&xpdev->ctrl_cdev); + if (rv < 0) + pr_err("Failed to destroy cdev ctrl event %d error 0x%x\n", + i, rv); } /* remove user character device */ if (xpdev_flag_test(xpdev, XDF_CDEV_USER)) { - destroy_xcdev(&xpdev->user_cdev); + rv = destroy_xcdev(&xpdev->user_cdev); + if (rv < 0) + pr_err("Failed to destroy user cdev %d error 0x%x\n", + i, rv); } if (xpdev_flag_test(xpdev, XDF_CDEV_XVC)) { - destroy_xcdev(&xpdev->xvc_cdev); + rv = destroy_xcdev(&xpdev->xvc_cdev); + if (rv < 0) + pr_err("Failed to destroy xvc cdev %d error 0x%x\n", + i, rv); } if (xpdev_flag_test(xpdev, XDF_CDEV_BYPASS)) { /* iterate over channels */ - for (i = 0; i < xpdev->h2c_channel_max; i++) + for (i = 0; i < xpdev->h2c_channel_max; i++) { /* remove DMA Bypass character device */ - destroy_xcdev(&xpdev->bypass_h2c_cdev[i]); - for (i = 0; i < xpdev->c2h_channel_max; i++) - destroy_xcdev(&xpdev->bypass_c2h_cdev[i]); - destroy_xcdev(&xpdev->bypass_cdev_base); + rv = destroy_xcdev(&xpdev->bypass_h2c_cdev[i]); + if (rv < 0) + pr_err("Failed to destroy bypass h2c cdev %d error 0x%x\n", + i, rv); + } + for (i = 0; i < xpdev->c2h_channel_max; i++) { + rv = destroy_xcdev(&xpdev->bypass_c2h_cdev[i]); + if (rv < 0) + pr_err("Failed to destroy bypass c2h %d error 0x%x\n", + i, rv); + } + rv = destroy_xcdev(&xpdev->bypass_cdev_base); + if (rv < 0) + pr_err("Failed to destroy base cdev\n"); } if (xpdev->major) - unregister_chrdev_region(MKDEV(xpdev->major, XDMA_MINOR_BASE), XDMA_MINOR_COUNT); + unregister_chrdev_region( + MKDEV(xpdev->major, XDMA_MINOR_BASE), + XDMA_MINOR_COUNT); } int xpdev_create_interfaces(struct xdma_pci_dev *xpdev) @@ -452,9 +527,8 @@ int xpdev_create_interfaces(struct xdma_pci_dev *xpdev) } xpdev_flag_set(xpdev, XDF_CDEV_SG); - /* ??? Bypass */ /* Initialize Bypass Character Device */ - if (xdev->bypass_bar_idx > 0){ + if (xdev->bypass_bar_idx > 0) { for (i = 0; i < xpdev->h2c_channel_max; i++) { engine = &xdev->engine_h2c[i]; @@ -519,7 +593,7 @@ int xpdev_create_interfaces(struct xdma_pci_dev *xpdev) rv = device_create_file(&xpdev->pdev->dev, &dev_attr_xdma_dev_instance); if (rv) { - pr_err("Failed to create device file \n"); + pr_err("Failed to create device file\n"); goto fail; } #endif @@ -535,10 +609,10 @@ int xpdev_create_interfaces(struct xdma_pci_dev *xpdev) int xdma_cdev_init(void) { g_xdma_class = class_create(THIS_MODULE, XDMA_NODE_NAME); - if (IS_ERR(g_xdma_class)) { - dbg_init(XDMA_NODE_NAME ": failed to create class"); - return -1; - } + if (IS_ERR(g_xdma_class)) { + dbg_init(XDMA_NODE_NAME ": failed to create class"); + return -EINVAL; + } return 0; } diff --git a/sdk/linux_kernel_drivers/xdma/xdma_cdev.h b/sdk/linux_kernel_drivers/xdma/xdma_cdev.h index 47441fca..3361e8eb 100644 --- a/sdk/linux_kernel_drivers/xdma/xdma_cdev.h +++ b/sdk/linux_kernel_drivers/xdma/xdma_cdev.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,6 +21,7 @@ * Karen Xie * ******************************************************************************/ + #ifndef __XDMA_CHRDEV_H__ #define __XDMA_CHRDEV_H__ @@ -39,13 +40,13 @@ int xdma_cdev_init(void); int char_open(struct inode *inode, struct file *file); int char_close(struct inode *inode, struct file *file); -int xcdev_check(const char *, struct xdma_cdev *, bool); - +int xcdev_check(const char *fname, struct xdma_cdev *xcdev, bool check_engine); void cdev_ctrl_init(struct xdma_cdev *xcdev); void cdev_xvc_init(struct xdma_cdev *xcdev); void cdev_event_init(struct xdma_cdev *xcdev); void cdev_sgdma_init(struct xdma_cdev *xcdev); void cdev_bypass_init(struct xdma_cdev *xcdev); +long char_ctrl_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); void xpdev_destroy_interfaces(struct xdma_pci_dev *xpdev); int xpdev_create_interfaces(struct xdma_pci_dev *xpdev); diff --git a/sdk/linux_kernel_drivers/xdma/xdma_ioctl.h b/sdk/linux_kernel_drivers/xdma/xdma_ioctl.h deleted file mode 100755 index a250a1de..00000000 --- a/sdk/linux_kernel_drivers/xdma/xdma_ioctl.h +++ /dev/null @@ -1,78 +0,0 @@ -/******************************************************************************* - * - * Xilinx XDMA IP Core Linux Driver - * - * Copyright(c) Sidebranch. - * Copyright(c) Xilinx, Inc. - * - * Karen Xie - * Leon Woestenberg - * - ******************************************************************************/ -#ifndef _XDMA_IOCALLS_POSIX_H_ -#define _XDMA_IOCALLS_POSIX_H_ - -#include - -/* Use 'x' as magic number */ -#define XDMA_IOC_MAGIC 'x' -/* XL OpenCL X->58(ASCII), L->6C(ASCII), O->0 C->C L->6C(ASCII); */ -#define XDMA_XCL_MAGIC 0X586C0C6C - -#define IOCTL_XDMA_PERF_V1 (1) -#define XDMA_ADDRMODE_MEMORY (0) -#define XDMA_ADDRMODE_FIXED (1) - -/* - * S means "Set" through a ptr, - * T means "Tell" directly with the argument value - * G means "Get": reply by setting through a pointer - * Q means "Query": response is on the return value - * X means "eXchange": switch G and S atomically - * H means "sHift": switch T and Q atomically - * - * _IO(type,nr) no arguments - * _IOR(type,nr,datatype) read data from driver - * _IOW(type,nr.datatype) write data to driver - * _IORW(type,nr,datatype) read/write data - * - * _IOC_DIR(nr) returns direction - * _IOC_TYPE(nr) returns magic - * _IOC_NR(nr) returns number - * _IOC_SIZE(nr) returns size - */ - -enum XDMA_IOC_TYPES { - XDMA_IOC_NOP, - XDMA_IOC_INFO, - XDMA_IOC_MAX -}; - -struct xdma_ioc_base { - unsigned int magic; - unsigned int command; -}; - -struct xdma_ioc_info { - struct xdma_ioc_base base; - unsigned short vendor; - unsigned short device; - unsigned short subsystem_vendor; - unsigned short subsystem_device; - unsigned dma_engine_version; - unsigned driver_version; - unsigned long long feature_id; - unsigned short domain; - unsigned char bus; - unsigned char dev; - unsigned char func; -}; - -/* IOCTL codes */ -#define XDMA_IOCINFO _IOWR(XDMA_IOC_MAGIC, XDMA_IOC_INFO, struct xdma_ioc_info) - -#define IOCTL_XDMA_ADDRMODE_SET _IOW('q', 4, int) -#define IOCTL_XDMA_ADDRMODE_GET _IOR('q', 5, int) -#define IOCTL_XDMA_ALIGN_GET _IOR('q', 6, int) - -#endif /* _XDMA_IOCALLS_POSIX_H_ */ diff --git a/sdk/linux_kernel_drivers/xdma/xdma_mod.c b/sdk/linux_kernel_drivers/xdma/xdma_mod.c old mode 100755 new mode 100644 index 3b094322..b9dbfcfe --- a/sdk/linux_kernel_drivers/xdma/xdma_mod.c +++ b/sdk/linux_kernel_drivers/xdma/xdma_mod.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,6 +21,7 @@ * Karen Xie * ******************************************************************************/ + #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ #include @@ -35,8 +36,7 @@ #include "version.h" #define DRV_MODULE_NAME "xdma" -#define DRV_MODULE_DESC "Xilinx XDMA Classic Driver" -#define DRV_MODULE_RELDATE "Feb. 2017" +#define DRV_MODULE_DESC "Xilinx XDMA Reference Driver" static char version[] = DRV_MODULE_DESC " " DRV_MODULE_NAME " v" DRV_MODULE_VERSION "\n"; @@ -47,48 +47,52 @@ MODULE_VERSION(DRV_MODULE_VERSION); MODULE_LICENSE("GPL v2"); /* SECTION: Module global variables */ -static int xpdev_cnt = 0; +static int xpdev_cnt; static const struct pci_device_id pci_ids[] = { + { PCI_DEVICE(0x10ee, 0x9048), }, + { PCI_DEVICE(0x10ee, 0x9044), }, + { PCI_DEVICE(0x10ee, 0x9042), }, + { PCI_DEVICE(0x10ee, 0x9041), }, { PCI_DEVICE(0x10ee, 0x903f), }, { PCI_DEVICE(0x10ee, 0x9038), }, { PCI_DEVICE(0x10ee, 0x9028), }, - { PCI_DEVICE(0x10ee, 0x9018), }, + { PCI_DEVICE(0x10ee, 0x9018), }, { PCI_DEVICE(0x10ee, 0x9034), }, { PCI_DEVICE(0x10ee, 0x9024), }, - { PCI_DEVICE(0x10ee, 0x9014), }, + { PCI_DEVICE(0x10ee, 0x9014), }, { PCI_DEVICE(0x10ee, 0x9032), }, { PCI_DEVICE(0x10ee, 0x9022), }, - { PCI_DEVICE(0x10ee, 0x9012), }, + { PCI_DEVICE(0x10ee, 0x9012), }, { PCI_DEVICE(0x10ee, 0x9031), }, { PCI_DEVICE(0x10ee, 0x9021), }, - { PCI_DEVICE(0x10ee, 0x9011), }, + { PCI_DEVICE(0x10ee, 0x9011), }, { PCI_DEVICE(0x10ee, 0x8011), }, { PCI_DEVICE(0x10ee, 0x8012), }, - { PCI_DEVICE(0x10ee, 0x8014), }, - { PCI_DEVICE(0x10ee, 0x8018), }, - { PCI_DEVICE(0x10ee, 0x8021), }, - { PCI_DEVICE(0x10ee, 0x8022), }, - { PCI_DEVICE(0x10ee, 0x8024), }, - { PCI_DEVICE(0x10ee, 0x8028), }, - { PCI_DEVICE(0x10ee, 0x8031), }, - { PCI_DEVICE(0x10ee, 0x8032), }, - { PCI_DEVICE(0x10ee, 0x8034), }, - { PCI_DEVICE(0x10ee, 0x8038), }, - - { PCI_DEVICE(0x10ee, 0x7011), }, - { PCI_DEVICE(0x10ee, 0x7012), }, - { PCI_DEVICE(0x10ee, 0x7014), }, - { PCI_DEVICE(0x10ee, 0x7018), }, - { PCI_DEVICE(0x10ee, 0x7021), }, - { PCI_DEVICE(0x10ee, 0x7022), }, - { PCI_DEVICE(0x10ee, 0x7024), }, + { PCI_DEVICE(0x10ee, 0x8014), }, + { PCI_DEVICE(0x10ee, 0x8018), }, + { PCI_DEVICE(0x10ee, 0x8021), }, + { PCI_DEVICE(0x10ee, 0x8022), }, + { PCI_DEVICE(0x10ee, 0x8024), }, + { PCI_DEVICE(0x10ee, 0x8028), }, + { PCI_DEVICE(0x10ee, 0x8031), }, + { PCI_DEVICE(0x10ee, 0x8032), }, + { PCI_DEVICE(0x10ee, 0x8034), }, + { PCI_DEVICE(0x10ee, 0x8038), }, + + { PCI_DEVICE(0x10ee, 0x7011), }, + { PCI_DEVICE(0x10ee, 0x7012), }, + { PCI_DEVICE(0x10ee, 0x7014), }, + { PCI_DEVICE(0x10ee, 0x7018), }, + { PCI_DEVICE(0x10ee, 0x7021), }, + { PCI_DEVICE(0x10ee, 0x7022), }, + { PCI_DEVICE(0x10ee, 0x7024), }, { PCI_DEVICE(0x10ee, 0x7028), }, - { PCI_DEVICE(0x10ee, 0x7031), }, - { PCI_DEVICE(0x10ee, 0x7032), }, - { PCI_DEVICE(0x10ee, 0x7034), }, - { PCI_DEVICE(0x10ee, 0x7038), }, + { PCI_DEVICE(0x10ee, 0x7031), }, + { PCI_DEVICE(0x10ee, 0x7032), }, + { PCI_DEVICE(0x10ee, 0x7034), }, + { PCI_DEVICE(0x10ee, 0x7038), }, { PCI_DEVICE(0x10ee, 0x6828), }, { PCI_DEVICE(0x10ee, 0x6830), }, @@ -105,13 +109,12 @@ static const struct pci_device_id pci_ids[] = { { PCI_DEVICE(0x10ee, 0x4B28), }, { PCI_DEVICE(0x10ee, 0x2808), }, + { PCI_DEVICE(0x1d0f, 0xf000), }, + { PCI_DEVICE(0x1d0f, 0xf001), }, - { PCI_DEVICE(0x10ee, 0x2808), }, - - { PCI_DEVICE(0x1d0f, 0xf000), }, - { PCI_DEVICE(0x1d0f, 0xf001), }, - { PCI_DEVICE(0x1d0f, 0x1042), }, - +#ifdef INTERNAL_TESTING + { PCI_DEVICE(0x1d0f, 0x1042), 0}, +#endif {0,} }; MODULE_DEVICE_TABLE(pci, pci_ids); @@ -132,7 +135,7 @@ static void xpdev_free(struct xdma_pci_dev *xpdev) static struct xdma_pci_dev *xpdev_alloc(struct pci_dev *pdev) { - struct xdma_pci_dev *xpdev = kmalloc(sizeof(*xpdev), GFP_KERNEL); + struct xdma_pci_dev *xpdev = kmalloc(sizeof(*xpdev), GFP_KERNEL); if (!xpdev) return NULL; @@ -161,12 +164,28 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id) hndl = xdma_device_open(DRV_MODULE_NAME, pdev, &xpdev->user_max, &xpdev->h2c_channel_max, &xpdev->c2h_channel_max); - if (!hndl) - return -EINVAL; + if (!hndl) { + rv = -EINVAL; + goto err_out; + } - BUG_ON(xpdev->user_max > MAX_USER_IRQ); - BUG_ON(xpdev->h2c_channel_max > XDMA_CHANNEL_NUM_MAX); - BUG_ON(xpdev->c2h_channel_max > XDMA_CHANNEL_NUM_MAX); + if (xpdev->user_max > MAX_USER_IRQ) { + pr_err("Maximum users limit reached\n"); + rv = -EINVAL; + goto err_out; + } + + if (xpdev->h2c_channel_max > XDMA_CHANNEL_NUM_MAX) { + pr_err("Maximun H2C channel limit reached\n"); + rv = -EINVAL; + goto err_out; + } + + if (xpdev->c2h_channel_max > XDMA_CHANNEL_NUM_MAX) { + pr_err("Maximun C2H channel limit reached\n"); + rv = -EINVAL; + goto err_out; + } if (!xpdev->h2c_channel_max && !xpdev->c2h_channel_max) pr_warn("NO engine found!\n"); @@ -183,9 +202,15 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id) xdev = xdev_find_by_pdev(pdev); if (!xdev) { pr_warn("NO xdev found!\n"); - return -EINVAL; + rv = -EINVAL; + goto err_out; + } + + if (hndl != xdev) { + pr_err("xdev handle mismatch\n"); + rv = -EINVAL; + goto err_out; } - BUG_ON(hndl != xdev ); pr_info("%s xdma%d, pdev 0x%p, xdev 0x%p, 0x%p, usr %d, ch %d,%d.\n", dev_name(&pdev->dev), xdev->idx, pdev, xpdev, xdev, @@ -198,11 +223,11 @@ static int probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (rv) goto err_out; - dev_set_drvdata(&pdev->dev, xpdev); + dev_set_drvdata(&pdev->dev, xpdev); return 0; -err_out: +err_out: pr_err("pdev 0x%p, err %d.\n", pdev, rv); xpdev_free(xpdev); return rv; @@ -223,7 +248,7 @@ static void remove_one(struct pci_dev *pdev) pdev, xpdev, xpdev->xdev); xpdev_free(xpdev); - dev_set_drvdata(&pdev->dev, NULL); + dev_set_drvdata(&pdev->dev, NULL); } static pci_ers_result_t xdma_error_detected(struct pci_dev *pdev, @@ -274,7 +299,7 @@ static void xdma_error_resume(struct pci_dev *pdev) pci_cleanup_aer_uncorrect_error_status(pdev); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0) +#if KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE static void xdma_reset_prepare(struct pci_dev *pdev) { struct xdma_pci_dev *xpdev = dev_get_drvdata(&pdev->dev); @@ -291,7 +316,7 @@ static void xdma_reset_done(struct pci_dev *pdev) xdma_device_online(pdev, xpdev->xdev); } -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) +#elif KERNEL_VERSION(3, 16, 0) <= LINUX_VERSION_CODE static void xdma_reset_notify(struct pci_dev *pdev, bool prepare) { struct xdma_pci_dev *xpdev = dev_get_drvdata(&pdev->dev); @@ -309,10 +334,10 @@ static const struct pci_error_handlers xdma_err_handler = { .error_detected = xdma_error_detected, .slot_reset = xdma_slot_reset, .resume = xdma_error_resume, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0) +#if KERNEL_VERSION(4, 13, 0) <= LINUX_VERSION_CODE .reset_prepare = xdma_reset_prepare, .reset_done = xdma_reset_done, -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) +#elif KERNEL_VERSION(3, 16, 0) <= LINUX_VERSION_CODE .reset_notify = xdma_reset_notify, #endif }; @@ -328,8 +353,6 @@ static struct pci_driver pci_driver = { static int __init xdma_mod_init(void) { int rv; - extern unsigned int desc_blen_max; - extern unsigned int sgdma_timeout; pr_info("%s", version); diff --git a/sdk/linux_kernel_drivers/xdma/xdma_mod.h b/sdk/linux_kernel_drivers/xdma/xdma_mod.h old mode 100755 new mode 100644 index 0ede7a08..abea67ee --- a/sdk/linux_kernel_drivers/xdma/xdma_mod.h +++ b/sdk/linux_kernel_drivers/xdma/xdma_mod.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Xilinx XDMA IP Core Linux Driver - * Copyright(c) 2015 - 2017 Xilinx, Inc. + * Copyright(c) 2015 - 2020 Xilinx, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -21,6 +21,7 @@ * Karen Xie * ******************************************************************************/ + #ifndef __XDMA_MODULE_H__ #define __XDMA_MODULE_H__ @@ -48,6 +49,7 @@ #include #include #include +#include #include "libxdma.h" @@ -56,6 +58,9 @@ #define MAGIC_CHAR 0xCCCCCCCCUL #define MAGIC_BITSTREAM 0xBBBBBBBBUL +extern unsigned int desc_blen_max; +extern unsigned int sgdma_timeout; + struct xdma_cdev { unsigned long magic; /* structure ID for sanity checks */ struct xdma_pci_dev *xpdev; diff --git a/shared/lib/check_src_headers.py b/shared/lib/check_src_headers.py index 329896eb..ef758686 100755 --- a/shared/lib/check_src_headers.py +++ b/shared/lib/check_src_headers.py @@ -176,7 +176,7 @@ ''' xilinx_xdma1 = '''Xilinx XDMA IP Core Linux Driver -Copyright(c) 2015 - 2017 Xilinx, Inc. +Copyright(c) 2015 - 2020 Xilinx, Inc. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -194,12 +194,6 @@ the file called "LICENSE". ''' -xilinx_xdma2 = '''Xilinx XDMA IP Core Linux Driver - -Copyright(c) Sidebranch. -Copyright(c) Xilinx, Inc. -''' - xilinx1 = '''\xa9 Copyright 2017 Xilinx, Inc. All rights reserved. This file contains confidential and proprietary information of Xilinx, Inc. and is protected under U.S. and @@ -400,7 +394,6 @@ apache_header_2018.split("\n"), gpl2_header.split("\n"), xilinx_xdma1.split("\n"), - xilinx_xdma2.split("\n"), xilinx1.split("\n"), xilinx2_header.split("\n"), xilinx3_header.split("\n"), From cbd4e77195ef9ce021eec5f2ec93f00fba08cde0 Mon Sep 17 00:00:00 2001 From: ThomasXilinx Date: Tue, 6 Oct 2020 15:54:44 -0700 Subject: [PATCH 26/31] Update Setup_AWS_CLI_and_S3_Bucket.md (#504) --- Vitis/docs/Setup_AWS_CLI_and_S3_Bucket.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Vitis/docs/Setup_AWS_CLI_and_S3_Bucket.md b/Vitis/docs/Setup_AWS_CLI_and_S3_Bucket.md index da09483a..dae67296 100644 --- a/Vitis/docs/Setup_AWS_CLI_and_S3_Bucket.md +++ b/Vitis/docs/Setup_AWS_CLI_and_S3_Bucket.md @@ -3,7 +3,7 @@ The developer is required to create an S3 bucket for the AFI generation. The buc To install the AWS CLI, please follow the [instructions here](http://docs.aws.amazon.com/cli/latest/userguide/installing.html). -The AWS SDAccel scripts require JSON output format and the scripts will not work properly if you use any other output format types (ex: text, table). JSON is the default output format of the AWS CLI. +The AWS Vitis scripts require JSON output format and the scripts will not work properly if you use any other output format types (ex: text, table). JSON is the default output format of the AWS CLI. ``` $ aws configure # to set your credentials (found in your console.aws.amazon.com page), region (us-east-1) and output (json) From ef053068dac1954dde532f86507d944187a566a7 Mon Sep 17 00:00:00 2001 From: Deep Patel Date: Tue, 20 Oct 2020 09:57:50 -0500 Subject: [PATCH 27/31] Release v1.4.17 (#505) * Updated XDMA Driver to allow builds on newer kernels * Updated documentation on Alveo U200 to F1 platform porting * Added Vitis 2019.2 Patching for AR#73068 --- RELEASE_NOTES.md | 5 ++ Vitis/docs/Alveo_to_AWS_F1_Migration.md | 61 ------------------- .../example/README.md | 10 +-- Vitis/tests/test_build_vitis_example.py | 2 +- hdk/hdk_version.txt | 2 +- shared/bin/set_common_functions.sh | 35 +++++++++-- vitis_setup.sh | 4 +- 7 files changed, 43 insertions(+), 76 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 363a00eb..3b9b8ead 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,10 @@ # AWS EC2 FPGA HDK+SDK Release Notes +## Release 1.4.17 (See [ERRATA](./ERRATA.md) for unsupported features) +* Updated XDMA Driver to allow builds on newer kernels +* Updated documentation on Alveo U200 to F1 platform porting +* Added Vitis 2019.2 Patching for AR#73068 + ## Release 1.4.16 (See [ERRATA](./ERRATA.md) for unsupported features) * FPGA developer kit now supports Xilinx Vivado/Vitis 2020.1 * To upgrade, use [Developer AMI v1.9.0](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) on the AWS Marketplace. diff --git a/Vitis/docs/Alveo_to_AWS_F1_Migration.md b/Vitis/docs/Alveo_to_AWS_F1_Migration.md index cdcb5fc3..01513f8a 100644 --- a/Vitis/docs/Alveo_to_AWS_F1_Migration.md +++ b/Vitis/docs/Alveo_to_AWS_F1_Migration.md @@ -161,67 +161,6 @@ A detailed working example walking through all the steps required to migrate an In this example, the source code for the software program and the FPGA kernels remains identical whether targeting U200 or F1 instances. Only command line changes are necessary to port the application. -The Vitis flow leverages dedicated compilation steps to build the software program and FPGA accelerators. These steps are described below. - - - -### Compiling the software program - -The software program is compiled exactly in the same way in both case: - -```bash -g++ -D__USE_XOPEN2K8 -I/$(XILINX_XRT)/include/ -I./src -O3 -Wall -fmessage-length=0 -std=c++11 ../src/host.cpp -L/$(XILINX_XRT)/lib/ -lxilinxopencl -lpthread -lrt -o host -``` - -The software program is linked with the XRT libraries which manages the specific requirements of each FPGA platform, allowing the source code to remain the same for U200 and F1. - -See [here](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/buildinghostprogram.html#asy1528754332783) for more details about building the host program for the Vitis flow. - - -### Compiling the FPGA binary - -When building the FPGA binary only a few options need to be changed when retargeting from U200 and F1 instances. These options are contained in a specific file (called options.cfg in our example) and which is passed to the Vitis v++ compiler with the `--config` command line option. - -Here is a side-by-side view of the both options.cfg files: - -| Contents of options.cfg for Alveo U200 | Contents of options.cfg for AWS F1 | -| ------------------------------------------------------------ | ------------------------------------------------------------ | -| platform=xilinx_u200_xdma_201830_2
[connectivity]
sp=vadd_1.in1:DDR[1]
sp=vadd_1.in2:DDR[1]
sp=vadd_1.out:DDR[1] | platform=xilinx_aws-vu9p-f1_shell-v04261818_201920_2
[connectivity]
sp=vadd_1.in1:DDR[0]
sp=vadd_1.in2:DDR[0]
sp=vadd_1.out:DDR[0] | - -The platform option specifies which acceleration platform is targeted for the build. - -The `sp` option is used to specify the assignment of kernel interfaces to DDR interfaces. The original U200 design is connecting the kernel interfaces to DDR[1] which is located in the shell. Keeping the same settings would produce a working design on F1 instances, but in order to produce exactly the same configuration and target the DDR interface located in the F1 shell, the `sp` options are modified to use DDR[0]. - -Putting all the platform specific options in a dedicated file allows the v++ build commands remain strictly identical: - -```bash -// Step 1: compile the kernel from source code -v++ -c -g -t hw -R 1 -k vadd --profile_kernel data:all:all:all --profile_kernel stall:all:all:all --save-temps --temp_dir ./temp_dir --report_dir ./report_dir --log_dir ./log_dir --config ./options.cfg -I../src ../src/vadd.cpp -o ./vadd.hw.xo - -// Step 2: link the compiled kernel with the shell and produce the FPGA binary -v++ -l -g -t hw -R 1 --profile_kernel data:all:all:all --profile_kernel stall:all:all:all --temp_dir ./temp_dir --report_dir ./report_dir --log_dir ./log_dir --config ./options.cfg -I../src vadd.hw.xo -o add.hw.xclbin -``` - -See [here](https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/vitiscommandcompiler.html#wrj1504034328013) for more information about the v++ command line options and configuration files. - - - -### Creating the Amazon FPGA Image - -Once you have compiled the host program and the FPGA binary, you are ready to execute the FPGA-accelerated application on a server equipped with an Alveo U200 acceleration card. - -When targeting F1 instances, you need to go through the additional step of creating an Amazon FPGA Image (AFI). This is done with the `create_vitis_afi.sh` command provided by AWS. This command reads in the FPGA binary generated by the v++ linker and requires information about the user’s AWS S3 bucket. - -In this example, the command looks as follows: - -```bash -$AWS_FPGA_REPO_DIR/Vitis/tools/create_vitis_afi.sh -xclbin=./vadd.xclbin -o=./vadd -s3_bucket= -s3_dcp_key=f1-dcp-folder -s3_logs_key=f1-logs -``` - -For more details about the `create_vitis_afi.sh` command, you can consult the AWS documentation [here](https://github.com/aws/aws-fpga/blob/master/Vitis/README.md#2-create-an-amazon-fpga-image-afi). - - - ## Summary – Migration Checklist Because Vitis provides platform-independent APIs and interfaces to the developer, the process of migrating applications across similar FPGA acceleration cards is greatly facilitated. diff --git a/Vitis/docs/Alveo_to_AWS_F1_Migration/example/README.md b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/README.md index 9aa4ec39..e35d4d71 100644 --- a/Vitis/docs/Alveo_to_AWS_F1_Migration/example/README.md +++ b/Vitis/docs/Alveo_to_AWS_F1_Migration/example/README.md @@ -7,18 +7,18 @@ The Vitis development flow provides platform independent APIs and interfaces to ## Example Overview -The accelerator used in this example is a simple vector-add kernel. The `src` directory contains the source code for the project: +The accelerator used in this example is a simple vector-add kernel. The [`src`](./src) directory contains the source code for the project: -- `vadd.cpp` contains the C++ source code of the accelerator which adds 2 arbitrarily sized input vectors. -- `host.cpp` contains the main function running on the host CPU. The host application is written in C++ and uses OpenCL™ APIs to interact with the FPGA accelerator. +- [`vadd.cpp`](./src/vadd.cpp) contains the C++ source code of the accelerator which adds 2 arbitrarily sized input vectors. +- [`host.cpp`](./src/host.cpp) contains the main function running on the host CPU. The host application is written in C++ and uses OpenCL™ APIs to interact with the FPGA accelerator. -The `u200` and `f1` directories contain the Makefiles and scripts for building for Alveo U200 and AWS F1 respectively. +The [`u200`](./u200) and The [`u200`](./u200) and [`f1`](./f1) directories contain the Makefiles and scripts for building for Alveo U200 and AWS F1 respectively. directories contain the Makefiles and scripts for building for Alveo U200 and AWS F1 respectively. ## Building for Alveo U200 -*Note: The instructions below assume that the required tools and platforms are installed and that the environment is properly setup to run Vitis.* +*Note: The instructions below assume that the required tools and platforms are installed and that the environment is properly setup to run Vitis. It is also a good idea to complete the Vitis example flow end-to-end before running this example.* 1. Go to the `u200` directory diff --git a/Vitis/tests/test_build_vitis_example.py b/Vitis/tests/test_build_vitis_example.py index 8ea0a989..5da6e81a 100644 --- a/Vitis/tests/test_build_vitis_example.py +++ b/Vitis/tests/test_build_vitis_example.py @@ -103,7 +103,7 @@ def base_test(self, examplePath, target, rteName, xilinxVersion, clean=True, che if check: check_string = "check" - (rc, stdout_lines, stderr_lines) = self.run_cmd("make {0} TARGET={1} DEVICE={2} all".format(check_string, target, os.environ['AWS_PLATFORM'])) + (rc, stdout_lines, stderr_lines) = self.run_cmd("make {0} TARGET={1} DEVICE={2} all PROFILE=yes".format(check_string, target, os.environ['AWS_PLATFORM'])) assert rc == 0, "Vitis build failed with rc={}".format(rc) # Check for non zero xclbin diff --git a/hdk/hdk_version.txt b/hdk/hdk_version.txt index 654491f1..cc4e772e 100644 --- a/hdk/hdk_version.txt +++ b/hdk/hdk_version.txt @@ -1 +1 @@ -HDK_VERSION=1.4.16 +HDK_VERSION=1.4.17 diff --git a/shared/bin/set_common_functions.sh b/shared/bin/set_common_functions.sh index 94bd19bb..fe31c60b 100644 --- a/shared/bin/set_common_functions.sh +++ b/shared/bin/set_common_functions.sh @@ -69,8 +69,7 @@ function get_base_vivado_version { local MYVIVADO_ENV_VAR_BACKUP=$MYVIVADO unset MYVIVADO - local __vivado_version=$(get_vivado_v - ersion) + local __vivado_version=$(get_vivado_version) export MYVIVADO=$MYVIVADO_ENV_VAR_BACKUP elif is_xilinx_path_set then @@ -116,8 +115,9 @@ function get_vivado_version { } function setup_patches { + local caller_script="${BASH_SOURCE[1]}" patch_AR71715 - patch_AR73068 + patch_AR73068 "$caller_script" } function is_patch_applied { @@ -211,13 +211,28 @@ function install_patch { fi } -function patch_AR73068_2019_2 { - info_msg "Patching Vivado 2019.2 with Xilinx Patch AR73068" +function fix_patch_vitis_AR73068_2019_2 { + local patch_object="$1" + local patch_dir_name="${patch_object%.*}" + pushd patches/$patch_dir_name + + sed -i '/.*checksum.*/d' ./vivado/data/ip/xilinx/ddr4_v2_2/component.xml + sed -i 's/coreRevision>73068/coreRevision>8/' ./vivado/data/ip/xilinx/ddr4_v2_2/component.xml + popd +} +function patch_AR73068_2019_2 { + info_msg "Patching Vivado/Vitis 2019.2 with Xilinx Patch AR73068" + local fix_patch="$1" local patch_bucket="https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/AR73068" local patch_object="AR73068_Vivado_2019_2_preliminary_rev1.zip" install_patch "AR73068" "$patch_bucket" "$patch_object" + + if [[ "$fix_patch" == true ]]; then + info_msg "Fixing Patch AR73068 for Vitis" + fix_patch_vitis_AR73068_2019_2 "$patch_object" + fi } function patch_AR73068_2019_1 { @@ -258,9 +273,17 @@ function patch_AR73068_2017_4 { function patch_AR73068 { local base_vivado_version=$(get_base_vivado_version) + local caller_script="$1" + local fix_patch=false + + # Vitis specific changes + if [[ "$caller_script" =~ "vitis_setup.sh" ]]; then + info_msg "Patching Vitis with AR73068" + fix_patch=true + fi if [[ "${base_vivado_version}" =~ "Vivado v2019.2" ]]; then - patch_AR73068_2019_2 + patch_AR73068_2019_2 "$fix_patch" elif [[ "${base_vivado_version}" =~ "Vivado v2019.1" ]]; then patch_AR73068_2019_1 elif [[ "${base_vivado_version}" =~ "Vivado v2018.3" ]]; then diff --git a/vitis_setup.sh b/vitis_setup.sh index 61948b83..9d79d3ac 100644 --- a/vitis_setup.sh +++ b/vitis_setup.sh @@ -165,8 +165,8 @@ fi info_msg " XILINX_VITIS is set to $XILINX_VITIS" # Install patches as required. -#info_msg " Checking & installing required patches" -#setup_patches +info_msg " Checking & installing required patches" +setup_patches # Update Xilinx Vitis Examples from GitHub From bc6ff26cc094552f2e30074cc24bad1b303bbaac Mon Sep 17 00:00:00 2001 From: Joost Hoozemans Date: Tue, 29 Dec 2020 16:57:19 +0100 Subject: [PATCH 28/31] Fixed failing cl_hello_world_vhdl example (#510) Co-authored-by: Joost Hoozemans --- .../software/verif_rtl/src/test_hello_world.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hdk/cl/examples/cl_hello_world_vhdl/software/verif_rtl/src/test_hello_world.c b/hdk/cl/examples/cl_hello_world_vhdl/software/verif_rtl/src/test_hello_world.c index 3969f969..d612bc8f 100644 --- a/hdk/cl/examples/cl_hello_world_vhdl/software/verif_rtl/src/test_hello_world.c +++ b/hdk/cl/examples/cl_hello_world_vhdl/software/verif_rtl/src/test_hello_world.c @@ -26,7 +26,7 @@ #include "sh_dpi_tasks.h" -#define HELLO_WORLD_REG_ADDR UINT64_C(0x00) +#define HELLO_WORLD_REG_ADDR UINT64_C(0x500) void test_main(uint32_t *exit_code) { From e7a5ff1616e3e10da109b94f77e10b288b175991 Mon Sep 17 00:00:00 2001 From: Joost Hoozemans Date: Sun, 10 Jan 2021 22:22:10 +0100 Subject: [PATCH 29/31] Add peek and poke for the 3 other AXI-Lite interfaces (#511) * Added peek and poke for the BAR1 interface * Added peek and poke for the SDA and PCIS AXI slave interfaces. Now all the 4 slave interface have a specific set of peek/poke functions callable from C. The new cl_peek_ocl and cl_poke_ocl are actually the same as the original cl_peek/cl_poke, which are still needed because they are used internally to configure the DDR controllers and test circuits. Co-authored-by: Joost Hoozemans --- hdk/common/verif/include/sh_dpi_tasks.svh | 40 ++++++++++++++++++++++ sdk/userspace/include/utils/sh_dpi_tasks.h | 8 +++++ 2 files changed, 48 insertions(+) diff --git a/hdk/common/verif/include/sh_dpi_tasks.svh b/hdk/common/verif/include/sh_dpi_tasks.svh index 15996beb..b8010265 100755 --- a/hdk/common/verif/include/sh_dpi_tasks.svh +++ b/hdk/common/verif/include/sh_dpi_tasks.svh @@ -36,6 +36,14 @@ import tb_type_defines_pkg::*; export "DPI-C" task sv_map_host_memory; export "DPI-C" task cl_peek; export "DPI-C" task cl_poke; + export "DPI-C" task cl_peek_pcis; + export "DPI-C" task cl_poke_pcis; + export "DPI-C" task cl_peek_sda; + export "DPI-C" task cl_poke_sda; + export "DPI-C" task cl_peek_ocl; + export "DPI-C" task cl_poke_ocl; + export "DPI-C" task cl_peek_bar1; + export "DPI-C" task cl_poke_bar1; export "DPI-C" task sv_int_ack; export "DPI-C" task sv_pause; export "DPI-C" task sv_fpga_pci_peek; @@ -65,6 +73,38 @@ import tb_type_defines_pkg::*; task cl_poke(input longint unsigned addr, int unsigned data); tb.card.fpga.sh.poke(.addr(addr), .data(data), .intf(AxiPort::PORT_OCL)); endtask + + task cl_peek_pcis(input longint unsigned addr, output int unsigned data); + tb.card.fpga.sh.peek(.addr(addr), .data(data), .intf(AxiPort::PORT_DMA_PCIS)); + endtask + + task cl_poke_pcis(input longint unsigned addr, int unsigned data); + tb.card.fpga.sh.poke(.addr(addr), .data(data), .intf(AxiPort::PORT_DMA_PCIS)); + endtask + + task cl_peek_sda(input longint unsigned addr, output int unsigned data); + tb.card.fpga.sh.peek(.addr(addr), .data(data), .intf(AxiPort::PORT_SDA)); + endtask + + task cl_poke_sda(input longint unsigned addr, int unsigned data); + tb.card.fpga.sh.poke(.addr(addr), .data(data), .intf(AxiPort::PORT_SDA)); + endtask + + task cl_peek_ocl(input longint unsigned addr, output int unsigned data); + tb.card.fpga.sh.peek(.addr(addr), .data(data), .intf(AxiPort::PORT_OCL)); + endtask + + task cl_poke_ocl(input longint unsigned addr, int unsigned data); + tb.card.fpga.sh.poke(.addr(addr), .data(data), .intf(AxiPort::PORT_OCL)); + endtask + + task cl_peek_bar1(input longint unsigned addr, output int unsigned data); + tb.card.fpga.sh.peek(.addr(addr), .data(data), .intf(AxiPort::PORT_BAR1)); + endtask + + task cl_poke_bar1(input longint unsigned addr, int unsigned data); + tb.card.fpga.sh.poke(.addr(addr), .data(data), .intf(AxiPort::PORT_BAR1)); + endtask task sv_int_ack(input int unsigned int_num); tb.card.fpga.sh.set_ack_bit(int_num); diff --git a/sdk/userspace/include/utils/sh_dpi_tasks.h b/sdk/userspace/include/utils/sh_dpi_tasks.h index 236ff0dd..0d0430bc 100644 --- a/sdk/userspace/include/utils/sh_dpi_tasks.h +++ b/sdk/userspace/include/utils/sh_dpi_tasks.h @@ -33,6 +33,14 @@ extern void sv_map_host_memory(uint8_t *memory); extern void cl_peek(uint64_t addr, uint32_t *data); extern void cl_poke(uint64_t addr, uint32_t data); +extern void cl_peek_pcis(uint64_t addr, uint32_t *data); +extern void cl_poke_pcis(uint64_t addr, uint32_t data); +extern void cl_peek_sda(uint64_t addr, uint32_t *data); +extern void cl_poke_sda(uint64_t addr, uint32_t data); +extern void cl_peek_ocl(uint64_t addr, uint32_t *data); +extern void cl_poke_ocl(uint64_t addr, uint32_t data); +extern void cl_peek_bar1(uint64_t addr, uint32_t *data); +extern void cl_poke_bar1(uint64_t addr, uint32_t data); extern void sv_int_ack(uint32_t int_num); extern void sv_pause(uint32_t x); extern void sv_fpga_start_buffer_to_cl(uint32_t slot_id, uint32_t chan, uint32_t buf_size, uint64_t wr_buffer_addr, uint64_t cl_addr); From aeda3939c53e37951082d69313406764743522f8 Mon Sep 17 00:00:00 2001 From: Deep Patel Date: Mon, 11 Jan 2021 14:02:49 -0600 Subject: [PATCH 30/31] * Added AL2 XRT updates (#512) * Updated XRT installation instructions * Added AL2 Kernel --- README.md | 2 +- Vitis/docs/XRT_installation_instructions.md | 38 ++++++++++++++++----- Vitis/kernel_version.txt | 1 + runtime_setup.sh | 15 ++++++++ 4 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 runtime_setup.sh diff --git a/README.md b/README.md index 8dbd1764..08044245 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ # Overview of AWS EC2 FPGA Development Kit AWS EC2 FPGA Development Kit is a set of development and runtime tools to develop, simulate, debug, compile and run hardware accelerated applications on [Amazon EC2 F1 instances](https://aws.amazon.com/ec2/instance-types/f1/). -It is distributed between this github repository and [FPGA Developer AMI](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ) provided by AWS with no cost of development tools. +It is distributed between this github repository and FPGA Developer AMI - [Centos](https://aws.amazon.com/marketplace/pp/B06VVYBLZZ)/[AL2](https://aws.amazon.com/marketplace/pp/B08NTMMZ7X) provided by AWS with no cost of development tools. ⚠️ NOTE: The developer kit is supported for Linux operating systems only. diff --git a/Vitis/docs/XRT_installation_instructions.md b/Vitis/docs/XRT_installation_instructions.md index 8ea0cc78..85c30bb6 100644 --- a/Vitis/docs/XRT_installation_instructions.md +++ b/Vitis/docs/XRT_installation_instructions.md @@ -1,13 +1,13 @@ # Xilinx Runtime (XRT) and Vitis Tool versions * Xilinx Runtime versions match with the tool that you created your Vitis AFI with. -* We provide pre-built RPM's for Centos/RHEL and instructions for building XRT +* We provide pre-built RPM's for Centos/RHEL/AL2 and instructions for building XRT * Use the below table as reference to install and use the correct XRT version for your applications. -| Xilinx Vitis Tool Version | XRT Release Tag | SHA | `xrt` and `xrt-aws` pre-built RPM's (Centos/RHEL) | +| Xilinx Vitis Tool Version | XRT Release Tag | SHA | `xrt`|`xrt-aws` RPM's (Centos/RHEL) |`xrt`|`xrt-aws` RPM's (AL2) |---|---|---|---| -|2020.1| [202010.2.6.AWS](https://github.com/Xilinx/XRT/releases/tag/202010.2.6.AWS) | d09c4a458c16e8d843b3165dcf929c38f7a32b6f | [xrt_202010.2.6.0_7.7.1908-x86_64-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.9.0/Patches/XRT_2020_1/xrt_202010.2.6.0_7.7.1908-x86_64-xrt.rpm) [xrt_202010.2.6.0_7.7.1908-x86_64-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.9.0/Patches/XRT_2020_1/xrt_202010.2.6.0_7.7.1908-x86_64-aws.rpm) | -|2019.2| [2019.2.0.3](https://github.com/Xilinx/XRT/releases/tag/2019.2.0.3) | 9e13d57c4563e2c19bf5f518993f6e5a8dadc18a | [xrt_201920.2.3.0_7.7.1908-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/XRT_2019_2/xrt_201920.2.3.0_7.7.1908-xrt.rpm) [xrt_201920.2.3.0_7.7.1908-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/XRT_2019_2/xrt_201920.2.3.0_7.7.1908-aws.rpm) | +|2020.1| [202010.2.6.AWS](https://github.com/Xilinx/XRT/releases/tag/202010.2.6.AWS) | d09c4a458c16e8d843b3165dcf929c38f7a32b6f | [xrt_202010.2.6.0_7.7.1908-x86_64-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.9.0/Patches/XRT_2020_1/xrt_202010.2.6.0_7.7.1908-x86_64-xrt.rpm) [xrt_202010.2.6.0_7.7.1908-x86_64-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.9.0/Patches/XRT_2020_1/xrt_202010.2.6.0_7.7.1908-x86_64-aws.rpm) | [xrt_202010.2.6.0_2-x86_64-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.9.0/Patches/XRT_2020_1/xrt_202010.2.6.0_2-x86_64-xrt.rpm) [xrt_202010.2.6.0_2-x86_64-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.9.0/Patches/XRT_2020_1/xrt_202010.2.6.0_2-x86_64-aws.rpm)| +|2019.2| [2019.2.0.3](https://github.com/Xilinx/XRT/releases/tag/2019.2.0.3) | 9e13d57c4563e2c19bf5f518993f6e5a8dadc18a | [xrt_201920.2.3.0_7.7.1908-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/XRT_2019_2/xrt_201920.2.3.0_7.7.1908-xrt.rpm) [xrt_201920.2.3.0_7.7.1908-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/XRT_2019_2/xrt_201920.2.3.0_7.7.1908-aws.rpm) | N/A | # MPD @@ -62,13 +62,35 @@ cd Release sudo yum reinstall xrt_*.rpm -y ``` -# Centos/RHEL pre-built RPM install steps +# AL2 build and install steps + +```bash +XRT_RELEASE_TAG=202010.2.6.AWS # Substitute XRT_RELEASE_TAG= + +git clone https://github.com/aws/aws-fpga.git + +cd aws-fpga +source vitis_setup.sh +cd $VITIS_DIR/Runtime +export XRT_PATH="${VITIS_DIR}/Runtime/${XRT_RELEASE_TAG}" +git clone http://www.github.com/Xilinx/XRT.git -b ${XRT_RELEASE_TAG} ${XRT_PATH} + +cd ${XRT_PATH} +sudo ./src/runtime_src/tools/scripts/xrtdeps.sh + +cd build +./build.sh + +cd Release +sudo yum reinstall xrt_*.rpm -y +``` + +# Centos/RHEL/AL2 pre-built RPM install steps -### 2019.2 ```bash -curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/XRT_2019_2/xrt_201920.2.3.0_7.7.1908-xrt.rpm -o xrt.rpm -curl -s https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/XRT_2019_2/xrt_201920.2.3.0_7.7.1908-aws.rpm -o xrt-aws.rpm +curl -s -o xrt.rpm +curl -s -o xrt-aws.rpm sudo yum reinstall xrt*.rpm -y ``` diff --git a/Vitis/kernel_version.txt b/Vitis/kernel_version.txt index eb0a1e6f..18fe1c12 100644 --- a/Vitis/kernel_version.txt +++ b/Vitis/kernel_version.txt @@ -6,3 +6,4 @@ 3.10.0-1062.4.1.el7.x86_64 3.10.0-1062.9.1.el7.x86_64 3.10.0-1127.10.1.el7.x86_64 +4.14.209-160.339.amzn2.x86_64 diff --git a/runtime_setup.sh b/runtime_setup.sh new file mode 100644 index 00000000..3c4de586 --- /dev/null +++ b/runtime_setup.sh @@ -0,0 +1,15 @@ +# Amazon FPGA Hardware Development Kit +# +# Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Amazon Software License (the "License"). You may not use +# this file except in compliance with the License. A copy of the License is +# located at +# +# http://aws.amazon.com/asl/ +# +# or in the "license" file accompanying this file. This file is distributed on +# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or +# implied. See the License for the specific language governing permissions and +# limitations under the License. + From 4750aacb4dac9d464b099b27e4337220cf0b0713 Mon Sep 17 00:00:00 2001 From: Deep Patel Date: Thu, 18 Mar 2021 16:59:44 -0500 Subject: [PATCH 31/31] Release v1.4.18 (#514) * Fixed the broken links pointing to the AXI interface specifications * Enable Xilinx 2020.2 tools * Updated FAQ on how to request an AFI limit increase --- .gitmodules | 3 +++ FAQs.md | 10 ++++++++- Jenkinsfile | 21 +++++++++++++++--- Jenkinsfile_int_sims | 10 +++++++-- README.md | 1 + RELEASE_NOTES.md | 3 +++ Vitis/docs/Create_Runtime_AMI.md | 5 +++-- Vitis/docs/XRT_installation_instructions.md | 5 +++-- Vitis/examples/xilinx_2020.2 | 1 + Vitis/tools/create_vitis_afi.sh | 8 ++++++- Vitis/vitis_xrt_version.txt | 2 +- docs/on_premise_licensing_help.md | 7 +++++- hdk/README.md | 2 ++ .../build/scripts/create_dcp_from_cl.tcl | 15 +++++++------ .../build/scripts/create_dcp_from_cl.tcl | 4 ++++ .../build/scripts/create_dcp_from_cl.tcl | 15 +++++++------ .../build/scripts/synth_cl_hello_world.tcl | 2 +- .../build/scripts/create_dcp_from_cl.tcl | 4 ++++ .../build/scripts/create_dcp_from_cl.tcl | 4 ++++ .../build/scripts/create_dcp_from_cl.tcl | 16 +++++++------ .../build/scripts/create_dcp_from_cl.tcl | 4 ++++ .../build/scripts/create_dcp_from_cl.tcl | 4 ++++ .../build/scripts/create_dcp_from_cl.tcl | 15 +++++++------ .../build/scripts/create_dcp_from_cl.tcl | 15 +++++++------ .../build/scripts/create_dcp_from_cl.tcl | 4 ++++ .../shell_v04261818/build/scripts/params.tcl | 3 +++ hdk/common/shell_v04261818/hlx/hlx_setup.tcl | 4 +++- hdk/docs/AFI_Manifest.md | 1 + hdk/docs/AWS_Shell_Interface_Specification.md | 4 ++-- hdk/docs/RTL_Simulating_CL_Designs.md | 12 +++++----- hdk/docs/images/AWS_Shell_CL_overview.jpg | Bin 125598 -> 105246 bytes hdk/hdk_version.txt | 2 +- hdk/tests/simulation_tests/run_sim.sh | 5 ++++- hdk/tests/simulation_tests/test_sims.py | 8 +++---- hdk/tests/test_gen_dcp.py | 12 ++++++---- sdk/linux_kernel_drivers/xdma/xdma_install.md | 8 +++---- supported_vivado_versions.txt | 1 + vitis_runtime_setup.sh | 4 ++-- vitis_setup.sh | 4 ++-- 39 files changed, 172 insertions(+), 76 deletions(-) create mode 160000 Vitis/examples/xilinx_2020.2 mode change 100755 => 100644 hdk/docs/images/AWS_Shell_CL_overview.jpg diff --git a/.gitmodules b/.gitmodules index 7133941d..3cad5231 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,3 +8,6 @@ [submodule "Vitis/examples/xilinx_2020.1"] path = Vitis/examples/xilinx_2020.1 url = https://github.com/Xilinx/Vitis_Accel_Examples +[submodule "Vitis/examples/xilinx_2020.2"] + path = Vitis/examples/xilinx_2020.2 + url = https://github.com/Xilinx/Vitis_Accel_Examples diff --git a/FAQs.md b/FAQs.md index 493a49a5..52e5ce16 100644 --- a/FAQs.md +++ b/FAQs.md @@ -103,7 +103,15 @@ Every FPGA deployed in AWS cloud includes an AWS Shell, and the developer Custom It is the compiled FPGA code that is loaded into an FPGA in AWS for performing the Custom Logic (CL) function created by the developer. AFIs are maintained by AWS according and associated with the AWS account that created them. The AFI includes the CL and AWS FPGA Shell. An AFI ID is used to reference a particular AFI from an F1 instance. -The developer can create multiple AFIs at no extra cost, up to a defined limited (typically 100 AFIs per region per AWS account). An AFI can be loaded into as many FPGAs as needed. +The developer can create multiple AFIs at no extra cost, up to a defined limited (typically 500 AFIs per region per AWS account). An AFI can be loaded into as many FPGAs as needed. + +**Q: How do I increase my AFI limit?** + +You can increase your AFI limit by creating an [AWS Support Case](https://console.aws.amazon.com/support/home#/case/create). +1. Select the `Service Limit Increase` tab +2. In the `Limit Type`, select `EC2 FPGA` +3. Select the region(s) where you want your limit to be increased +4. Add justification for the limit increase. **Q: What regions are supported?** diff --git a/Jenkinsfile b/Jenkinsfile index b1a1fd95..4f980364 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -126,9 +126,9 @@ task_label = [ ] // Put the latest version last -def xilinx_versions = [ '2019.1', '2019.2', '2020.1' ] +def xilinx_versions = [ '2019.1', '2019.2', '2020.1' , '2020.2' ] -def vitis_versions = ['2019.2', '2020.1'] +def vitis_versions = ['2019.2', '2020.1' , '2020.2' ] // We want the default to be the latest. def default_xilinx_version = xilinx_versions.last() @@ -139,7 +139,8 @@ def dsa_map = [ def xsa_map = [ '2019.2' : [ 'DYNAMIC':'dyn'], - '2020.1' : [ 'DYNAMIC':'dyn'] + '2020.1' : [ 'DYNAMIC':'dyn'], + '2020.2' : [ 'DYNAMIC':'dyn'] ] def sdaccel_example_default_map = [ @@ -165,6 +166,14 @@ def vitis_example_default_map = [ 'RTL_Vadd_Debug': 'Vitis/examples/xilinx/rtl_kernels/rtl_vadd_hw_debug', 'gemm_blas': 'Vitis/examples/xilinx/library_examples/gemm', 'gzip_app': 'Vitis/examples/xilinx/library_examples/gzip_app' + ], + '2020.2' : [ + 'Hello_World_1ddr': 'Vitis/examples/xilinx/ocl_kernels/cl_helloworld', + 'Gmem_2Banks_2ddr': 'Vitis/examples/xilinx/ocl_kernels/cl_gmem_2banks', + 'Kernel_Global_Bw_4ddr': 'Vitis/examples/xilinx/cpp_kernels/kernel_global_bandwidth', + 'RTL_Vadd_Debug': 'Vitis/examples/xilinx/rtl_kernels/rtl_vadd_hw_debug', + 'gemm_blas': 'Vitis/examples/xilinx/library_examples/gemm', + 'gzip_app': 'Vitis/examples/xilinx/library_examples/gzip_app' ] ] @@ -186,6 +195,12 @@ def simulator_tool_default_map = [ 'vcs': 'synopsys/vcs-mx/P-2019.06-SP1-1', 'questa': 'questa/2019.4', 'ies': 'incisive/15.20.079' + ], + '2020.2' : [ + 'vivado': 'xilinx/Vivado/2020.2', + 'vcs': 'synopsys/vcs-mx/Q-2020.03', + 'questa': 'questa/2020.2', + 'ies': 'incisive/15.20.083' ] ] diff --git a/Jenkinsfile_int_sims b/Jenkinsfile_int_sims index 7c8349c2..51a2d46f 100644 --- a/Jenkinsfile_int_sims +++ b/Jenkinsfile_int_sims @@ -36,7 +36,7 @@ task_label = [ ] // Put the latest version last -def xilinx_versions = [ '2019.2' ] +def xilinx_versions = [ '2020.2' ] // We want the default to be the latest. def default_xilinx_version = xilinx_versions.last() @@ -53,6 +53,12 @@ def simulator_tool_default_map = [ 'vcs': 'synopsys/vcs-mx/P-2019.06-SP1-1', 'questa': 'questa/2019.4', 'ies': 'incisive/15.20.079' + ], + '2020.2' : [ + 'vivado': 'xilinx/Vivado/2020.2', + 'vcs': 'synopsys/vcs/Q-2020.03', + 'questa': 'questa/2019.4_3', + 'ies': 'incisive/15.20.083' ] ] @@ -177,7 +183,7 @@ if (test_sims) { module purge module load python/3.7.2 module load python/2.7.14 - module load batch + module load slurm module load ${vivado_module} module load ${vcs_module} module load ${questa_module} diff --git a/README.md b/README.md index 08044245..3d851c6d 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ AWS marketplace offers multiple versions of the FPGA Developer AMI. The followin | Developer Kit Version | Tool Version Supported | Compatible FPGA Developer AMI Version | |-----------|-----------|------| +| 1.4.18+ | 2020.2 | v1.10.X (Xilinx Vivado/Vitis 2020.2) | | 1.4.16+ | 2020.1 | v1.9.0-v1.9.X (Xilinx Vivado/Vitis 2020.1) | | 1.4.13+ | 2019.2 | v1.8.0-v1.8.X (Xilinx Vivado/Vitis 2019.2) | | 1.4.11+ | 2019.1 | v1.7.0-v1.7.X (Xilinx Vivado/SDx 2019.1) | diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 3b9b8ead..38d40175 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,8 @@ # AWS EC2 FPGA HDK+SDK Release Notes +## Release 1.4.18 (See [ERRATA](./ERRATA.md) for unsupported features) +* FPGA developer kit now supports Xilinx Vivado/Vitis 2020.2 + ## Release 1.4.17 (See [ERRATA](./ERRATA.md) for unsupported features) * Updated XDMA Driver to allow builds on newer kernels * Updated documentation on Alveo U200 to F1 platform porting diff --git a/Vitis/docs/Create_Runtime_AMI.md b/Vitis/docs/Create_Runtime_AMI.md index 087a4ba4..8cc3bc62 100644 --- a/Vitis/docs/Create_Runtime_AMI.md +++ b/Vitis/docs/Create_Runtime_AMI.md @@ -4,8 +4,9 @@ | Vitis Version used for AFI Development | Compatible Xilinx Runtime | |--------------------------------------|-----------------------------| -| 2020.1 | AWS FPGA Developer AMI 1.9.0 (XRT is pre-installed) or [XRT](https://xilinx.github.io/XRT/2020.1/html/build.html) | -| 2019.2 | AWS FPGA Developer AMI 1.8.0 (XRT is pre-installed) or [XRT](https://xilinx.github.io/XRT/2019.2/html/build.html) | +| 2020.2 | AWS FPGA Developer AMI 1.10.x (XRT is pre-installed) or [XRT](https://xilinx.github.io/XRT/2020.2/html/build.html) | +| 2020.1 | AWS FPGA Developer AMI 1.9.x (XRT is pre-installed) or [XRT](https://xilinx.github.io/XRT/2020.1/html/build.html) | +| 2019.2 | AWS FPGA Developer AMI 1.8.x (XRT is pre-installed) or [XRT](https://xilinx.github.io/XRT/2019.2/html/build.html) | ## 1. Launch a Runtime Instance & Install Required Packages diff --git a/Vitis/docs/XRT_installation_instructions.md b/Vitis/docs/XRT_installation_instructions.md index 85c30bb6..8a1afb9b 100644 --- a/Vitis/docs/XRT_installation_instructions.md +++ b/Vitis/docs/XRT_installation_instructions.md @@ -4,8 +4,9 @@ * We provide pre-built RPM's for Centos/RHEL/AL2 and instructions for building XRT * Use the below table as reference to install and use the correct XRT version for your applications. -| Xilinx Vitis Tool Version | XRT Release Tag | SHA | `xrt`|`xrt-aws` RPM's (Centos/RHEL) |`xrt`|`xrt-aws` RPM's (AL2) -|---|---|---|---| +| Xilinx Vitis Tool Version | XRT Release Tag | SHA | `xrt` or `xrt-aws` RPM's (Centos/RHEL) |`xrt` or`xrt-aws` RPM's (AL2) | +|---|---|---|---|---| +|2020.2| [202020.2.8.743](https://github.com/Xilinx/XRT/releases/tag/202020.2.8.743) | 77d5484b5c4daa691a7f78235053fb036829b1e9 | [xrt_202020.2.8.0_7.9.2009-x86_64-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.10.0/Patches/XRT_2020_2/xrt_202020.2.8.0_7.9.2009-x86_64-xrt.rpm) [xrt_202020.2.8.0_7.9.2009-x86_64-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.10.0/Patches/XRT_2020_2/xrt_202020.2.8.0_7.9.2009-x86_64-aws.rpm) | [xrt_202020.2.8.0_2-x86_64-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.10.0/Patches/XRT_2020_2/xrt_202020.2.8.0_2-x86_64-xrt.rpm) [xrt_202020.2.8.0_2-x86_64-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.10.0/Patches/XRT_2020_2/xrt_202020.2.8.0_2-x86_64-aws.rpm)| |2020.1| [202010.2.6.AWS](https://github.com/Xilinx/XRT/releases/tag/202010.2.6.AWS) | d09c4a458c16e8d843b3165dcf929c38f7a32b6f | [xrt_202010.2.6.0_7.7.1908-x86_64-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.9.0/Patches/XRT_2020_1/xrt_202010.2.6.0_7.7.1908-x86_64-xrt.rpm) [xrt_202010.2.6.0_7.7.1908-x86_64-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.9.0/Patches/XRT_2020_1/xrt_202010.2.6.0_7.7.1908-x86_64-aws.rpm) | [xrt_202010.2.6.0_2-x86_64-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.9.0/Patches/XRT_2020_1/xrt_202010.2.6.0_2-x86_64-xrt.rpm) [xrt_202010.2.6.0_2-x86_64-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.9.0/Patches/XRT_2020_1/xrt_202010.2.6.0_2-x86_64-aws.rpm)| |2019.2| [2019.2.0.3](https://github.com/Xilinx/XRT/releases/tag/2019.2.0.3) | 9e13d57c4563e2c19bf5f518993f6e5a8dadc18a | [xrt_201920.2.3.0_7.7.1908-xrt.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/XRT_2019_2/xrt_201920.2.3.0_7.7.1908-xrt.rpm) [xrt_201920.2.3.0_7.7.1908-aws.rpm](https://aws-fpga-developer-ami.s3.amazonaws.com/1.8.0/Patches/XRT_2019_2/xrt_201920.2.3.0_7.7.1908-aws.rpm) | N/A | diff --git a/Vitis/examples/xilinx_2020.2 b/Vitis/examples/xilinx_2020.2 new file mode 160000 index 00000000..f72dff9e --- /dev/null +++ b/Vitis/examples/xilinx_2020.2 @@ -0,0 +1 @@ +Subproject commit f72dff9eea45a76e9ee0713774589624e2b52c9f diff --git a/Vitis/tools/create_vitis_afi.sh b/Vitis/tools/create_vitis_afi.sh index c7bd9b9a..5f19c848 100755 --- a/Vitis/tools/create_vitis_afi.sh +++ b/Vitis/tools/create_vitis_afi.sh @@ -279,4 +279,10 @@ echo ${timestamp}_agfi_id.txt #STEP 6 #Create .awsxclbin -/opt/xilinx/xrt/bin/xclbinutil -i $xclbin --remove-section PARTITION_METADATA --remove-section SYSTEM_METADATA --replace-section BITSTREAM:RAW:${timestamp}_agfi_id.txt -o ${awsxclbin}.awsxclbin + +if [ "$RELEASE_VER" == "2020.2" ] +then + /opt/xilinx/xrt/bin/xclbinutil -i $xclbin --remove-section PARTITION_METADATA --replace-section BITSTREAM:RAW:${timestamp}_agfi_id.txt -o ${awsxclbin}.awsxclbin +else + /opt/xilinx/xrt/bin/xclbinutil -i $xclbin --remove-section PARTITION_METADATA --remove-section SYSTEM_METADATA --replace-section BITSTREAM:RAW:${timestamp}_agfi_id.txt -o ${awsxclbin}.awsxclbin +fi diff --git a/Vitis/vitis_xrt_version.txt b/Vitis/vitis_xrt_version.txt index 3c06762f..df3ef470 100644 --- a/Vitis/vitis_xrt_version.txt +++ b/Vitis/vitis_xrt_version.txt @@ -1,4 +1,4 @@ 2019.2:9e13d57c4563e2c19bf5f518993f6e5a8dadc18a 2020.1:12115fd4054cb46a5ade62fafa74c523f59116e6 2020.1:d09c4a458c16e8d843b3165dcf929c38f7a32b6f - +2020.2:77d5484b5c4daa691a7f78235053fb036829b1e9 diff --git a/docs/on_premise_licensing_help.md b/docs/on_premise_licensing_help.md index d58903e6..8b8f2af6 100644 --- a/docs/on_premise_licensing_help.md +++ b/docs/on_premise_licensing_help.md @@ -3,6 +3,11 @@ **NOTE: If you are developing on the AWS cloud and using AWS FPGA Developer AMI provided on AWS Marketplace, you can skip this document.** This document helps developers who choose to develop on-premises with specifying and licensing AWS-compatible Xilinx tools for use with the AWS FPGA HDK. +## Requirements for AWS HDK 1.4.18+ (2020.2) + * Xilinx Vivado or Vitis v2020.2 + * License: EF-VIVADO-SDX-VU9P-OP + * URL: https://www.xilinx.com/member/forms/download/xef.html?filename=Xilinx_Unified_2020.2_1118_1232.tar.gz + * MD5 SUM Value: 523e8596f114ab5e389c14df50ecb1d8 ## Requirements for AWS HDK 1.4.16+ (2020.1) * Xilinx Vivado or Vitis v2020.1 @@ -10,7 +15,7 @@ This document helps developers who choose to develop on-premises with specifying * URL: https://www.xilinx.com/member/forms/download/xef.html?filename=Xilinx_Unified_2020.1_0602_1208.tar.gz * MD5 SUM Value: b018f7b331ab0446137756156ff944d9 - ## Requirements for AWS HDK 1.4.13+ (2019.2) +## Requirements for AWS HDK 1.4.13+ (2019.2) * Xilinx Vivado or Vitis v2019.2 * License: EF-VIVADO-SDX-VU9P-OP * URL: https://www.xilinx.com/member/forms/download/xef-vitis.html?filename=Xilinx_Vitis_2019.2_1106_2127.tar.gz diff --git a/hdk/README.md b/hdk/README.md index f3b74fa9..6e3e3954 100644 --- a/hdk/README.md +++ b/hdk/README.md @@ -66,6 +66,8 @@ For more details on the examples, see the [examples table](./cl/examples/cl_exam | 1.4.11-1.4.x | 2019.1 | v1.7.0 (Xilinx Vivado 2019.1) | | 1.4.11-1.4.x | 2019.2 | v1.8.x (Xilinx Vivado 2019.2) | | 1.4.16-1.4.x | 2020.1 | v1.9.x (Xilinx Vivado 2020.1) | +| 1.4.18-1.4.x | 2020.2 | v1.10.x (Xilinx Vivado 2020.2) | + * The FPGA Developer Kit version is listed in [hdk_version.txt](./hdk_version.txt) diff --git a/hdk/cl/examples/cl_dram_dma/build/scripts/create_dcp_from_cl.tcl b/hdk/cl/examples/cl_dram_dma/build/scripts/create_dcp_from_cl.tcl index f044ed7b..fdae02f6 100644 --- a/hdk/cl/examples/cl_dram_dma/build/scripts/create_dcp_from_cl.tcl +++ b/hdk/cl/examples/cl_dram_dma/build/scripts/create_dcp_from_cl.tcl @@ -19,7 +19,7 @@ package require tar set TOP top_sp ## Replace with the name of your module -set CL_MODULE cl_dram_dma +set CL_MODULE cl_dram_dma ################################################# ## Command-line Arguments @@ -39,7 +39,7 @@ set uram_option [lindex $argv 11] set notify_via_sns [lindex $argv 12] set VDEFINES [lindex $argv 13] ################################################## -## Flow control variables +## Flow control variables ################################################## set cl.synth 1 set implement 1 @@ -147,6 +147,9 @@ set_msg_config -id {DRC CKLD-2} -suppress set_msg_config -id {DRC REQP-1853} -suppress set_msg_config -id {Timing 38-436} -suppress +set_msg_config -severity "CRITICAL WARNING" -string "WRAPPER_INST/SH" -suppress +set_msg_config -severity "WARNING" -string "WRAPPER_INST/SH" -suppress + # Check that an email address has been set, else unset notify_via_sns if {[string compare $notify_via_sns "1"] == 0} { @@ -159,7 +162,7 @@ if {[string compare $notify_via_sns "1"] == 0} { } ################################################## -### Strategy options +### Strategy options ################################################## switch $strategy { "BASIC" { @@ -200,7 +203,7 @@ source $HDK_SHELL_DIR/build/scripts/device_type.tcl source $HDK_SHELL_DIR/build/scripts/step_user.tcl -notrace ######################################## -## Generate clocks based on Recipe +## Generate clocks based on Recipe ######################################## puts "AWS FPGA: ([clock format [clock seconds] -format %T]) Calling aws_gen_clk_constraints.tcl to generate clock constraints from developer's specified recipe."; @@ -254,7 +257,7 @@ if {$implement} { # Apply Clock Properties for Clock Table Recipes ################################################## puts "AWS FPGA: ([clock format [clock seconds] -format %T]) - Sourcing aws_clock_properties.tcl to apply properties to clocks. "; - + # Apply properties to clocks source $HDK_SHELL_DIR/build/scripts/aws_clock_properties.tcl @@ -385,5 +388,3 @@ if {[string compare $notify_via_sns "1"] == 0} { } puts "AWS FPGA: ([clock format [clock seconds] -format %T]) - Build complete."; - - diff --git a/hdk/cl/examples/cl_dram_dma_hlx/build/scripts/create_dcp_from_cl.tcl b/hdk/cl/examples/cl_dram_dma_hlx/build/scripts/create_dcp_from_cl.tcl index 90553f00..63445b80 100755 --- a/hdk/cl/examples/cl_dram_dma_hlx/build/scripts/create_dcp_from_cl.tcl +++ b/hdk/cl/examples/cl_dram_dma_hlx/build/scripts/create_dcp_from_cl.tcl @@ -37,6 +37,10 @@ if {[string compare $notify_via_sns "1"] == 0} { } } +# suppress warnings coming from Shell +set_msg_config -severity "CRITICAL WARNING" -string "WRAPPER_INST/SH" -suppress +set_msg_config -severity "WARNING" -string "WRAPPER_INST/SH" -suppress + ################################################# ## Create BD (Block Design) of example Hello World design ################################################# diff --git a/hdk/cl/examples/cl_hello_world/build/scripts/create_dcp_from_cl.tcl b/hdk/cl/examples/cl_hello_world/build/scripts/create_dcp_from_cl.tcl index 8f7b975c..d36310e6 100644 --- a/hdk/cl/examples/cl_hello_world/build/scripts/create_dcp_from_cl.tcl +++ b/hdk/cl/examples/cl_hello_world/build/scripts/create_dcp_from_cl.tcl @@ -39,7 +39,7 @@ set uram_option [lindex $argv 11] set notify_via_sns [lindex $argv 12] set VDEFINES [lindex $argv 13] ################################################## -## Flow control variables +## Flow control variables ################################################## set cl.synth 1 set implement 1 @@ -134,6 +134,9 @@ set_msg_config -id {Synth 8-3848} -suppress set_msg_config -id {Synth 8-3917} -suppress set_msg_config -id {Opt 31-430} -suppress +set_msg_config -severity "CRITICAL WARNING" -string "WRAPPER_INST/SH" -suppress +set_msg_config -severity "WARNING" -string "WRAPPER_INST/SH" -suppress + puts "AWS FPGA: ([clock format [clock seconds] -format %T]) Calling the encrypt.tcl."; # Check that an email address has been set, else unset notify_via_sns @@ -148,7 +151,7 @@ if {[string compare $notify_via_sns "1"] == 0} { } ################################################## -### Strategy options +### Strategy options ################################################## switch $strategy { "BASIC" { @@ -187,14 +190,14 @@ source $HDK_SHELL_DIR/build/scripts/device_type.tcl source $HDK_SHELL_DIR/build/scripts/step_user.tcl -notrace ######################################## -## Generate clocks based on Recipe +## Generate clocks based on Recipe ######################################## puts "AWS FPGA: ([clock format [clock seconds] -format %T]) Calling aws_gen_clk_constraints.tcl to generate clock constraints from developer's specified recipe."; source $HDK_SHELL_DIR/build/scripts/aws_gen_clk_constraints.tcl ################################################################# -#### Do not remove this setting. Need to workaround bug +#### Do not remove this setting. Need to workaround bug ################################################################## set_param hd.clockRoutingWireReduction false ################################################## @@ -236,7 +239,7 @@ if {$implement} { # Apply Clock Properties for Clock Table Recipes ################################################## puts "AWS FPGA: ([clock format [clock seconds] -format %T]) - Sourcing aws_clock_properties.tcl to apply properties to clocks. "; - + # Apply properties to clocks source $HDK_SHELL_DIR/build/scripts/aws_clock_properties.tcl @@ -365,5 +368,3 @@ if {[string compare $notify_via_sns "1"] == 0} { } puts "AWS FPGA: ([clock format [clock seconds] -format %T]) - Build complete."; - - diff --git a/hdk/cl/examples/cl_hello_world/build/scripts/synth_cl_hello_world.tcl b/hdk/cl/examples/cl_hello_world/build/scripts/synth_cl_hello_world.tcl index f5819636..8d1d5c04 100644 --- a/hdk/cl/examples/cl_hello_world/build/scripts/synth_cl_hello_world.tcl +++ b/hdk/cl/examples/cl_hello_world/build/scripts/synth_cl_hello_world.tcl @@ -21,7 +21,7 @@ set VDEFINES $VDEFINES create_project -in_memory -part [DEVICE_TYPE] -force ######################################## -## Generate clocks based on Recipe +## Generate clocks based on Recipe ######################################## puts "AWS FPGA: ([clock format [clock seconds] -format %T]) Calling aws_gen_clk_constraints.tcl to generate clock constraints from developer's specified recipe."; diff --git a/hdk/cl/examples/cl_hello_world_hlx/build/scripts/create_dcp_from_cl.tcl b/hdk/cl/examples/cl_hello_world_hlx/build/scripts/create_dcp_from_cl.tcl index af16971c..06938eee 100755 --- a/hdk/cl/examples/cl_hello_world_hlx/build/scripts/create_dcp_from_cl.tcl +++ b/hdk/cl/examples/cl_hello_world_hlx/build/scripts/create_dcp_from_cl.tcl @@ -37,6 +37,10 @@ if {[string compare $notify_via_sns "1"] == 0} { } } +# suppress warnings coming from Shell +set_msg_config -severity "CRITICAL WARNING" -string "WRAPPER_INST/SH" -suppress +set_msg_config -severity "WARNING" -string "WRAPPER_INST/SH" -suppress + ################################################# ## Create BD (Block Design) of example Hello World design ################################################# diff --git a/hdk/cl/examples/cl_hello_world_ref_hlx/build/scripts/create_dcp_from_cl.tcl b/hdk/cl/examples/cl_hello_world_ref_hlx/build/scripts/create_dcp_from_cl.tcl index 385782dc..99ff2a68 100755 --- a/hdk/cl/examples/cl_hello_world_ref_hlx/build/scripts/create_dcp_from_cl.tcl +++ b/hdk/cl/examples/cl_hello_world_ref_hlx/build/scripts/create_dcp_from_cl.tcl @@ -29,6 +29,10 @@ if {[string compare $notify_via_sns "1"] == 0} { } } +# suppress warnings coming from Shell +set_msg_config -severity "CRITICAL WARNING" -string "WRAPPER_INST/SH" -suppress +set_msg_config -severity "WARNING" -string "WRAPPER_INST/SH" -suppress + ################################################# ## Create BD (Block Design) of example Hello World design ################################################# diff --git a/hdk/cl/examples/cl_hello_world_vhdl/build/scripts/create_dcp_from_cl.tcl b/hdk/cl/examples/cl_hello_world_vhdl/build/scripts/create_dcp_from_cl.tcl index ad7a216c..75a28a7b 100644 --- a/hdk/cl/examples/cl_hello_world_vhdl/build/scripts/create_dcp_from_cl.tcl +++ b/hdk/cl/examples/cl_hello_world_vhdl/build/scripts/create_dcp_from_cl.tcl @@ -39,7 +39,7 @@ set uram_option [lindex $argv 11] set notify_via_sns [lindex $argv 12] set VDEFINES [lindex $argv 13] ################################################## -## Flow control variables +## Flow control variables ################################################## set cl.synth 1 set implement 1 @@ -133,6 +133,10 @@ set_msg_config -id {Synth 8-350} -suppress set_msg_config -id {Synth 8-3848} -suppress set_msg_config -id {Synth 8-3917} -suppress +# suppress warnings coming from Shell +set_msg_config -severity "CRITICAL WARNING" -string "WRAPPER_INST/SH" -suppress +set_msg_config -severity "WARNING" -string "WRAPPER_INST/SH" -suppress + puts "AWS FPGA: ([clock format [clock seconds] -format %T]) Calling the encrypt.tcl."; # Check that an email address has been set, else unset notify_via_sns @@ -147,7 +151,7 @@ if {[string compare $notify_via_sns "1"] == 0} { } ################################################## -### Strategy options +### Strategy options ################################################## switch $strategy { "BASIC" { @@ -186,14 +190,14 @@ source $HDK_SHELL_DIR/build/scripts/device_type.tcl source $HDK_SHELL_DIR/build/scripts/step_user.tcl -notrace ######################################## -## Generate clocks based on Recipe +## Generate clocks based on Recipe ######################################## puts "AWS FPGA: ([clock format [clock seconds] -format %T]) Calling aws_gen_clk_constraints.tcl to generate clock constraints from developer's specified recipe."; source $HDK_SHELL_DIR/build/scripts/aws_gen_clk_constraints.tcl ################################################################# -#### Do not remove this setting. Need to workaround bug +#### Do not remove this setting. Need to workaround bug ################################################################# set_param hd.clockRoutingWireReduction false @@ -235,7 +239,7 @@ if {$implement} { # Apply Clock Properties for Clock Table Recipes ################################################## puts "AWS FPGA: ([clock format [clock seconds] -format %T]) - Sourcing aws_clock_properties.tcl to apply properties to clocks. "; - + # Apply properties to clocks source $HDK_SHELL_DIR/build/scripts/aws_clock_properties.tcl @@ -359,5 +363,3 @@ if {[string compare $notify_via_sns "1"] == 0} { } puts "AWS FPGA: ([clock format [clock seconds] -format %T]) - Build complete."; - - diff --git a/hdk/cl/examples/cl_hls_dds_hlx/build/scripts/create_dcp_from_cl.tcl b/hdk/cl/examples/cl_hls_dds_hlx/build/scripts/create_dcp_from_cl.tcl index 43d7d6d4..7e942750 100755 --- a/hdk/cl/examples/cl_hls_dds_hlx/build/scripts/create_dcp_from_cl.tcl +++ b/hdk/cl/examples/cl_hls_dds_hlx/build/scripts/create_dcp_from_cl.tcl @@ -29,6 +29,10 @@ if {[string compare $notify_via_sns "1"] == 0} { } } +# suppress warnings coming from Shell +set_msg_config -severity "CRITICAL WARNING" -string "WRAPPER_INST/SH" -suppress +set_msg_config -severity "WARNING" -string "WRAPPER_INST/SH" -suppress + ################################################# ## Create BD (Block Design) of example Hello World design ################################################# diff --git a/hdk/cl/examples/cl_ipi_cdma_test_hlx/build/scripts/create_dcp_from_cl.tcl b/hdk/cl/examples/cl_ipi_cdma_test_hlx/build/scripts/create_dcp_from_cl.tcl index e146e23c..911f471d 100755 --- a/hdk/cl/examples/cl_ipi_cdma_test_hlx/build/scripts/create_dcp_from_cl.tcl +++ b/hdk/cl/examples/cl_ipi_cdma_test_hlx/build/scripts/create_dcp_from_cl.tcl @@ -29,6 +29,10 @@ if {[string compare $notify_via_sns "1"] == 0} { } } +# suppress warnings coming from Shell +set_msg_config -severity "CRITICAL WARNING" -string "WRAPPER_INST/SH" -suppress +set_msg_config -severity "WARNING" -string "WRAPPER_INST/SH" -suppress + ################################################# ## Create BD (Block Design) of example Hello World design ################################################# diff --git a/hdk/cl/examples/cl_sde/build/scripts/create_dcp_from_cl.tcl b/hdk/cl/examples/cl_sde/build/scripts/create_dcp_from_cl.tcl index 1f16f71b..699332f1 100644 --- a/hdk/cl/examples/cl_sde/build/scripts/create_dcp_from_cl.tcl +++ b/hdk/cl/examples/cl_sde/build/scripts/create_dcp_from_cl.tcl @@ -19,7 +19,7 @@ package require tar set TOP top_sp ## Replace with the name of your module -set CL_MODULE cl_sde +set CL_MODULE cl_sde ################################################# ## Command-line Arguments @@ -39,7 +39,7 @@ set uram_option [lindex $argv 11] set notify_via_sns [lindex $argv 12] ################################################## -## Flow control variables +## Flow control variables ################################################## set cl.synth 1 set implement 1 @@ -142,6 +142,9 @@ set_msg_config -id {DRC CKLD-2} -suppress set_msg_config -id {DRC REQP-1853} -suppress set_msg_config -id {Timing 38-436} -suppress +set_msg_config -severity "CRITICAL WARNING" -string "WRAPPER_INST/SH" -suppress +set_msg_config -severity "WARNING" -string "WRAPPER_INST/SH" -suppress + puts "AWS FPGA: ([clock format [clock seconds] -format %T]) Calling the encrypt.tcl."; # Check that an email address has been set, else unset notify_via_sns @@ -156,7 +159,7 @@ if {[string compare $notify_via_sns "1"] == 0} { } ################################################## -### Strategy options +### Strategy options ################################################## switch $strategy { "BASIC" { @@ -195,7 +198,7 @@ source $HDK_SHELL_DIR/build/scripts/device_type.tcl source $HDK_SHELL_DIR/build/scripts/step_user.tcl -notrace ######################################## -## Generate clocks based on Recipe +## Generate clocks based on Recipe ######################################## puts "AWS FPGA: ([clock format [clock seconds] -format %T]) Calling aws_gen_clk_constraints.tcl to generate clock constraints from developer's specified recipe."; @@ -245,7 +248,7 @@ if {$implement} { # Apply Clock Properties for Clock Table Recipes ################################################## puts "AWS FPGA: ([clock format [clock seconds] -format %T]) - Sourcing aws_clock_properties.tcl to apply properties to clocks. "; - + # Apply properties to clocks source $HDK_SHELL_DIR/build/scripts/aws_clock_properties.tcl @@ -369,5 +372,3 @@ if {[string compare $notify_via_sns "1"] == 0} { } puts "AWS FPGA: ([clock format [clock seconds] -format %T]) - Build complete."; - - diff --git a/hdk/cl/examples/cl_uram_example/build/scripts/create_dcp_from_cl.tcl b/hdk/cl/examples/cl_uram_example/build/scripts/create_dcp_from_cl.tcl index 0b21940d..2c1a0888 100644 --- a/hdk/cl/examples/cl_uram_example/build/scripts/create_dcp_from_cl.tcl +++ b/hdk/cl/examples/cl_uram_example/build/scripts/create_dcp_from_cl.tcl @@ -39,7 +39,7 @@ set uram_option [lindex $argv 11] set notify_via_sns [lindex $argv 12] set VDEFINES [lindex $argv 13] ################################################## -## Flow control variables +## Flow control variables ################################################## set cl.synth 1 set implement 1 @@ -133,6 +133,9 @@ set_msg_config -id {Synth 8-350} -suppress set_msg_config -id {Synth 8-3848} -suppress set_msg_config -id {Synth 8-3917} -suppress +set_msg_config -severity "CRITICAL WARNING" -string "WRAPPER_INST/SH" -suppress +set_msg_config -severity "WARNING" -string "WRAPPER_INST/SH" -suppress + puts "AWS FPGA: ([clock format [clock seconds] -format %T]) Calling the encrypt.tcl."; # Check that an email address has been set, else unset notify_via_sns @@ -147,7 +150,7 @@ if {[string compare $notify_via_sns "1"] == 0} { } ################################################## -### Strategy options +### Strategy options ################################################## switch $strategy { "BASIC" { @@ -186,7 +189,7 @@ source $HDK_SHELL_DIR/build/scripts/device_type.tcl source $HDK_SHELL_DIR/build/scripts/step_user.tcl -notrace ######################################## -## Generate clocks based on Recipe +## Generate clocks based on Recipe ######################################## puts "AWS FPGA: ([clock format [clock seconds] -format %T]) Calling aws_gen_clk_constraints.tcl to generate clock constraints from developer's specified recipe."; @@ -235,7 +238,7 @@ if {$implement} { # Apply Clock Properties for Clock Table Recipes ################################################## puts "AWS FPGA: ([clock format [clock seconds] -format %T]) - Sourcing aws_clock_properties.tcl to apply properties to clocks. "; - + # Apply properties to clocks source $HDK_SHELL_DIR/build/scripts/aws_clock_properties.tcl @@ -300,7 +303,7 @@ if {$implement} { # This is what will deliver to AWS puts "AWS FPGA: ([clock format [clock seconds] -format %T]) - Writing final DCP to to_aws directory."; - + #writing unencrypted dcp for analysis to checkpoints dir. write_checkpoint -force $CL_DIR/build/checkpoints/${timestamp}.SH_CL_routed.dcp @@ -363,5 +366,3 @@ if {[string compare $notify_via_sns "1"] == 0} { } puts "AWS FPGA: ([clock format [clock seconds] -format %T]) - Build complete."; - - diff --git a/hdk/cl/examples/hello_world_hlx/build/scripts/create_dcp_from_cl.tcl b/hdk/cl/examples/hello_world_hlx/build/scripts/create_dcp_from_cl.tcl index 59246c89..5a5d24f5 100755 --- a/hdk/cl/examples/hello_world_hlx/build/scripts/create_dcp_from_cl.tcl +++ b/hdk/cl/examples/hello_world_hlx/build/scripts/create_dcp_from_cl.tcl @@ -29,6 +29,10 @@ if {[string compare $notify_via_sns "1"] == 0} { } } +# suppress warnings coming from Shell +set_msg_config -severity "CRITICAL WARNING" -string "WRAPPER_INST/SH" -suppress +set_msg_config -severity "WARNING" -string "WRAPPER_INST/SH" -suppress + ################################################# ## Create BD (Block Design) of example Hello World design ################################################# diff --git a/hdk/common/shell_v04261818/build/scripts/params.tcl b/hdk/common/shell_v04261818/build/scripts/params.tcl index 96103532..1ad16bb1 100755 --- a/hdk/common/shell_v04261818/build/scripts/params.tcl +++ b/hdk/common/shell_v04261818/build/scripts/params.tcl @@ -25,3 +25,6 @@ if {$uram_option != 2} { ####Enable support of clocking from one RP to another (SH-->CL) set_param hd.supportClockNetCrossDiffReconfigurablePartitions 1 +# Maintain DONT TOUCH functionality for 2020.2 onwards +if {[string match *2020.2* [version -short]]} {set_param project.replaceDontTouchWithKeepHierarchySoft false} + diff --git a/hdk/common/shell_v04261818/hlx/hlx_setup.tcl b/hdk/common/shell_v04261818/hlx/hlx_setup.tcl index 90fbb653..727dbaac 100644 --- a/hdk/common/shell_v04261818/hlx/hlx_setup.tcl +++ b/hdk/common/shell_v04261818/hlx/hlx_setup.tcl @@ -45,4 +45,6 @@ set aws::make_faas::public::bd_faas_examples_directory [file normalize [file joi set aws::make_faas::public::bd_faas_initscript [file join $aws::make_faas::public::bd_faas_build_directory scripts aws_bd_faas_initscript.tcl] set ::env(FAAS_HOOK_TCL) $::aws::make_faas::public::bd_faas_initscript - +# Maintain DONT TOUCH functionality for 2020.2 onwards +if {[string match *2020.2* [version -short]]} {set_param project.replaceDontTouchWithKeepHierarchySoft false} +# diff --git a/hdk/docs/AFI_Manifest.md b/hdk/docs/AFI_Manifest.md index b120f362..e6509387 100644 --- a/hdk/docs/AFI_Manifest.md +++ b/hdk/docs/AFI_Manifest.md @@ -40,6 +40,7 @@ The manifest file is a text file formatted with key=value pairs. Some keys are m | vivado tool version | field value | |------------------- | -----------| +| 2020.2 | tool_version=v2020.2 | | 2020.1 | tool_version=v2020.1 | | 2019.2 | tool_version=v2019.2 | | 2019.1 | tool_version=v2019.1 | diff --git a/hdk/docs/AWS_Shell_Interface_Specification.md b/hdk/docs/AWS_Shell_Interface_Specification.md index 8016dae2..2733f9db 100644 --- a/hdk/docs/AWS_Shell_Interface_Specification.md +++ b/hdk/docs/AWS_Shell_Interface_Specification.md @@ -99,9 +99,9 @@ Starting from 1.4, The shell is reconfigurable, allowing, in most cases, develop **DW –** Doubleword: referring to 4-byte (32-bit) data size. -[**AXI-4** ARM Advanced eXtensible Interface.](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.set.amba/index.html) +[**AXI-4** ARM Advanced eXtensible Interface.](https://developer.arm.com/architectures/system-architectures/amba/amba-4) -[**AXI-4 Stream –** ARM Advanced eXtensible Stream Interface.](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.set.amba/index.html) +[**AXI-4 Stream –** ARM Advanced eXtensible Stream Interface.](https://developer.arm.com/architectures/system-architectures/amba/amba-4) **M –** Typically refers to the Master side of an AXI bus. diff --git a/hdk/docs/RTL_Simulating_CL_Designs.md b/hdk/docs/RTL_Simulating_CL_Designs.md index d071bd12..c940c719 100644 --- a/hdk/docs/RTL_Simulating_CL_Designs.md +++ b/hdk/docs/RTL_Simulating_CL_Designs.md @@ -4,12 +4,12 @@ Developers tend to simulate their designs to validate the RTL design and functionality, before hitting the build stage and registering it with AWS EC2 as Amazon FPGA Image (AFI). AWS FPGA HDK comes with a shell simulation model that supports RTL-level simulation using Xilinx' Vivado XSIM, MentorGraphics' Questa, Cadence Incisive and Synopsys' VCS RTL simulators. See table below for supported simulator versions. -| Simulator | Vivado 2017.4 | Vivado 2018.2 | Vivado 2018.3 | Vivado 2019.1 | -|--------------------------|--------------------|--------------------|--------------------|---| -| Xilinx Vivado XSIM | Vivado v2017.4 | Vivado v2018.2 | Vivado v2018.3 |Vivado v2019.1 | -| Synopsys VCS | M-2017.03-SP2-11 | N-2017.12-SP1-1 | N-2017.12-SP2 | O-2018.09 | -| Mentor Graphics Questa | 10.6b | 10.6c_1 | 10.6c_1 | 10.7c | -| Cadence Incisive Enterprise Simulator(IES) | 15.20.063 | 15.20.063 | 15.20.063 | 15.20.065 | +| Simulator | Vivado 2019.1 | Vivado 2019.2 | Vivado 2020.1 | Vivado 2020.2 | +|-----------| --- | --- | --- | --- | +| Xilinx Vivado XSIM | Vivado v2019.1 | Vivado v2019.2 | Vivado v2020.1 | Vivado v2020.2 | +| Synopsys VCS | O-2018.09 | O-2018.09-SP2-1 | P-2019.06-SP1-1 | Q-2020.03 | +| Mentor Graphics Questa | 10.7c | 2019.2 | 2019.4 | 2020.2 | +| Cadence Incisive Enterprise Simulator(IES) | 15.20.065 | 15.20.073 | 15.20.079 | 15.20.083 | Developers can write their tests in SystemVerilog and/or C languages. If a developer chooses to use the supplied C framework, he/she can use the same C code for simulation and for runtime on your FPGA-enabled instance like F1. diff --git a/hdk/docs/images/AWS_Shell_CL_overview.jpg b/hdk/docs/images/AWS_Shell_CL_overview.jpg old mode 100755 new mode 100644 index 3369a711298e086db50a3b41ca56e46ed98d98d1..cd1508ea9aa32dabcf1c7f80b0e0e5493bb3a42c GIT binary patch literal 105246 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 a>*ObsGpHgCUyhrO0`%(B=xxw0GXEWGU~UZn literal 125598 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 E4ZFxFlmGw# diff --git a/hdk/hdk_version.txt b/hdk/hdk_version.txt index cc4e772e..8d821ae0 100644 --- a/hdk/hdk_version.txt +++ b/hdk/hdk_version.txt @@ -1 +1 @@ -HDK_VERSION=1.4.17 +HDK_VERSION=1.4.18 diff --git a/hdk/tests/simulation_tests/run_sim.sh b/hdk/tests/simulation_tests/run_sim.sh index b4b9a083..af00f668 100755 --- a/hdk/tests/simulation_tests/run_sim.sh +++ b/hdk/tests/simulation_tests/run_sim.sh @@ -63,7 +63,10 @@ done vivado_version=${vivado_version//./_} if [ $batch == "TRUE" ]; then -COMMAND="batch_submit.py -q vcs-lo --jd Cad-centos7_2 --jn github_regress_${test_name}_${test_type}_${vivado_version}_${simulator} --wait --echo -c make" +# COMMAND="batch_submit.py -q vcs-lo --jd Cad-centos7_2 --jn github_regress_${test_name}_${test_type}_${vivado_version}_${simulator} --wait --echo -c make" +# COMMAND="sbatch -c 1 --mem 64GB -p regress -J github_regress_${test_name}_${test_type}_${vivado_version}_${simulator} -L VCSMXRunTime_Net -W -o ${test_name}_${test_type}_${simulator}.stdout.sim.log -e ${test_name}_${test_type}_${simulator}.stderr.sim.log sbatch_wrap.sh make" +COMMAND="srun -c 1 --mem 64GB -p regress -J github_regress_${test_name}_${test_type}_${vivado_version}_${simulator} -L VCSMXRunTime_Net make" + else COMMAND="make" fi diff --git a/hdk/tests/simulation_tests/test_sims.py b/hdk/tests/simulation_tests/test_sims.py index 0c725c49..9e526d3d 100644 --- a/hdk/tests/simulation_tests/test_sims.py +++ b/hdk/tests/simulation_tests/test_sims.py @@ -39,7 +39,7 @@ class TestSims(AwsFpgaTestBase): """ Pytest test class. - + NOTE: Cannot have an __init__ method. """ @@ -197,7 +197,7 @@ def test_cl_dram_dma__dram_dma_axi_mstr__sv(self, simulator, batch): test_dir = self.WORKSPACE + '/hdk/cl/examples/cl_dram_dma/verif/scripts' test_name = 'test_dram_dma_axi_mstr' test_type = 'sv' - + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) def test_cl_dram_dma__dram_dma_rnd__sv(self, simulator, batch): @@ -599,8 +599,8 @@ def test_cl_uram_example__uram_example__c(self, simulator, batch): test_name = 'test_uram_example' test_type = 'c' - self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) - + self.run_sim(test_dir=test_dir, test_name=test_name, test_type=test_type, simulator=simulator, batch=batch) + # cl_dram_dma c def test_cl_dram_dma__sda__sv(self, simulator, batch): diff --git a/hdk/tests/test_gen_dcp.py b/hdk/tests/test_gen_dcp.py index 24ba04ad..e1c7e764 100644 --- a/hdk/tests/test_gen_dcp.py +++ b/hdk/tests/test_gen_dcp.py @@ -71,7 +71,7 @@ def set_allowed_warnings(cls): cls.allowed_warnings = ( (('.*',), r'^WARNING: \[Constraints 18-838\] Failed to create SRL placer macro for cell SH/SH/MGT_TOP.*'), (('.*',), r'^WARNING: \[Shape Builder 18-838\] Failed to create SRL placer macro for cell WRAPPER_INST/SH/SH/MGT_TOP.*'), - (('.*',), r'^WARNING: \[Common 17-576\] \'fanout_opt\' is deprecated.*'), + (('.*',), r'^WARNING: \[Common 17-576\] \'fanout_opt\' is deprecated.*'), (('.*',), r'^CRITICAL WARNING: \[Place 30-823\] Failed to process clock nets that should have matching clock routes\. Reason: Found incompatible user defined or fixed clock roots for related clocks \'CL/SH_DDR/ddr_cores\.DDR4'), (('.*',), r'^CRITICAL WARNING: \[Constraints 18-850\] Failed to place register with ASYNC_REG property shape that starts with register SH/SH/MGT_TOP/SH_ILA_0/inst/ila_core_inst/u_ila_reset_ctrl/asyncrounous_transfer\.arm_in_transfer_inst/dout_reg0_reg\. '), (('.*',), r'^CRITICAL WARNING: \[Constraints 18-850\] Failed to place register with ASYNC_REG property shape that starts with register SH/SH/MGT_TOP/SH_ILA_0/inst/ila_core_inst/capture_qual_ctrl_2_reg\[0\]\. '), @@ -84,7 +84,7 @@ def set_allowed_warnings(cls): (('.*',), r'^CRITICAL WARNING: \[Opt 31-430\].*'), (('.*',), r'WARNING: \[Vivado 12-3731\].*'), (('.*',), r'WARNING: \[Constraints 18-619\] A clock with name \'CLK_300M_DIMM._DP\'.*'), - (('.*',), r'WARNING: \[Constraints 18-5648\] .*'), + (('.*',), r'WARNING: \[Constraints 18-5648\] .*'), (('.*',), r'WARNING: \[Vivado_Tcl 4-391\] The following IPs are missing output products for Implementation target. These output products could be required for synthesis, please generate the output products using the generate_target or synth_ip command before running synth_design.*'), (('.*',), r'WARNING: \[DRC RPBF-3\] IO port buffering.*'), (('.*',), r'WARNING: \[Place 46-14\] The placer has determined that this design is highly congested and may have difficulty routing. Run report_design_analysis -congestion for a detailed report\.'), @@ -96,8 +96,10 @@ def set_allowed_warnings(cls): (('.*',), r'WARNING: \[Synth 8-689\] .*'), (('.*',), r'WARNING: \[Synth 8-6896\] .*'), (('.*',), r'WARNING: \[Synth 8-7023\] .*'), - (('.*',), r'WARNING: \[Synth 8-7071\] .*'), - (('.*',), r'WARNING: \[Synth 8-7129\] .*'), + (('.*',), r'CRITICAL WARNING: \[DRC HDPR-113\] Check for INOUT ports in RP: Reconfigurable module WRAPPER_INST/SH contains an INOUT port named .*'), + (('.*',), r'WARNING: \[Synth 8-7071\] .*'), + (('.*',), r'WARNING: \[Synth 8-7129\] .*'), + (('.*',), r'WARNING: \[Route 35-3387\] .*'), (('cl_sde_*',), r'WARNING: \[Vivado 12-180\] No cells matched .*'), (('cl_sde_*',), r'WARNING: \[Vivado 12-1008\] No clocks found for command.*'), (('cl_sde_*',), r'CRITICAL WARNING: \[Designutils 20-1280\] .*'), @@ -123,6 +125,8 @@ def set_allowed_warnings(cls): (('.*',), r'WARNING: \[Memdata 28-146\] Could not find a netlist instance for the specified SCOPED_TO_REF value of: bd_bf3f'), (('cl_dram_dma_*',), r'WARNING: \[Place 46-14\] The placer has determined'), (('cl_dram_dma_*',), r'WARNING: \[Synth 8-5856\]*'), + (('cl_dram_dma_*',), r'WARNING: \[Physopt 32-894\].*'), + (('cl_dram_dma_*',), r'CRITICAL WARNING: \[Vivado 12-1433\] Expecting a non-empty list of cells to be added to the pblock.*'), (('cl_hello_world_vhdl_A.*',), r'WARNING: \[Memdata 28-146\] Could not find a netlist instance for the specified SCOPED_TO_REF value of: ddr4_core'), (('cl_hello_world_vhdl_A.*',), r'WARNING: \[Memdata 28-146\] Could not find a netlist instance for the specified SCOPED_TO_REF value of: bd_bf3f'), (('cl_hello_world_vhdl_A.*',), r'CRITICAL WARNING: \[Designutils 20-1280\] Could not find module \'bd_bf3f_microblaze_I_0\''), diff --git a/sdk/linux_kernel_drivers/xdma/xdma_install.md b/sdk/linux_kernel_drivers/xdma/xdma_install.md index b0803b3f..30b440f4 100644 --- a/sdk/linux_kernel_drivers/xdma/xdma_install.md +++ b/sdk/linux_kernel_drivers/xdma/xdma_install.md @@ -194,12 +194,12 @@ DEVAMI 1.5.0 or Later instances come with preinstalled Xilinx Runtime Environmen lsmod | grep xocl ``` - To Remove XOCL driver + To Remove XRT and XOCL driver ``` - sudo rmmod xocl - + sudo systemctl stop mpd + sudo yum remove -y xrt xrt-aws ``` - XDMA driver install can proceed once XOCL driver is removed. + XDMA driver install can proceed once XRT is removed. diff --git a/supported_vivado_versions.txt b/supported_vivado_versions.txt index 26e509fb..261b08e1 100644 --- a/supported_vivado_versions.txt +++ b/supported_vivado_versions.txt @@ -7,3 +7,4 @@ Vivado v2019.2 (64-bit) Vivado v2019.2_AR73068_op (64-bit) Vivado v2019.2_AR73068 (64-bit) Vivado v2020.1 (64-bit) +Vivado v2020.2 (64-bit) diff --git a/vitis_runtime_setup.sh b/vitis_runtime_setup.sh index c6fb0681..68af3c6b 100644 --- a/vitis_runtime_setup.sh +++ b/vitis_runtime_setup.sh @@ -152,7 +152,7 @@ check_kernel_ver check_xdma_driver check_edma_driver -if [[ "$VIVADO_TOOL_VERSION" =~ .*2019\.2.* || "$VIVADO_TOOL_VERSION" =~ .*2020\.1.* ]]; then +if [[ "$VIVADO_TOOL_VERSION" =~ .*2019\.2.* || "$VIVADO_TOOL_VERSION" =~ .*2020\.1.* || "$VIVADO_TOOL_VERSION" =~ .*2020\.2.* ]]; then info_msg "Xilinx Vivado version is $VIVADO_TOOL_VERSION" if [ $override == 1 ]; then @@ -193,7 +193,7 @@ if [[ "$VIVADO_TOOL_VERSION" =~ .*2019\.2.* || "$VIVADO_TOOL_VERSION" =~ .*2020 return 1 fi else - err_msg "Xilinx Vivado version is $VIVADO_TOOL_VERSION , only 2019.2 or 2020.1 are supported for Vitis " + err_msg "Xilinx Vivado version is $VIVADO_TOOL_VERSION , only 2019.2, 2020.1 or 2020.2 are supported for Vitis " return 1 fi diff --git a/vitis_setup.sh b/vitis_setup.sh index 9d79d3ac..37848da7 100644 --- a/vitis_setup.sh +++ b/vitis_setup.sh @@ -171,7 +171,7 @@ setup_patches # Update Xilinx Vitis Examples from GitHub info_msg "Using Vitis $RELEASE_VER" -if [[ $RELEASE_VER =~ .*2019\.2.* || $RELEASE_VER =~ .*2020\.1.* ]]; then +if [[ $RELEASE_VER =~ .*2019\.2.* || $RELEASE_VER =~ .*2020\.1.* || $RELEASE_VER =~ .*2020\.2.* ]]; then info_msg "Updating Xilinx Vitis Examples $RELEASE_VER" git submodule update --init -- Vitis/examples/xilinx_$RELEASE_VER export VIVADO_TOOL_VER=$RELEASE_VER @@ -183,7 +183,7 @@ if [[ $RELEASE_VER =~ .*2019\.2.* || $RELEASE_VER =~ .*2020\.1.* ]]; then fi ln -sf $VITIS_DIR/examples/xilinx_$RELEASE_VER $VITIS_DIR/examples/xilinx else - echo " $RELEASE_VER is not supported (2019.2 or 2020.1 is supported).\n" + echo " $RELEASE_VER is not supported (2019.2, 2020.1 or 2020.2 are supported).\n" return 2 fi

2L!K zefSe~qN-}kKS?KWz4xgwBlfw)IC19DZ*VCn&)B`VgTZ##m+)UG^f^}Tb7)m=he~6P z=%2B}NY00^w`m3CC>iH$+0bsh));E42!;;dY`!_>m~X6pFU&>R?gEyY>9zL;txnzG z9&9qQjyVq+tYoeg;LK<4n|*=bg;(+K@JC%+BS+i~fF>o{1R#CpSKXIJ$P>rIr@C+1&R7k_87}2I5GY< z2as2NaE_Q3bu9-@$30_vtnF8bu-1_yjmVV^{eH-ojpVho44)hvXLJH+ykXhxo;7?H z_<9qjFoqA`rpD3r{oNUxOTi23*943X=U9hep>>Lq=8FV=0a4}+=+MiwU4cd6#IvbW zc0S1XFyU+`F?Z8>?kK+NJMpoBy76%Ye*|DbR^!#zboXOLk={n+aY1jv-oPOVu0O=NlQSGHb*woa|yvy;fX7`EAL zA;GxnFNFJ0^@dvDdTG~8#Iqpzlo+o4W5vt55$kZ<7%$_mIP@1-&d+TVE)nMLIE8hx z-*J0g+_zHk)XC1%Lbnimzq@vv%{%0mboQd<2|0)BKJ%AeGw4kzeenDw&Ns14^GzC> zBZF$N)y*Qk3a@+#Uwyy?Tu-4l)cS>|TLQT`NU`mmJ;f(Bge4EST)VxAJ!59J@iK@p z%ou8Z)_IBmf=O6M!<&(R_=Zm|L2afNOE`fWnB2I0zQ-(_KNMFfZR6G2=~MGmF*H@f zuIGEUmDMaZ_|rcA+hEF;NI>1KeK^fEPvF5G0c^)pd3ojy?s|;ifsY00I{_>xzb*E8 z?{j}4lFgXSY^d$$jx*b%;64}Fe+$!1`F0rYx4s@}{d-ktCtmB~P2igYGh-0k*@(q$ zY&RhQGeWqvFx=J-%2h_tt@NwavUT<>?h{)7QB8^C&s8itf>qA5O=joY&ScOxICP&s z<-V$=^VunSLzVR9kUyarV~7rYRo2l_!!tNo1(kV4n1@c`!q6Akt#9{XPT2!A8Q%Vk z2eBMMuf<*p8Ihqi#~bzRDa&{g!{Mi7uBIZ%UOFc)zS~k{ zrh#6BQ;8Jd3B1KhE<8HFJ@!|&<%798u`dUOH?_-3mwumMD}tT9U7y;xT!i$ujNr$o zWe9pbcLMC9b5r7VE*6JA<4GPU59TlG8B1kY*4gWb^)d_HNzA-ujm_DAzcHU~d}xQzyD=phhd;>zrW3Z@$KX>njetZxV_)AVI#uIQW;EEQijAb#X4e zGY_8kX6lXs?4eHU>uh4qZwD%xvt0pNigZ1Ov_dD@Rk})+%r3i+OBUvubMlxd=OFzH z4nnfEi)7ubj4Ij0a0QyIZUoGy!tQhxzLwRo|EC6<^y4qwch0VKQVQgu6{!=-H2Sl5 zfvz{rY+-%eQ|p$iH?HeTXKgLE@}@_*iS+namXr$+yBYBB9&HABswUdi9bc=dMHUQvT9{3PauSzi%)YfjWY;M^JNS64eB$WLCo1*1RW|M*1W0R}SV0OlVI^qS69rkTf{NNIE zkL#7U$C#njyt63q?-{{AxtzNP&0e2oV|;$!HE)r!$tqO@zSZ+lAj_3I$h&R_oT8DP zpd0#HHpX6C2bwsdK;IM6@r-ixa;9A5wZIhl7pgS<~cr{h!IBguru9P#!kjO#Avz-rE269MQK z+7rXdE)PVREQB(0S*P_MgTNenNEzQ1`^Lm0@F+8%O8=+(r@s4FX!rckDj$A*@ZfOo zQS0>u*K)*whi-3GeU%?T)DK7;=;H$oT&2)fp~+d!E~C!Q3vmQ}yoaDxo_)Z?*#`h| z%!I;<#FJjRQ4)y3&NU4dW5WIASbrE^`x9V5t3^kW1NW-BW?5?xDGJvo*x-<}7}&or z1%8v;Go1XXZ<_ug4*&SW%`Y=n-Fz=GxSPv{#wpLU+1i26P3EEXJi~X0Io2KeP8at$ z%N4)>$yrC7aaS_apuVw=1DzpVA~|sX?6Nl+TBndl=rrbbKkZenjb9&OUgFxw76S?*Q7HSf4;lVBDdv}|xt?=31Su;hW(s%+BAc=A?};Idp@nyVK* zobb>OY?vVITw6kz4wDVg?xGvW z923_n*El&S09Qb$zXudL{p+30)$r(uT$43$qPLn>cSZ;*M35hN$(mH zDJ)8!15U3yWH_B;UKnG0;7vQsdYk$5b8}WJA>p|AbBI$rVEojvs=q}&Yf+o;A2y%9 z?;M0TS z;`ykHh$!9l!08`5>;s)$U>_JnXs$@qKJV@Jxcmp%ra7YSIDW%7aX;F-HeBUA^MgNF zXg-Ys@^LR{Xp?nhbHeea93K|WaWwF=lY8B+Q=0EQJuLh~_#ERRo!v5vBntw7TyU-# z&C8x}UKwnBm%LHP<;{5%wcqQ}@0|y{##ndBV^TfXjYsaag*B=~Z=O6BGN}~1J z)$BSHSp-@a=L}6g;7IG=30cJ^sES$09DQec)aU_;Rl(o6sN=aSV&fyV>y!s)9k*`$ zAs@7l{d$c%&rQU_c;>3F*T>rD+nPIIf&q)3?mDRNxx} z^ZM#OMU96oIZtPQ_jkhn9{S5f?L{w2h@w0%Oixx{WQbGut=z6VH28+y5@sX5RI5Tq z|Bd+RgJ&Vti3Lh0^FiQO3I2rzbs0{ap<|4|YW|zqd#aCpi2`q+B7)OYC63YJJYurf z9wP&MtF3;c!rNOLR%$6vcug}{XRJwpfJH;<2aw7T4D^j*yg96M3~-4_VG-Le+Cqoh zSi4aG_o*hq-MIs|(RH*DUCT%>hN?tNt&lor$kDLGdm_NqW`ptgKgB@jiWe^0c}{6< z7uYPO?Gu~8(d#hk6!hpM48FmOUm5XRmc78efr8?|1=On9C`>HRm>*^jEHEA?GKiH1 za+x!7!aN#l92m3le{2DD_zTYDf2fs07 z87h_^B5DUTpEzW_%lsHoeS)*%Kvwq$$HSkEp~^eSLid^993lMQ9DNU6fKNOp`-v6< zCXaTS)UOLH-<$cc#WL{T!Re$@z;Z#NOe9 zqY#_71by2By*Rf^NV@llv5QAn_@VQ1T=!Vl=yBkOypjzqTi_cXM&n+B6=V%~*1T!P zvna72`GbDrd@zI#^B@$VT*rFfFrzQmF;Cpus6qTQENu=pu*TmFM>c;R#@y&*E_5Gr zA!j}l?aw_Bq-qbZmNvMJ-}v}?6*AURO;jyU!hKm24Nte~*qXT;viDt5TG)x6=`Gb7p;F z{V+(jMs3vX!#rYmj{H{ZD3hM#W-nVUKd{=X2gv|QVC>|-zoBLcT5>wPDzp7Z?>)m} z&f^Q5k@y(d=2<}f=<~Em)U{C92cW_)ay*RH_{UxWBhl)wUhPiSaFCCKGWf4z7)YVg z0EQ%WH4fdf5#xYa3!!8K)eL0RH#zJChaQph@660acvf(87>Sk7=8#!1Z$;BdAoHEZ z=^_eyl81i0jWHhc=!TxTt+3-Y&I%!GqSbGe=RZI22YMtfDb22Y*LUeCu{<#Ur+LZp zufx64?Be8>XRjyM$QGvh%P76-2+^PJ@@b*BwJ0@3J$p@sK!1_M{ANOwBpxD|WI#~9 z;F$kC)wa`QeDj7exE(v4Z{)$5?Z)-m345ux+>rtp^|~#KRCjYnG<}f-b;G#Gxmp*R zTj$0)oDajy@>eCu#y`kI8T&j#j)Ujb5NMnN(sHao!lSzl3#iObp5i#{YU9_!4!82I z%dE^}7RIOs<3C)htKt%R(hE)@D@Wu3uFXd`EuGdiIaW@@COG^MEyG*HqZRT5iYvgl zx$rm*fJI|8Bd0zIv1Sm|3&&Vxh$qK1WJaI$!{N|ayx@h+;2+qjHH^DzDnr+ddMvs7 zrr(X8HQu$4-jJP?qDV60zSz5ZAv*hC)j=o2Z9X=0X7ZDyl}z0rn3P%sHvJ37Jx&WN2HO#PR)!%B_GlgODxt2Mu`Py8fQs=ee z`6G4FIQwOow0SlJbo-Sva#^j@R~#ZWJeD3nStbwf0MCdAgM1Qx(v5K|$giqEi7wR2utb07(QxrJ6e{)f^Z+{9z9_(spHtK@%CWI8Ib=LtPxAr_ydcwe zd{t6;NDkY?w#I{De2n79hoKx1fIVHydea)@gpuD+dKhOB2Rk%DR$_?LQCq- zHuvl|DxQTnfwqHMUhA!IFY+0Sf1_PwP0Tj}jEGqBuFtTGwrlJ!)1*1F%8u3he4N~U z*RK`UHAGY~GD>8ob)9->bC3C9ez47)#_udB;h8bQ!mRQ-L5yDJ+hpN6Mr_g{Yrb-D zH0~>*3wmQ+rw*AK`OU2nM}*GnDeCtkH!B2BL>xQVIjYbu6e{4+r>K z6CdKdGIqOw+Q$Yu*@?Y&LaMpA;!<8+hjZl9v7cgKZ1@15&nV4ugAY(m`%M<;z@@->l< z1zGvb@MrwvpYpdbfbn*_;B>F{qzmxPxSlX4y?1>x*E}A7r1`z;j@(jr^iBi9ciw==ULM8u2s}K=ih!lJ#v(aws2)GatmQW_dr^`R4cEjw z3?MgiXtkj<7yUHjR++?4u{*)8(Q3JataY-)Q26EijY|;UfkEVu;*EVg{v(?`+wjA` zH*ds{eDTmp6X%iowRbb3;}V-7GEnUvFU-w|8oir20yJ>9SdV{VGoo6z7zcSVmSZOJ z1@VxW*3SVH5r<*+^O{(*H!NjlufJ?+Y}AmOZxZki7~yS1tnvPBWf;f<>lpJ7{|^qt zSRc6tHR^q-_p@v7J)ushAI^AugTV;*_^udRN))P(X!)pEX7e5c-*knIoVV; z{PURiX(703=I>^s_v+hzt$R6qb$58!jV%~9fVD1Eqm4h^2T1- zY`o|vw1d}0*jh^oTfec4Z~WumCBdksRKoaxi+pm{;Q+qdG$ml8*)s;0e_>u?I#)B( zxU#TQrbgj3A)a^Po4h>FES6V})B5%zf3{It`8f%#z>YPfe?X|Y!U}~<4{7whLr{&~ zblSmFliJC2kaF)*xvkVLQxsS9-J8C!jrQHuZ`WWcaQ2UP0%iU@M=sQo4`}E$qH+&w zv8pMo?e&+<1oU<8;Dr501olcpHPEWe^-KnF*sn0j7Ct#&x}`O8eDHyXe@Uc%h1z6o zBE!4|q)LHhT7Ny;6RzbxmNLVGQd8wW8R6}*#tzBPco6~)y0LR^#<(hj_ z_Y<9Eo(Aak?gn+^7FS!}NN?6%z3+mZ>DkuKq($MHIy3@oGyW#1&toJWgyh2tPB7+e zo&{$;luG%-_dV{IBKOw^hM@VL!&ssD42lfemX3+XSq~KqijckKtGu+W+ z)6=-*$-n2kja8M75aB@9=LgWz{zYND z%XpFGroAZtUK3c}{xD|CHHt zkKN)UQ;G4PUmA=|XwxIn20uiyH&F&UqCV7X^iw1dOhWUy5R1|ZiJQVTCdTdGoQ#_H zdf(#RMP((!v)(4}prYfrTBZ6MW-3myEt6sKRufud=QKG?p@RnV%Jg!BN;zNyY8clS z?e&2huwQi(=HJX5ZTwucd0-dh*Puv~*h4`Q@x@BbiX`raDj8#WKCa(JxjYppJ9vjAq(IT`@ zd}tIMEqZYFdh|0X_J#93!ff|Ug8j{or@jy$9<&FG2yd5&!s}qeBW^{) zGNtdC85h{s_V$6#Crek5j;v~iY)*vmVI5`i??t$?p<@q6`X}T|0nE8zvDjWuBfj-2S@j6 z%vF>Sk0+k1G0I;1I>?IFKk02xm8dq(><>RK9AvTZOmjP9dY{+X%73hsh6hm;cP4A# z^;Z&|x`lyJv^~M`xn^g*m8n4ydu0!7C9h;Xkb=AGeyauoJ?*!vWQLsc+TKW?`R?c7 z_lm=H|1A&O`Outx>KgJXo?HtZM;X>JvKcXtZAQ%fHQS7h60PY&^I{8$r05+6E58ny z2@Vp+@0zm_a%=f<4Rry~s=Fw_1!OpHU?126dv9i(4~$0;m#xVC%IrHjx*6;n%y1+n z(kjK^hkms5{{IXc1`k>m!ZUJgEIC*3@Nw;4o!_BzgjfjNh$;q+Q53rmj>clLU&K^A zl;Ps!KLMuvr=9&P?c_AQK1|v#b}@cBFmWKQPI1J>#eKg#^St_K^b%%_3hWSCbbOOT zv%yn|Z_Bm^R%P3jp>dlVaNod&U>sS4AsUn2c8KAPOVUS$i~!?GEPA z>LVyBz_7jtO6HczjTd`>=|$+|-I+A72Y}&~nm@7eK0n^puV!IgjY_P1Fy`Cyil>yf zZ|;}6lMn;1j}x%cW87uT`@h3x<3ErX{Bvyv-dg%gqD+-Q{u+{0U+-cJ-#x&Ab%Mvw zIS{jdG_TG5F^XNz#kV^mpVf;~q4hK#+eJ*`>tObb7d?6GVgOsyV{TmiTMz0G>z8YI z#KCo{kWV}f>OEVDLws_y4>YVJ&swC?phFa6#T+u%V$Gar*<53t1J|^DWn3q8zJnd( z)aHGUUiXouYgKTqglPZ*d1!2ntcfIb{D#J^F=SrnUihm%&%~8_Y zM3p~-BT)6LMK-$-hbGI|4IA}kD#{7m4Yp?Ztdy}JLw$@wyyOUTwsRi2P(MFw<+lvS z+Su6m4;~Sy?xQ-S;Iwhq>#n2!AzuZ?u-m#Z1w!Ny+bDz0azM+f0<4#*V*8ZGSGhss zYhtuPq~+-H5s^8|eb9}$blNX+z!nOeZ4T!WP3`K_%C3^Pgq$0HPh`B69Svq(VAKH| zYmruZo=t<=I#-~=?ln=*T_>Lwb0YHN3MEk8ZbF-&WBeRTSb9UoX!{4C_N%;6kI{nG zj_Y3>HFEP=F_AH!vDP4yG1b=#Lm%SZP*TO$>v5lPd={Jv*sN;b?d=~^8+d$)hX)DJ zX8_cpj|VYwF2_?6x7~||{!C*hv(2m#4@+eMS1}hVnPcqDTUs)INeaiMWh zk;938Qj^1k*@7r=Xsj5YVvG!7n5*@sV@<2q&VJsX#{Q&VMR2-C>6(xNu||Uj)xyKA zx1qdhJ&jpCzB*-KygazSEdiwhlyhASda7$ln8-qPH}S7jE4lZrnB>>%4+}Uz?>pIH zjx_7{%&*VDJ@1FLND_(F$vs^R9}ez{ZZ)a%@NLO%zzNg4b?LV5vXcL>WR~at?n5YG z@5if0pIx{Hsc&k)qDuAC`{(#0cpNna(dTX^L<&f%X<+Y#5=Pm*Sht;{S)(E zt*MBz-V-NS`b$iE z;TGr6yy9Vxx1^_Ikz>bQ1&h4|+^0up{aE8FJn!wXfj34w5okBb3Rq@&z2AK0zbR1+ z?L6G`o*(DUh|15`A)Q-@Ccj}fqbOmJxn7hvTvpTk?eicWtwbsc>R20|6H>cF$2E8O z00HDKUA`#;nJ#y?<^lWXkFneM(E|}wn`Rs%9T}msTRIzWMZg7Sqx`QQCTf379~*xN70~>l-+;Ww zQ?jN`CtpXlGrad(1E(O94z4YD!*?j)h;g8ew-BNC@j+f6=egA*Py*C2N*u2b!-;R3 znK$=io_p5Ww#MsN)T$)4dY=@+kB3t6`cN?NHA(P+Zr^C`Y4|K zIFFfRfp%VLU@dV+_B8un9D#it;P0G6{6b42=^K4BKNJpSuu_aHuN+tPYra==3OW90 z*B#Bb#in?XhZ^{}r5&O}%x=y5P_!M0LMNq$aqy0k`Zw&J)*rIP-0MegN}g_RD37}b z==fjIK!|))?t2QA@`=n(l!M)=&M?2h9NcWxt9xVJJ<4gzeWg@xeP!isZtso_hGaV| zmku;uaOFg#U&$1f%9L^28YJ89R%6IaO`FASxV#uX(@xl_R}F7(7$ctLo?)-`$hr-C zK5E2&YVlsWn)G|CceSh0l*>bV<3i8+jp}!O)%HK|<_%O2#)YwY#-0fp*Icw(Y#_n| z1W|q1DewWLHe%d;;G-c5&-BJ~;$gSSnL35m4yN$`aG!ribAZ`5A z>kB$|RBhiFHBn*Uu&m{FBXsy}v&ehYK$Pt+TK`l~Bf`x!F+6)8D#Onb9M0?Oc6GZR zk<2?v>)sP=&G1Z$m%n!K&ED46V&I8-o>@7bVJ$k`4C>w{^Ff++(IEzB!Dtsx)&~y% z(Bwb(rkcKsKpkGR>36zy9otKA=uG~n`{o$dxxP3Odqdc>g2NN!$N_s2+5=bBoU)J1 zRq=LzxcM|fyf=S>MtKQ>p58ME=a+ z`@qDxN~_MP*FA4zDJqU&sM+Q@nk;)6&OXmtPjpbnB9tyRbSy&>gK}CY!=1q zfbB#08|{3_swljGmGR?UzYVwbF=PK!J&^Pw{;)n}uIPs%+O}+WV-Fn;=AoU%6R}j^ z*bw{Voc*k9U-2Kg`)pXbXma3e|FcoGn(dA7tD|;pZb02>KqcmWy!#x-o+JLtw>XaWMI-2kh=<1v_W)k@-5U-$%EEESiN4~69(BTNq&yfpZ&f#pKqex6V^J@-hKp$L}7#fy# zya()^V%bTofoIz*goOljpgMFE<)m}-y}f1T`-r61P2#t7M<%V0lK3ip#4kuftv|zx z`;FD%HJlGeY^%W%xA6xX&X=Dt_VDHX^y_#TJohD@OVG7Af2>siX%n6jf+?E(+SJqT?&F+Nm5VH6~6?q0&w zZ1*8k=6$a}UPPRDK2q1@7whFT1oDNuDKxlnz(i?v#C-n=3)#^Kx*#tkAU98 zINtv1s2d#`pPU<232OI1I&`>#n!Ia!15Bw#<5jA89#BE7`87A7jTadyG%z;Ef`gYmsZrd=luRN?7ypnOXAHXiZZC6pF@ypzI1wv3k0$9rV^r(s}u&d=N&f*#Q2Xt zWsLEtT9az7%;It5|i)6>&D)AqkO z8g>|P@FR9So*gl==ldY+BgZrU5skXouYzZJkofU*?t3&&X6qQtLD)8i!1}+gv%8kC zTDB%ozx4skvz>d*r5bf7cL{Amqq~pbte1=P!Re*?Q#{B?xOQW38PPRt+|P;$2Y6}y z(Gi`!z`uXYh%1Q>#~VYNO+$^YBG`Z$IXJzaW9b`Ze>LO{JkiEAOS^=4&L!xZic5 z55H)ie3KJzD4&ioW_#o_aYj{Udw< zAa6ScdX~7l$Oj7XZ&KS_HF|K+y3uOCk~f*0GzKnQ9RcI`fe)nQe|+m0BPrh>mp78^ zPo?yWqPh{i%IUK{qeegQE2sW42{GW{*?QHp*&$j@U7YyBP{XoK6wHz2Uj0+la#whn& zKj<5QE^~C-+%rP}{BAvBGehX@sK$YDbqpGyXk$*f#)yu{CmY4KB$|QxQlQPq=-XsQ zm)RP@^$B-datz8~8U2cC2UbfEMY3+<%SrZ?k)!U)_oAjdb)Tt?~6;skaW>NMOAbZ)Xn zXQW5KV~*PE*X>@r1q9a##Yk;+42W}uMA^0LWC|1c#4nrCBona8xKYsuytaXO?_0Q`JTWpd(FwBJ2SX~QO@|dZy=m$vp58XyBd-TbEIBQVy#DId* zI$QfU@W1W2%D!{{MdPMmMNLj3twsKF;mPP$e>s4dbLE&YRmY=Ek%#>U@iZ(=mLWO- znvQyD0!6@~gKNa){t#@{iwi>gyQe2ndY)J9GKcTa?bog}GtciKc``1ih})=tlJey8 zUOz{L>n$En4@`jgrg3C==LRS;z1sWC6m|E6`#|Q^zQ=F0*cjsl*$+^3WMeS&^Ns4z zZCt*rs@WyRpm1Xm!>|3qR_y~xja4Z~Z?PL1uv`y#&GVAIhK}!OArCypO9-6{-Ic3j zm+cBV@KsuqtW(*WL%E`UZsA3N&OHImYaR0!0d~S3t#4SZ_(!;a#baiJ4Q>?t%>wJJ z^_dcZ#s98D|9YU@(EWkOWj!!NeT-51OFL&ZimXI_>^k$nuqD36%%srHoCP@lw;Y%E zi)Fg3hp+4a)-}GV-PIfk^s5nT(F81Ig^kRyoA`Q;hdFtbM<@GoqpCr0c?1MBI+h>o zs;WU=&x~@7g7C#-{IVB5+qm+BqZ`gN74Ttql@X|_F+EI!cI~u4Ruwsi$%y80Vod%T zIPsl=oD7D5o_QXc=PiGo^ldV!Oj0yo^6b)uOuJ2nH+a^5MS(4fM))Lkym7GBp^^q^Ja2 zaG`|AiLu7MbG*a59^czonI_LScDE6`@^QkJ^c}aD6BgUrtFAM*HvPEK;qiJTPT;|~ zX!XLmC-c-6W4X?8#YT5nFVmV)rOgp#CKzPN6}n!%@(20AjaJ7e-Y$RC_z1}(k3SoX z%K6=Xl`-Ti-LsezOPlD3BR{shI^@Eo=NY*W&p=Atn%}L_X>QZLI6uJ_=8r`dceNLD z^j=%rWgr}^Qu)4+zf60d={1JO^C!DW)BIMw^jq;2vZZ|v;O&0l{1K zIIChg*;h6Jb~QCA8!J19-!hlM5%ir`uGpOEy607 zxW>B>s!_NYL8~VCrIGx{1LKCrh>e>0Y?yF45fH~{aI(fTgGs2b#&G1ivi|qUmpP%J z?N3JCW`&v4AD9NhQPpwq31|#W5Zf;iFn+)g=fKj`(RQLiU@cXNsXs8EN}mq2q3ozn zVL(`OMJe8Vy*+f@BrvVP8kwny28x5KR!1;FW_~3wRwyE6G!AxiOS0-*dWOs#_inv z|Lnbqg5x-@1UOx@`~N?@Q@sd)K>{Fn$aZFB&pcJxB7s2QAVo>O(%8CLBG;b<>oPlU zD^{Lp!+1L^H0=D@QVN=7rxAC409l*X#&Chz&haCbfBkOXT!BvY?Qb1&?uiUk_K+I6 zz^d~WWcX<~j}wY%qwNVd8U8_mk9ik2$6*dtE8N9@>zhF9T7gG~M+XKU@V4)X8@uW- zM$oqndj0ko`j89AVm1NZ8YJ9~m3Hk2wQf2?*lBxO7?)R$NQP8p>Ko4W|4>RxF#K30@mKHCxK#rfQ+it1`va>AV@W;?5(7_D?TSK7nkx%TCfLs_ywRC|& zhrjdPH_@TjkK?9Loc!!0xjLSD7^z{_IPR{RWfoGCtFsPP;`+sE;AbwgTt(WnqK40# zW5F!G_t~xzMkcI$mF+&$r*UTw(iaE)7e_DXMokBokCAQvrdXsUqUA3G4-gHn*Qc|YJr~!Zv$h1e$V3VeN4yNd=utLzo(5DMjZQc4%{I&tpkd} z15?_*HmzOEr!Dc(KgU5>mfQ|gI%|gbRJuNP_@$GXc^do#@#V3X!xJENkF{v{Tbx#G zmuvEG6`q8T1drTxW}C0b>pnMB)Go$2WMbVJ(ZEf=Zn|fui8j8DF<@Z*;2Nbq;{_0X z5hS`B2(d$)dmr{95GeA6`XI8F@yIdGS2i-B^`k!oQ6~^_3$i4J%@ez+G-59VnYH&# zgLn})aol&`~u@Hv_F;OG|*A~N*s-h5DA*PGh0&#OwyyT6e%kf&D8 z(dTor{io=2j#J!iaC-G$xH{wXtbL6+G5J;jJUfhZap?6?b}DbLYu7@z5O;H%!@XNJ zdOb?56P}y_dV|qp*YR$edWdg0*EdFk^g6#`qOG!aea&%TjAJ36eu}P}V8lmKqtyZD zM&a*l^urK3Fc;ZhK+c)nlT>5b`8y3~RX=(=Kni63H-MC*eJ_;#^x_YLQDj}u*cC@T0e^6-;9R;h%oCB zXJdP7SDq^y@yj?9k*R(I8ugOxo1-^-QYVy{}LmST!HB4}|j|q*wx(H0s%{ zy_p|<^7|-5y;_Gja;UiJm`nJ3J=p-h^hFgJ59h!&^~fWC*po~4z$3HWoT4rKcwdx{ zz4tz(Y^}8nh{*dr=M8ISmhd#Z_2az?zAG!Ajbl&+-pXPrb0N{C{#wJ*pi(f~N(UM0 zxWBeoS^gxsj%BF%Cc2lWj$HLTvDKfrXHan*Jk8DPjhk%VQlW0~I9Su&;?@k%upWEV z$F$<^GjSIY`9UnyHzHJn55@cPIDXB+>l%5rJYAPK@o5)NNgn!HCvXk345S6Q*u^6P zAR(XlTM;I?Cxx9WmRD(eYix)^{NZmNohH;*>!V3#Ngv?x*+&qHD(f&$BhwcvIh zdKila>QY^7l9OSuFH2MM*8(75;inR>d{G-Pl7k;E zUKs&j=RP-E5_2V5^2|-c1(?W|TZ4^k7A=-S{YmuOMMyylB8gzKZ9z;ga#UDP3qN=; zxD(#nzS2hRMs8L~+~Q-yGbD&*+}I;kn^O2hx5-UL{NN*peVfhXI9Ie*^I>i<{+L7f zL*)EXJ-DYFv7pZQ?A>o6(K#umwponO+wb#3irDdp8^;QN1Igx`a0M8mvk1+y=83H0 z$&vVWpV!&ozpXF%_Y#cha>z0iUa+XU$$Sk>COTbf{MZl5m)NBk)s2@9@dJN)3h~A00w04XL>mwB)F&3P zkaJxcYvpR%0o`T?38ua&fc)(CdB%~;o*UYtBDoM#y0A+ij#cR}VJE()0yt?gbbrx@ zYP(L*qSh|HiG+>)(J*;?2Af}BNHwOJB7zM&z}P3mA;GzW)gnv%q^^1@zuJ`}}fa5gU%C_Xip8Rn?pHb9^8j zo1!prrcLHUlc~0M+BL4ZQpBpRD%UtAM!o(Z;V`DH9Yc(L3T6_}Zc>N<>1gzfxdM4v zNYE=r+x(4MQWGlI`~?|-d9N{w@FK=5zRaJ9clDyFpGlNG*^m3>g_R_t-?qzYtUXyK zeTxU0R)J!kDkd$U&LW+~&5Iw!?FW4t5q9s^rbzDvk&par-seqGH`7@?l*x~Q6GMk_ z4c|}_8R~&++wKFvwiWJFQ^_kCc~<+K%}xhC9>+Fis_0i}>N%&sSWR)vRi%rcfMG)J3f#xC-zNbfgDB9+&B6r#$eoeAUM-;GrsJ+TuQ)yjFg` zT5c!!lNS{AFaW2zx8do3hXnm@!v^*^`?4?1!=@JL?+xH)(T@!l%&};C&4JvhEh2fA z6urm7xXqP2w3Ya*~RnsncJa%nm^Y)T>atPkRy*~!ThmOm@PjsIUOcS#5cgh#B zuC~mVu%gZgFpc?x)o{!qFSkonTNf~kq@5KoWytf3#5JstPHSKeps)#$o4|v?B8P;z=xRA6Jk0;&Rze`e znpe$C8l?Ovo*ar|shhx80{ftW=S{JYkD#|a zJ0G(ySJRH7dk1{s3e4j?m04%MUDAF(##>Bn2%50#q|w_TYkkQ4OpezJ0FG_MJ7jD@ zx6>2H{Zl;cUfI*vllZb9)`<18H$X85$2{cE)K#{y*ZTXZBKM{C#t}4jRZUEXi2!qK zym16}X!$^&n_0y?JJUQq>I}BMp+t-!hzHGpdl^G;dyS)$IfXWJtTBd+e%fEUZA76) zCvdaj9LTZUMjm{E1SL4sF#EdiKO;sCtNgBgUc9ncy>T?vr8%^^x;zSgi+LP_F!jAk z@8>nvyVLj~g12kaa{5_2S6c+u3Q^XBLYOo&)R|(Kb1Q~PRVGh9X++ZA7w(E&^eeeD z{YNzyX@=qg)92vQV3T&YS=Ar5JDsRIN8x9u6W(WIhBywf6d`=2sJ@mxd)(hkp6x$^ z*pAJ;2RomCh^%m1uf$*HuLz-wO0Pd}TK0Iqrt#Om!Z(j@oa_#iosQf$7-DU|UMP&K z7)llS%Y?}2d+}wGg3E(9ZN##=(Ak*HDul33dB!)1uj?)j&`8LtsBYI`{VYt)P}n;|z!@MIY{hYY=83wgVwlqS{$9{Imyj{b(O%fW52z{>3W z`Uxq<)~|8Q%PiE)J#jtirO-G5fE{g}LI30|WZt*O)NT5zwL^M~8y1K&=ZC(@#yZP< zxE~C@^(-rI>DrhK4C(sErd!PT#-o0`EJq@G3>0~tJKxmtcVpLP*U8LNXnXBOSGr>y zB+>e#9*0doWxvIoIr|>=I{*Mc07*naRJ^&aiC&=XXB>SlJ~NxVnrk~Q2NharF5=q- z_?7|IfnGDQ6Y=zkVCa*1?RX(o`-%XSLu{CTymdl9Z*_$;>Z5&z(QC6}&&SRRm*vd? z{WP_$$#bm|ER%))7|$R+cBWJ%4E+|0Skk}l+3}373{W!zv;$l^p)b8E-YAoo-=k5m z;opuN*8(H3$Yb(K)}w+S20v)tYJskYuML^cQ?YMcFgV-$W7oIIq?b4C`2HK`1~Jq5 z#eg&xd4kGzdL-(#h%Wnb6(tant}Bwv=V z_%jau6-R}ARfalX#lmKF8I>{r)EWlEfyZ1x)AIv9{E5K|Yo}|xaim%^)aUW7@8+dB z^4D$vju_Q!dTKA%H2UrZW^j(3KD#HJU(h{Jk1?@DM6F2H2nL4y%!~ck_L$?lV{!I- z_Or5C)q<(+m@CXucBuF4=gxrsxSx40ByFx#9>EJaAmbi;_Lgmd@ZV5n6dq?soI6Ru zm!r0(w@^}xN1JUflf2psNj$PE&{J8A*;~8tz1X!=K2GDCfv1hntan_i;~hq#Q$7b* zE(rDFQb8&jPZ>Nkb8ClP>1w&9QS0E>^y~W1u?@*;4R~^{8f>wJ3g@#evIyhYO$03p z@0YPb=H=Z)8?7!fX6nzEsT^Q$Enr~$0Y>%4R#iCSDm&UQ_G2uKWdZxKVp}(Sk^f+* zI4R}}?x*2w#`zJ|q9jV6hB|fC&3rwC)$g2Vo8R#ojaL_u6 zOYu~=A$!6;tUlQaE9H7&`J~G|SB&Ad^p5kvD8%xkXXSXos|#S!+)fO5#A6Fu5SthW z0}m3OBw{VWZl|CdFRZ~0)(6HIyv(1Yh9VJ?QhN?0w9mrl^HIq+-2Xt03R{5O56`KcUas7?l{@QDYGb@fb_a;RsJ{;A$v4^huggC7CKFRFaVO7~l zeO*{HFYE6>M%A8I@&NjhPVgK$Yj=L!ton0}9-n7P!M(m}Ze^v21Fb((3%w{p$Z}7? zO8e-6;ls;s+cDo;tAT_4?PFMdwuSsr8$5XZZddBPy6t{!RFF1`A216{l;fHoB7D53 zUA1MbS%_A>x1Q}#m-vDQj28st5u3cJWER`}@N!4(#pFAW^{9{8&DWx2ulIYO zF5qN7=2TN?LTh|CSI7mf8_bO|=7*HIlCu{`?n#k;HKsN1TDtRSGkA3^fB@3iOF;IM zjLx56ybr4buQeJjC1Mud3OFV2T*<^aY|tqAzTP&lPlOTc5|)RkiW3BJwb<4nW&*~W zcmBrug9a!n;VPh#$qs3F;Kgz3-z{_W%b}vKRn;-)vWR2ZMMTjrIKYu z^jP*_r!UUpmadJC3}DR!X+D%zr+mA`>^{ZxZ~5uEc~Oa%z`MG3u5E)cBF-GEH>4hc zt@8DFwx!l$3NK>=SCkB$I~rV*`Z?bbjE%n`XB-*Y9_xeh+wsvqwVYrd@A7!$D+|ei zO-lqe*GF{;51h#(o_|jPQq>?|X`n9SZx@-&&oN*zI*@63)LI$T4}6h(ghIXTha7X& zScc468iz{=Yrx$)keU8OpLrrT_MCZxUQ97<)enM_wr11fL|b(*YBDqtI?g$`I>GkSHg9NyH(kpm zL;$ph#c#3w55~g#0CC%<7tg6^bHru}ybgj@tt&Y!)wJ>UKIr64M)bQ3ZI0z|rp<`hj_q!p*gAhy570mjT4*|t68wE)0J|9Qs_(%BF!@F6#U zUi+;#nP#Bj%grFxDb`123$L((hyUOi$Cuxvi>n}vgX%@s!}2(3!!%hZ#Eac(!c*c6y|l5JRSu@t^pV~nm*Vrg`5tZ zP@9;m{@kx!)vUNwDNn|^;w5U{gV${L#|dg()tijf@$VTiCs&(ftYd)l3-0;#pIf_Z zO%tWYx?=HiVE--gQsyI}tk@%f{t$h)?+rE5o;;*~3`2`R>@{{aFkrTT$+g_ipPO&7T*2b$cJ9jO}J#JpS3buS_NmCWd@{ zup8D5nKsYWKO^Atej%&s5%Z`JE1An@1$k92)az8e!GJ?#B%I_AAaz_ zmg3Y{Omlvg3rwLyx_xX&n~cXCa1J!(Ip1KacL*jK908F!2!KJzOm-Jj3HY!}&dSV> zbMvl#k=wkcKxN}u>AC)y9m5|NL7q?QFLTfS5MSF%nD*@=xfw#p@YU*}7n^!Yv=`hE zgUOInj-?qx)#nK8@>~QiW7SBXK3D(2`J-DHus9v&aNDQBXT@HUX*qTr-?cR?@sPQr zBr;w)p?K^;n8&eZ`|NmXFl~04KhF1s_gcJ>`kA?bU8%rzvsqR*$j@N(rZG?<0zCX$ z5deRv<3}T}Hw?*RD2sb!b~_f)vhL|RxSDv~ku=JI-Pu*2OY!Ic9|D6-O5Oo&&`{{8#B&1z>AE&Xg;qGa*jzc%z& zxxvp%-v)BK!I2A{@mNr>6p8q^cv@HR>>~<&14(4vN?UbQ?>FS=>D~tHZo_R5@LDrqL&tf+| zdl6RVjU>al5bWq+u?MZyAp%ssm`N*sj7!B8nf+)-&D&?(Ruh&w&!y;13mQdbFC9(2 z?!z8_#!teL1i*ozbi2nGCIA^`{sHVZuK0-B>KWtj*wz4l$t?<6a$GpS)U)V8fin*E zDleW~ScUfML|VI^@N++E@6D?50mv_C=*nZV^*oDq_|VCO;b;hVPK;yug45NpZ1OjX zm*PjvDAN>s!c|?w66Rh7DrCAIiJVzrul~`X5Hi=6?z{njpD*u61R!HPf`R0TVK`9+ zo7T~_yw%C;!B-P5V(5Hic^-|86YX#J@T1XQ8T^)O0sA8lgx7ISj5RE{wn(r#+4jo( zVN~UwlV%l5X(S<@7R!ZQC1wanGKVp)sD|aJ#*l@giI_axt3desIzdJA$@+H2NdOOp zkUZTGjRHq;i4Vr#);Z0koqm7Bep?Eaqnirn0lKlNd}Z0|W!V)QUUJ0Qv-Yn*rR7q1 zTN$ngxA>*QFID6M716$S#;~aKr%b{aZPfEI#91jsF18t$95JqRL7Y$*T{uMyc;Kd}ehiF@w+FmQSR**; z71Uy2+xFF)yyGP2wBlmOqivQC53b-txM=~;dd;xon9U~ty%MZ5d|>$bcrjzt_Nu;q zNZ~WwGRs=fujF0~=Z@T-4`IxI~x=pc5^9opAAeeVu~0?`<*h?S3gD6k45B zBAs>Z4Fafe^ueos(F|Pj@JA$c7;|FL*y=@gAZInZfA*&rND+`m^p+#$7O~@z*7CPUDY~K33 za4KbmDc>ZbZbMh`&}_ZO6*Ma4HkVRdcN}KZggGg4xRh_qC)I8#BN#Kk;;v+{Nf|3m zRlk)z{eE)K`AW|DEgxu5(Ogwp6#Jrh<_F_`e^k?>)vdN81~sc=ACXrtLNa>rRO3Va zf5X1#SB#I%xm071W1(3HF{o!h02xf9EbkE!aNJkN3yfBBBg}rI8%uMKi5Bn&$uk>r z>|-UW?QLMx6`Kk1pljp%_ix!>kx70Zx)+2yb@^J!T8{4+-`kF9e`kYPe1imTwMMlB zZ6}2SA4Ut0e4IU+KgM`|emKsfMrZ0jiP)|A=eVv85*eTwH%rdm{%HtXO@2t!@uKl` zIJP4UvFk{EI+fS?kVnj=75J1=9|r+`aQ4|J+&cNb(PA98Mtk@ZZCR5>z~gW6TFBnb zqE=72KvS)umSC%!%f_oU&Ujj<2p48?8H{c>OrW?F9ZLvAtPj8Rb;FOKGrfwzo?K6)LE*WbNk5 zk5Q{^hdydDAHcdTB8G?=v<~#SYid3H~;(9>quw2I3Bb9J;^FdsU(V~1zlm@^ZdRw)|6_k{%P?Z z;+ZBb*4RlXxmGe%5oeou8!x&!yS(O$8Esif%w3&xR0L|Gf>1m2JjJ;RzF{MK;j^FV z)SeMAp0@9iYNPjhjAk^R`K>FH*tro_Jc|q@TF@XCJQ$la!^ZO$Vjcc_dx*MKS*GP! zb+dJYi+OoYMW>_ zgbw(sM9}%4xPw1m2AFaKRv(}eKK%3@eyRsI|Fq+tHm~f-;rGagzqVsRAQ&Q~-J1H7 zKvER@{-0JzQpfj&j}|N8%We!il~5bj~88yX%fYlVnx9#Geg zPeDGJAL;_JyEhLZ>vO=(6A|lH@l(b5u_pBXli#}tnZ#Q75&%!|0`HH=Iku%K!-1}n~$JaP(&@^wy8|L*JbGY&A@ z_|35+-gb*;vGcqHBfkj{UUxsG3H|P8!ALibLrT7Guj3)~+&>!X6c#wJ>6x-f!t|m| z!_%Qjj-bpYD=>%5SAJf}C#S)1<`3$t4gvztj%%k|IeEoq#kH0PFVe~7ovtHb5R58r zJ8x8)O2%_Q_FZ8q!{rt)xzz3$*D+{Pr~QrH4aU459s}LUNDh5^QD{e2FY#{JA z#U3o}fFCaiC6w##6RA!p&RCj=1#cR?yCDu=qs*B5*ab zi5YJn(c3tInFN~n1`?6v!5)76wx6Q|$@oyy%ppTNCp1j|ms_aIn{Ohqe5kS28RNclz?#Ey?{=l!d-8j~4K90nz)5OJ=)IRL2n)+?ZwcVut-w?3YKdlN?JbLRS!?HOa z{Es>jSZ`Z=hz?%f9S4i7#=wz*e*Uvov;e|w_x1T;6iEbHG$o$>I2pE2V` zg#IMD7YZb=7qL%EGa{p}vj5wK^WWx!9js_+JXg;TOk$K*>=P(+@O*8t^B6!-Kt2f0 zc>*UNpy3M>pi}?6d6&L=Y(dd$>jpbU1~(d&yzqc=Cf2z(JH*iRu=VyH%eJlpAd`p2 z4%=i;o+o?dAXnR$WyK3Zd6Z zEaOd;%&HXy%-bssUw~D^Pha3MigDuhnT>e-2W#+UPf*6}RUq zTm?~{OVKtZ)+{3?(7CaS^4ngO&(1c+60?cD9m{(DG)fn&W>SII}3aQPRAJHJn^%~F6y;6`iK^z!4bic@mg*;vRV!#+eD}JzJ~{<3;KYsIyO)0np^&rmC0V4 zW2ozzGiW5N5!q-3jCAbPq_tl0;uB-aHJ=}x$z1H~xUloqo^f%%C+oKid)T!WrDiVL zzP2>rUDOXr0heGH*R?eg*lj2M&i04t^lu)aK)-&~C+Qy+uM5YI!g=}(gxH}&0gu$q zOa<#9c(|gt<6dvv(TPK>VDNiqPzJ;-N@dE4rQr7zxG!xHmc$ot`d7%a+~NHKmD=q*lDhMHe|(Kjw^EQrxJ1 z`-XD8;Pj?kagM}%hfA4l6-(R&$Ui&dJ2qmu<)ewmbJMC>$ee1b-*c{OA~F)cQQNA3NJSoc#VSF=Bl_@yZy;G{b}d0U64NOz zcpe2Dzvf1ULKs2P>eQ(KC^lxV{_*Bi!!+|~Q3@lZ?19{EcI_>3CV9JplUi65s%C)B z9!)Pco*^+>JSPW%Lw?RK1mLk_t{aBj+#69Ie`SywMcx(#OySS|D*?-?dBfPzXAT%t zG9_v{yutgo{M4U1A(#4-4*1;$pUGv1(3Ef+jV5icYGJP9`gV2yw~STeu=!5@YLDnR z7cI~+CMwTC3Q6^X8{3Iy1_RhUes+Nb|E2?v6bOsjtz*mOp>Ld(#2Wih03@^fuaDy#UgRDtF_Y;ASK+- z6)w{GAQvtR$Hw>ZqEj1h?J>%_Mf%B2fh#U$?xIy3A*#Ac_rrMYjQ|wY~@M5=$tNbb5Hbp;J=iZeEHTr#7b|@Nue8WGHK% z_9_D)I5%9swuT4!pSLMr$B}CT+x_2y%j}lJEd3c0ee>vNgz_+oK1e*|F7090ZDnwp zxr%ghv>DQ8m;m%gzc2Z}0_Ng|e;3838a6|`n6?5$H;5JUO#z7|isk^?$5sf`!@C;r@JuqM*ZWVX7WuJKN!DSnA znNG-5{x9!YYSe&bJJth60M9owfAL#ta^*DFn-0VtSK!|F(We3U=1(~O7CdogUpm;r z7LJ}ZvIbsQ31>)t~wbG-Da$8kz3C9a{0&Wy;0{mMQmV#F19gCte>B|zTv6YE=eeqJ?4Vyd;oYA$8Dw> z0DD^?V#4`pKs$>cFA7IE-T=Ijn|Rv;D=`ma>3i>kD`Fx`6^|kUZ;OPKJ}k-_?UK*w zV+0sePY5kW55yxMUB7iaqC?IbSoIB%L}^UT*7*zaPGF5Wt_aXM=*7?rfQVAu z6^QHB3|%=`$&EeaDF+=smVgleKOVHUK6_^S^x4YQj6dX51Wft znCBPx2tf>T&O6PuV3ZP>bl~h~s-PVmoM&yF=QZq(6?Q?7&dcSKJF`ZH@nU<#7F${y zE7MRodkB4OFNZbQwZ*t>PI(UrXlQxq$37HPLD)xF0m%tF>yyFFJg3WGSn{|D6i=F!b$xWVk|^{##7 zw#&omEyM^)JsEUNoHThtH*^G#d4knl50>YX2051}H=)#nHbpphuYt3vgzFci84x9! z9a4?rZSS*Vx^>l+^}6Mw)=? z=;T70V%IvWFZe(Mk85WgsubPNy77QnN!pRRCfsPS($3$#8Id9uJceXL)>KdNXU5kM zxSp`>Pe;V+^?)QS#^hy;ceC#&7_ob3x?z1m#hhx>z1CLB`C3e@PKMsy4b~RUZlzUE zGAyntZzx;0SX``QMWl(tce(Cy-<@j%XB`(fsMVE|d3`kQXP7P)TfW$05kFrIe4LsG zh)C?uso(Gt10%F?o&+C0J&X^H7`H$F__hH1mgQ4lT{M5v z*0Vdh;uk+>g%Y8Qbp}xTWV-A{(O`DJ(Li?UFkQC+ygl?igQj4u`&9sa2o{_Avu63c z)C<4rG{Dld32`M9H_o#twHjo9j34RL(L#|ukQr>oh%t${UJ;RV9$^etT(fQ`AF^TG7Cy$Yb zM}wt~)im~uiTwF@!yt(%_k|Zbg zUAmk^WA4HiYJy{Z30Dk|of#dsRdODk4)#K`9Ipe zIR3#8_Uys>S&HKVBOJ$1y>J4E4&M?kF6Tlp>UXABOb}PV2C&*R+F%r19Xc@V!Mizl zLl|x0$YQ#&9brAO(MZdSgcyshxtlnI$dBU9-(DLLTZ_kSmLL1#8`pJVLt;s$bVd;tl~KXpBNARSK=MkFSaD)r_u7z<0r;n^!x|RQl>qTBxhvQ zv%lKk;#T$xIo>Y9LAQu*qgW8WBYq>t^+m}tGl{fvc)tYsF9_FZw{PJ>BGxVBzdT@<{1 zB95L=veDj}E|uiOW!HFs_kHfA(^|n$4tve`fYJFV7+{}1G&u63!+EKSiznFXW|y+; z**=a}s59=^{at%BjJ*cMyt+T48$}GE&)et#J-Nx6g$qd{U7+3-Bc7X>zH;t{3*GNY z`$5?_=MY#G9Q7MY%=gN4WActF)bol6!Bw;1*^yx12AmxZx$~jx>@$8aI|k>7QtXk- ziI;dsk(&N*A1$2z>-Y3=Oq{<#gs1i}L1K4Z#asU?k1^+Q+pH?{d_Gk!T%wh_kY&HQ zUzh|DE;*(b4j>bhM&pwe0gmJ@>J0-cmo#~_V}{|Orx$%ENjlu%gAb9xhIWK}VozS| z5pMUX$<-ce6<=`8TCkGc^8ts4RzP2J;|Yh3BO6wdk4-MshJiCUv>IYiZU57Pv>gnX{8JrKvqCYF{mc0g`7iD`$q zjkP!gwr=m0ST7_K_dx$Pu6sX%TqIFVt8o5&GQ~CleMwFme^j0Pntn6iNF@732_3>W zPn?UwVmf%5L)-p7*$Om#Xr51qSCl(B-0`u)J=Tpp9-Drl0oIn?`a;)++0TbhWq6wJ zjA`Dd2&%bK$!4OrCHdnM!ENgVS@T%Ej-{%U+6MxBo8rHT;9GvSE}WDW)w{u%sh>rd z9q6xTNk{CD;UX&G#YG)Hs*IbPy_>@RAYxz#nC6DF*E+?C0ni6E?cl z?nZ#O}bVsa~=|GN{#GWJ!dPd-+Ck0{j!YZty@;KhIO z??W{j&#SYjz1h^c#n>{EJf&gn5d&K>2a}Fcj1dHZWo`9T%$yo&ulGJj4bpQ;o3Z13 z#aMm2MJ($K&aFK{5qqNRa5`}I0YM20*LeDI*NQAV+!ATM*^pwX4T{#n`b%`$ zgbZLcXzPBnhe+d)DTi67H7AF&LD0~b8)GSzCM=H+;t^zvjiS@uO5%-t8`i66ZT2GP zUa0O2GHeWpoVGU`L*(bIBa?EqP*g@rbtB_Lpp$1VgA!<-PZ-P_!w9i6Re$i+1_UbY zDy_xCP}EF1nDRkpAv6o7mE$9=g?Hp6IGmgcC&4(K!`_gIY(2W3s>y z4IZwwlr8t*Jn$`TvqEcTd3gVQX0`aeE>o=fOdWcJt2q{6!|^QY06L(}*ooPMdcBE9 z=*v3MuvB(R9oya;jg_2;)mX0Nw7c0`&ilA;cnp(kE-Ti5gj>W|DsUX(bV`(!Q$Efu z4gHyU?+7v}cE2VrLPYFi9syvCo(An>owNuDFk61QFW1F-FN&C|b)}BKj^bIc>v6_t zjB`0~x~wmY!8)Vbn;0-Q!i@1lR^Y_`dpC>Ea>rb0-Vq4m(ZFIvV?IUs%RTx`1bsd1 za=Vv7mCp0kYO6m<+LKaCD{}H#)&1zB$Mtg?7%SxQRU6l-uj0Q7{&9jj_-O_#Gmzrx z4c8KIR?yy7jWa$WRtMapVZ8+FFBDy38RkQ{j_H#zyTjf@@hJ>5Z+rg<*c%tgeAVU4 z5bJ`6rrP>dERzM zWrOuMo>0aT|BjI3SM3Kc=GN_FSiR7~yy4tI`g18?AU&JFO@Co{3wHr&6JurLWn=90 z%EP*nR4zgU!V#_x9U|Y_=P)u^oZwj-`aRYl#U<&P#6Deo#&zmV+;```&a`PrJP1ke zGQ^>Vw~BGj{&R6`LcCRBalm30!naNkWxh?FGxTHqO+a?+xb@UIMS4Bl&XLBYE$B%q zEZx8{qGaQoP$L>#l$Acq=5ueI%LsxD$jlxyhiF!dKg~hdi__S1KV{%eVG)mGF)pvo z=gKy3$K5iAWXaAdBv4wp|PV%m&- zdmVKMddqxAo~{fH)Uk@q*FP9+J31;2QL%1~OXW=tGz3KP0&I zRpoRS0&0{Wa~=BIM0|Zw$+6N*qq%n5gItWBQjIZN5oMoM1Pc!<$~WZacz5KzBsB$tgtoOkrxv%%~_7{}K>L%YwenVz_=uuE_9;u9Z1*|BmJ7pg#7^BY!gV>8<2XF&=L>ikt=92Sn(s?qvgL>Ns8y z$g6a`m~)!RY9&A&s>yan4?TC zNPFBza00XdlCZApJt1s*je++_Sta7DACioddT&%R41?5It{s|diz~J}4@usDH`^cn*VJs#SnA%~j zvRE(=XB}`cH(-cG+j6PaJXOB%H1gjWo9`Xs%XI3x`S)Sqg_>5x5e5ZbC6#x3pdQb+j?ErkTfzubX}5u@K71i z<|F$$r|G=zW&p=sM_~~kFt&nQka|vNSemp|T><3eD$CU3aUqtiw&Wm=`zRlkB){S8 z{6U+zj|^THIodIyLn}6PCFfc&C`+g64bcFomGjiv21>7wx-q`Rg>%)w#~3KbK5Y~^ z*RDCh=5+M0TXbLscHPmQ8J2QO209mj6NN2=dLE`L=49t(6jW?<{kAr7)!uL;vs0fO z^r`)39&BA*?C&cKA3PLvt|C{wAp~{L6Kxx1R>?03I%Qx3=cH|Qf#{Kv^gU{~-^e*oI~!#KCuzl;O>Lq0vZ>5diw$MIq?NBM%YBYbmMg#hdV&Pe zeB(-0=edk4!(kkVQ$P5~cp*@wnQNM2WGg0gro_>2Y3^%YYr6}0OC1xLxYetR8XJ@7 za@UZ_-a>T3*ktaYVLKwK-YSzBiz>Gg&PtW+5?Gjs*z!UgI7h5;Pc$bQ&abd0We59Y z6@9}qjoT@>97pcAxb&y$vToBq#X8b;0Zze32mg^V+x}?+M-?s6i%J^{MA76??aYUQ zIXUIaO>(W~#7cheaKwFY1LOlch1&Iy`jG2m9anj}VZkwOxEam-F(vFcoiWTyeY(g4 zvK{0>M#B&7IhM@2URTZ$*z`Z)pl8Nh&#FYo1FVfpzi%DplOa?awO*e0Ra_I@p(pya z05tA8cn$2{6~bEgD42F4;CxErMc4b#zydCxQOBR8h+{(|JMUYBJ&qnQQE}gKQGC^V z$M(vBfWE`WZ7eGsVjRb2MCl0s6OxEw-}Yp7$y{vL(6>fwoE}t*BWrE7);y)!94w%E zO6LQk?Z$aSfuiVE6s zVjjV;Wjglgot#5H>JAL`hL1XOaBmSb&A(cAQ9I=o3dHMH1V?yoVs`9ovG%puT$7~~X3!1*-A-?8sQuv{ zd~)k&{iJ+J(2hCX?dCP-z2wzQE>e6cqB|o5ajx<4FZr&VT~Mz~Uz4-;Ebb*s2?y6a zzs{_i-2^z@9!lYrqcH(-oyE+F2xw!7Op+G5Nhqg-14Sm^fW zM(x+^l-<_=?)}!>k0_jyLT6L?s$`C(H#5%YK~6`6vPRaYR>v9R>Nf{Pn)Y^+3s|x3 zN;j+xgCxf_G@}KtctZ?`WPnyaFoB#dq1ouPxS_th$=vR!7Hb^i9e6*PXH{&x~ zy(@V??&lHMI`Z7kENl&mZ${ejfVIY*V-Az%KZ0GIgHL0zr~bN{p5m%%`if1(^KCL+ zFQT_BnsZ{!^Bcr&K19m*dwGq1pYfv%`#E}Y#d@xBHYS3T#tMxy60ciUOyRa$Kqvf) zC&(qHSMx_+nj4Z@B^I1L>AXs)5d}x{F@SJa{9kw+gs9%{RC&G6`t=M~-#mKlrt7o8 zj~H;M-AoKQy?*#$=+~%vw=_@gW5yuJM|cyh4uQc5MDp3XH`N$CqXlzKMfN-h&v6X< z+twJnTZ=EirP6f|K4HQ5ZpR!NyZlgByU=q1h!g(pBcq1bp&z~HrxkenErZHA@k%~( zy2j@3bta64Pp?wPey{*Ja+~ZXL4j3K%!CUr+yq|*cDP9OoL;nIs3VVI%eZVbhkUdw zLIflk>v3+9fv^^Ih#3#&kug;tpRUf!M`M)n{v|)3+`cR=ZvEdl!W_i+7Vw+y_{U>C z`aph&mw85Q?%l<1oSX_za?SqgKH{xwT;qR`v=s$2P1j(i(Js)#oPHFx&2h6g(ouKm zV*=3^cyT4mlYs7%e&t&@5Gtv-U%??4cz0FfR&x{R8xJ+>TDsumgk2lX8lggd`swLJ z``TDG!oHHvE+GkHiyHCUWi|X8rI^`iy|oIpLP@On8#ll0JCQcNsc=QKTFZJ7EYNR? zcw8WlGBi6+FiU^d;J1=6C#tPeJLM$P2{k(&$F`k|h7Y_r)PAtR&0*EMzH`}{b}sVr zJZE!%V25{)VVis4_1wdAF3pf0+e&I3Zzm^8)!+%O-_pn4OdDQ%K*Y_)fg|K~#_6cN z^3XQVD-a@5c5PUE8LKJ*<>lC?(Rsue$GO!6QfhELK)J`nHhg>BO&=I++0LZ(vzF7bGF8Y*sOKTe-=5)Aj@u%( zUo98IDGV%HYFPD8d#lhY-kK7FAT%FXYeQ94Y_!21=nbV7g4g8OV91lln8AgZ#nfO$|r<>p*WXYwM=zb&?ri zi{jG6K^GWbYuqn-Sm=1g)W)45X3yOWissR0*42zR<3Xk;*zdA=B__u9WUr$l!#Mp- zBPnZm9jC8zWOsE}-F_}0pXr=TD%tBB8d$c4#xXlYYbs!im~FmQauXXcRxcZ8e~eYZ z>Z@vEF>os{`%y5ryyU_4a6h+HZeNgLy&*r%%a}5V;5YZSR*X8W=t4}cV@*`IsBj^& zyB#PT37n!k;R_tF({_uS4F7QgtO>8Kb>~t3hH~r{wYS{2$@6xSn23Bl4TyHwe{vH( zr1xrW3=1K>!trHe_G*nT>f5G6@=!|?XxV+e4msc$$E&P5nnuF zIWlrPI?kcew2VhS;~Q3`i$uD#b&BK-^hB^Lp!}y*m`IPfD{MFd#0{$$|??~^}3+ky-(@;!; zW>U%LPmfzopVe!MDG0z=`6j5=Rdb&ft9?0cZCx5(_#y`+LrP9Rr_e4r30C`=qpQET zVK>rkjq-u-{AyAH(0yfuv8SB5q0jb?e6M>l=YcKpEsUj3^cXWltnVY>iRrlTR@roU z+Twd*zm@YT#%_tRwUN~%9qwyjk$%p*rj1upjP6d;4A1telyR#>1jMqdT<$r z)%NV8{a#%fkGjD4Klrv$S<-1nj6kJzlQRtv67IK4H`iRV_0xJiiJ7rK-G9QzCpezQ zJ*_`^s^)&>;09CKdD%S7Ui&5OPt@Dy;w!=5+4!SzwYuY6aT)^e&2zq0*o9MwRRyR1 z@s_ibvCoj$Sh09c1;*Rhd6Aa7U*u=HLMftpB)p&CVeS;PGw9hmT-pDVWxrmzKzWkz z6aMoeg2OFN#8oWyi^?nXEZ4b%CwchePTTT?yb$j$=4RgQe~Ca}z=fi1Y}%eZYV%$k zqXYs&74p{~ZKcRIsV}zhqBn3tr#Xa!H{rjjYp)@oy7g8s1_KNI+IrxomNRnA304W7 z%x!PaIkUd_veU||{Foen%SYg~W;#c`_gC7u;VJAmUAZqHI@_j+S^`bj1_8OR@;7(# z%pXbbbkO8LF)!>JIiSWvZ%}Q*bxS*Th=3SeZ5*W4!h+&@Tg4v<%qQmrbvZnfqb4mw zD?$&ubuB*uTOV^^L=M}3*Ti(&EuEk>2M=}3PuGz3WNvVah@Z$O$NgScypYem?axK( zxL38qIO&69`5=e>3QRj$G*ePevl&CH$0)`qA3xD=d0eVJIOK>)4?EUO=cZyO)zrl; zD8`$cT^$<$xh-`?V-lNb4#*}HOC>>X?h(Qq*fUa%@l2A}jNt^fBhfWZP}STUMCaCU z$)+!oA(HN+fm>?&0xKpZUQBcGI-+&+T%NVNz@Np6PspZYX^ld}B^}_PchU&I!Ke9C2vA?1D(z$ca?~rM>~(Fwo^~ ze43p^$OkB4(T2&j_AOZ7CSMirN=AE&l??FPA{?P~C2hLEHw3T4FMH&UZxL^h`k{bFOkG+lsm>J>M3h)pAxoMNGpqDq}^r{sy%B89N zu21{C&vE#?IMiOoU@Rng!Cai%8)q0#wBfW}Q?$4lGcz~xp3u0Rxm>;bVv`t1J7?Q}9TC@ij-k3GQo}0C$FB9L(splRhdA%~-2w-PVp55Ms zwS%b+zHA(a|D(}|0Pp6BFpNWr`tX?CrQqYT`k+SgkV(S+);=pSP4I9tP9ZAOR(PuC zM}RoMtersp))`C1VG z0O#@e+g~)K0GQ8hPR&bVY27Kt8g`OCjp@X9UYuu!+f?k$4y!p|%HlbMV}>LD$R_}f zoV_}Cw3vflN*c3Jf>oyoM06PJN?}0w4%V8R_2$W#TD>$I#BS2eLYlx<-@w#sg3tCrNY zAD`f^A9@p}I%Jx&t$6>LvSW==EBS9T@-|1-6!>{=jrwQ4=4Cd?KsSby>X87EVmpm6 zFV+oh&-juS?Y&&vl>)L#o{W!UlJKAJUIw~#e5&Zy_*!W{h`EOI?@3gMz6?~#A0ca# z|($mI8;cMu(W^quTqzhut- z^1q}Vef#55&6+JK`VF&?wjXfy0rYmvuZu?=NC*{wW>1=r=d0%#Zbqx62iPUF+4{QB z5;7k1Xj9%ybm#57Jhpc?zg4U|JeW^Ua=(r7rS!&%*e82tiF*3ST+^G}D$f`R zeF3FC?}jwV9_4+IRIc-dDmLYC#Z?iqOnvdr*9W4h%30Sa6>SiR24 zR<8u{=)7J>)1hK-NPVghDTmbkl$RY3kJa*=r-l|3u6eLwuIqg76I{jPebK8N1XK-x zimwRFY4x1USL?<~UQzyIW$qrx=iu+uy!@ZtP6PiqnRcL`XigJ{_B=k=_woFNJ0dC; zgXHl5|JHk^`32;Nt9zRdDAWc&M9LDa!m-b2thA%V0YOp@P*AQrr*W?=@gm#b@>gfD z(f)6F7f{FFr1Crm0xTD1g&m)eRO3Mt*UWmBWU@yB2ax!9mUPnI?34y#UR{qkI>w|k zhUk&|jEN+tu_hzxFk!1>OkKkV8g{8LIKI9$=W9M8FUMZXVe$6LNQ3XE;Z141IFelO zFJF}6d^;|jM%`b{bQS-Ok2d{+S6>+ti8$FwiR7z+$c)7ShTl3w|kL9^sT z@i-cc#k+p?W8|E%38xoZAF~VWS3>^&CFisN5$;>))( zIm=m6tF@MwKa&8roC|*oK20=yLo;*R6`!k_aB|rk1d#~6%!86;8Le=>9On!8lDA>P z_|19Pw@GVH*%rQSO3-7AT)HahfnlD^zElVdPIip~J2hjRO|Dpdngml$1G{SVz~XdX z!INA=mN0IXRlR2E_XTRHsagxfc3oh#Mcc+mx#v_h5{?7cja5H|J#}GETd!QniOGH` zulB@xUF9>ZA050XK-X6d*xcDwu~m!}-Izf*hZi0RkWkRXL#H&r@?Rqq0py(@I@#Jz z4SXh5ysyd-OSZK&PJb|2;`)!qi-^LT7>p5t#^7Qu(Ca4GuOQ*^+@v?V93O4;l7=1K z`#^$1JMqQ6J$6{Pb-xeB&}a+!q@1dF=ea)n*YYI#Slmgef>mfWdLHi;?nYkay0g2% z-(X^0?0E5httNAgJtns?Mw4%$#{JgKw)W;V()QgO;)by(V7w-n;(x$zZ};09p^wZi z!H8`>4)(^oe0Dmr67$qA?cd+~xihZwC>_^j&pch{g9E{>Ps4BWmvBjY?6S^B;1>eg zSyVi%j}N%Vw|zUrHFIcowVI`|4^LPhfPHl=BjXD_4(bc0XOn#`YkO3}?BY2$qI1|* z%ZT}O&mT8GVa|R!zjyh@3iU42kFn3w>|tQd{FTFC>FJ8>3ZyRhg8t2dInW6z%Swj=Qfv%DY3N|e_yqD{MJ(m6RM+lUT?>Prgkriz%XzDEHBP*o^^56 z*wQYP3o%Zu^X76JrQcu5(sz9H|mM@L6TM74G;CG^Q9ozzGUu_wVt_p|biL z7cA_$xNG@x4P|&$6jzY1idBPKJRuHy;ATOx(%(H1FozF&Z0uX_v(MyCdz9$A9!#k6 zr#i;gF0_ch+JjUJ=*N4U`sZ3@Ugf zbD59vv6-Iddp6HMV>)7S`8oc%30!0y91cy$2+)+w(@sduAcGtao8)tSyA3VoC^0`| zug9;8AKBva78~38AukG41EoL1Q)qi=tnT<*8_FUI=On_9z1nj&L@OxoHdV7M+@f!86bIGuXi^x;&%9NNHVO=T^zVXy#*IGqQ} zd~SG3cl&Q!#-J{9ibiks%3L>$Pw^`%T?$vqH{^AEx97|^9ABGajNcpQUG4tH2VRP; zu8SNVJF*u+5)5qghj=o8be6~3iaUlHP`r1i7 zhiL+we~D#vH0|E>AQwI5>v8H|+G~KbrG8d)7T=wtD!VJ$Zo&+Lubw*3=E5rG)ku## z{;&0~e;vPhRNe^w@XCez(A!wutiGK(tj)6tn*#FA5QFb0sPFzIFNDJ{?k!+)GSl=D z=;nmweSTe=#ZLh`hqH#uv4CW?L@jhY@*4!LK8{M8-s8-j(NfaWNZ{$#d^Y1IKb#NTVmm_E3^-NJcAg4Dmm%HRXW=6hf)feiIO` zeu33D=Fo7PUKtAqAntg=dUU&;=EjZ(GcrX~!Zn&3pjhh+-(Yo)x?D?#6oTiz6ttT5 zy6)cie3Izok@I6NapdFK`n^yxB0zZ_)uEC8ZicCy4r8mU?DUk~>^d(=gtQI8 zL|o-l$u!1Jg5J6o+1}!5b;nO(NU)IU?BqNLq1>P|=vluDklxH8I;+x8nSie3#J52W)maa^7Hw{qlXgPKtg|ZyVj+ zTtyzQoCBjT*AutuRi46#GcJ??pyTI)2+GlUew?vl+{@fX6GuGG zF3X4c99AQSx>eo$&z0QAf6m{0w@)`7FIo~GlBsMI24%w6iM}P>=Wo;%rjjXI2MBKo z#aYFR8J^~#w+vS~uH-S@WgHQ9(bK_5I88=n7$&|RrgK&2Yl6Ej*{Z#R{Z}=6uGO5L zGR>!W&I|y-ge}g2r(^vT504yH9}VQy7Navn&T8b6vx$rqS44bGuU{N*={X*2&>hd( z{>wD|z@0r<&5_$YYBTyLNH`9=+1W6JR$(Wdt;7Nh^3bVRlB~vaUdJT?=jLR-?IPdt z33mS? zWAMD!>eZGKYhDn@gQJnzo7%+5hFI8oUdp?$krPwZb0w?foj)~zCEk3s$ojm30c3cz zd9`@s2*_$vs!Aa;`d+9%DrPM|O4`Uikq6?7F}6wY6#@U3bK0D{uOE+tdK_n-8rONm`iv6EwJM^kKRf2=H~2En4389Egky=KG2vA@(2_5hGoVehntBEk9&7| zlnCgIWE9FLPd5vb_l?``@7Qj}_ZSDhS>!)T>J3mT**FIM1sW4CpRI24-0YQOi8jS2 za`AursJlZLayGWu5t$3BgGP={v}u9|pCh)vvlM0?RK*7ILN%lH#gGl!sc!4G!&!Y= zfR4KdrX_J>DFCwwRTd;|IYwm(>=^YzvP?C^K1`Z11NCHCLHwF2K4DLs{r1&Iba2Y_PuFd=*Rw+>eDbIX7`E`-#&mmg(c2UB%m+ zGk8NQmv?D$9b?q8>tXxa@8ySi?OlDSt^62x`ETFXM66>oy=0U>-p92Sd16DZZlTgS zrHc7!9(t_T8bSgimidUmaHzY4wr;Yii3N&pu^?vqFapjOod00R^A$8!CONM#XUJsp zSl>3KKKG|&+U2?7dFHBC;IK%+oGN){Pu|PDgwg%}p-*9iH z6WD?^l&w)}?;ODg=aUnsrZK3{oJp=2M|6xg85mUKG=9!bSdhYO9Cs%H!sfWn7KNB> z=dYW$hOXFRHqSU5XA*Zi$Zc+CYw2sCBfe=g84~go7%D*#;>Yp6(WiK_uNz(|$6+JjTn`e_Z&_zMSP1R=j8(7qE<4Yz!Ax%FEA!ZL3TZztt$-iS z18xu-9=>kA@8zqop2~0PvEoGSNBvi*D90Ls(&h5u9$zw#;MUWzkU0ilr*ZN1s>nE1 z;Ys;C2nUWhC|BAR8uLB*iL|ux(%0J@vnTTb)#bTi=b5-Z5-3Sw0NiqeN{m=XoCQ9* z9q9Cyp3b}DDvPc>HvD+A{v*S^xz!2*xih3rM6=83@Hk+^ah!!s<|waT_nxt)06`{? zZnB^PI0($35E-xM8*SEyakD=VKcl6iA-U;o!xR$g456$$1?EfNJep$pQ-U@#;~OTN z4W?x8)etcNRzRu0Nj^70?xT6d?>+mg)%Zrcey8<~KEJ>f7T2#CmwVQG&=(XeTa7AQ(1p7*m3(t?jTyZ><*Y!G+V0Pe7sB^KW1uur;X&FTli&j%q7!tdU zjY#s`?#a2rL;tyTu<(LJ@*L19Wb>%7m_^;54en>?m4xp|@M_{gDB$P#T=^AMuzUHMfVNt zqZnQ+Rlq^~?g?jBl6#uVd90A^4-sz**eBf77mbZtTQc zWr|p>L}i3vZfbLqIoto7%`PBBCO|g)wr011T{EBs6hh3 z=$pNcVPy8ldepENIgC=STGe-)bF}b#@^ign$R0Dd&1XDgr8s7zNdjNBzjNG`A=W9x z)FWvP`snh8VD3|3U4U`xoiA^UIr8PMUUcxR9-qkPE6NW}{wVp2g_z8~W1i%CqR%oa@L)1CEC88@BRcOhRDKAtm@iSvWkT{zwe^+wk@ zxMBHF0RA|=ar-rxhq*rr;w!ly1@hy;7gshvK8GHl{=xO$YYjbUkR~2^Vn`pq*}wSX zf0^p-KHMEiu0Vl>C)Xg{baE9o(4Vi8f-;|~4%AJF@CDyV@$~|}fDz`x<*-*d?jycC z#Fus2kS}A|k`?i+@cs@~jvR%}chn(5xg`kw+>OdHce4CX^_Ml(fH-qvbjTPQd2fVMh z=1c&U8@^Op+7HuN9dw}+u~2Q)5&U`&HR2<)P|khUe|aDCc(rMLI0_gcJld@k#{U;} zAjl&KW6Z_vtrrac%qHRK{DpUEw;xI^V+k2(O$IESx`w!(SFlYRVwg974ClHcZf}9( z(DyAbFY!L?26q_b+g-eA>^c*y&Jx= z4gQ}#)bRR=9C>T9#N`o4i7xdR{vlvy8hAd{n%CI@TIOQQnL9^?yo)Hscj5_IAQcmpGS|?sL z5A@k=u0utDOrkulyB73oRmu@re~zoht)#GjmE*?l4zr4G$m{tw^uBfUiD63PF|0GS2;e4 zNKRK8&SIQ+GzQMs;}0~lqTMhd=Xdgk4`eqUcEN|2M|{@RA{yd-x#PXeBsVn(R(d8_ zS>;o2uzaJlJN=Nh@VyEXV}CJRN-okzTBv^RlVFfKoxr%mO4e=D-KUGnfD+WCH0|N%ZVNTNGbvE_ z{tDwD(t4(EhK4#AAlRS-OjVaLK34nDpD2Q$;tGHdbV6Pa`QEYhuJ(EQYWcQjc%{9c zFQ4=@qJvLczag{PFtkvnDW9qVrLu37k5#qH&6 zW6yR$btR(xSX-~m0*D+z_+Qs~r$YV3j#sOKMc|c%pz^0TiFwTUifd)iWWxllx5}Z6 z{^EY)_Twt}z42`?>0vF~AF>}0@D0K-MvcUcD{hth%AA3#6a}|Zy&k4qQsB3__4m2$ z@&dC7j~o`9;{_=G`?s|8!B;vqLEw0~8RwZ|ibA{=vCW2sJ=)jSF13{_eMv62Vl z-sx`~Nigo0w49#Ru;U*J9^JS(v={AoUBJJy*v-pE&U3u*XBEM7uFW8lvm54Tx!F%X znX0{+vVxZOvrxb3Gm9t5%`w@HketNzS1UMk<+b_WBIh|@zjz~9tBK{*k8Kg^4Z7^{ zcMW35T$qRB0gKhN{KpCl5rWi%0UwUw2JehO#d2Wk7*Rnb3;+N( z#usBLI~6rmPsiK94jb*PH=L>pTwsdZO16?mYla)SEnWr)oxQwf*OrtUQ{^Z7Sob{_ zyxQEcG&zrIYxg-S*-*CPCVqUyT2_B^C&<5TFWQfOLrzR-)9>nnrrFTy!H z#!q*}w4h4%3ttZLY7=9?$5RfD-_Gt;?urvN+SjSF+R5g+VqBK%!j4LHGatmt+4i?% ziFu93O^ww@o=_0BZO5_G(VlycMVo!@iM!dqV&i#l?NJu2LVhKJEg$%4Sw5alu2}MV z>=`rtvH!}RIqUo^3HCA2!=?O&-=WH|NW_1p2ZFmY96qQ;(b+qdYv5tK<8ZVV4~N?L1LXnE(NlS zzADe|VB3(qSGkDYF9i2z16)Uc6W22SP10+R&|soGoGg37Nqe3{U*rFs!~JF~rbIs? z*j3A)%0J?)lRV3}icw;NxKed5RpYTiMY52+IInyjJ-mvmD{KD;_1dU1gshS`7FpMx zUc}Y@|D3d%gPOJE7LMgK6!r#^2$TFzWTH1Of5P$P^9K}Tim5o;@CEyq!i5nYJT}Jq zXfKYeNQqzRQ{V#Y%rM<<;5_lp`p&=Qrt%mBf!lp`ylo9WrkwMChx&0ff_q%fdj?r) zf}W89gGZ@spq-99w*Park8z-<+4sXc!k@kS`JAj0=dPPscUZ4;_gCV)&vOK#l>H@P zHS$9NHNA2VkhY6NAmRf!-K5S2z zTpU$gwHU7>Yglj)=e2CZ);~sk!xyo(hkW%QQf-ku-1`Rs*i-JB5b4GeurGVQStQQQ z7BcFYeql$5#mwH_Uh_!MN!EgxqdhkgXr_LEe{tY(_9O|U|*3rLX*+gvn_-cY$O4et4aPe`n+{b#d=COFj-6C>4x$k*)y8pC- z=J^hLl~n~7*?;s{_FiIJ^-;9!O)i9+OL@6Eg^9ML?F!^E`RLlYv8xx+HyC33UV?ZM z2kaiE+FgA|gLQS6hoxK8YMNiSg(z^C8-=*^eJxbNe6HMBD;`-ru-VWJ)ji+p97e9! zYjht2efj_Dl34pi}Mh@sRQBADk9v_JUL4wTVvpwWVp^ zwFgV*@T-GX?A6KT?Q*$J8GTR>*FKa>YStr9Zcy=}6I8x^Lk(VX-{93paUjmN`x#TY_^#p4ALb{KqFz6x%B{8*TSDhNf zYq*DbKy1mGm7DxGs;LGI8`xWt6*l0?IET=O@x*R0)Gfr7kI{^rVh2Ejuvvv~ci2s) zT}1OD7Ix5`_(8|*CLUt3&-gM{8c00)N59#Zy|1eie?b!k`{c;E5UV6U;EJ`yX-w%V zKQ4^e6bl-{SUyUFpOC|5WAtySJzoS;sp@P*U<+Uqao75ob$w2W3?Haoe)ylZeV<9Y zqHa8dKPu6bpoOrV!!F8OoHO~7<|>X}I%#OTtu} z`)T-2)Ce6fniaDjV%1}PZ$iE1aU4F1WehzO)_?sroN>r)4X(NRosl?{e&@$sPn()O z2Mxrc;qnN#w1Eb%f}qb_AQ~H(Tw+Z@`+>_X#D;)yM()wXHffuhoVc;Xc~fIUTq?jC z3?JatkY(4_WsMy+^3#cb{YRwoeRhROU(W-rFfh~&f6)tZVKWZkZPdqn!*ORZ!5#oS zG>Cpa_)Bx74LI>atzm{O^z_X=IFW~8aYcj8&RN8$C_R~uwMxqC?#Z5|R>C42=y`3^ zQxF-m>FFLK8u>S1<;y#0u*uHJH8$s0W6B&N?1z!)=vJ|q4DDdC9C3U$8F(9b6$4$L z^u$@!)bkM0iIapT;uis}7=OT^vru@k%>^%+ST+LKF$xE>1Ih_nQ=#Sy&Dkp?l%no! z9hjMdWaVyf1$gh=k5M<#HNo4Rj-_E~EpMB3?C0q^YRuY@ix#^**C(mQx=>1R6Pwnw zA3P&6C5Ykef?Dc|+0?K#d6m;$9t@%8h4#c#`6es(z+@iUVVw2af#A0HH5j93O0P?1 zIQ!VqQ=|ktJoq<)vu*C%8Oll9q%5cv1i8ir++m(MR<+?d-phTP_42Z3ZMj-#f$L75 zG)za*)J~F{hVZehQw3J5kx3r+^V~TRaLw$m^=%TXBFys*{^Cb{S_Fw#FHPIp9aL}< z1kL_tR|UAS)3MPT^eT&u;g#w>iHBi3@9-hkrK>TAoq;q<@J1f3(Zk=2Uh~ZOQu2Nn zoz@>?UHGJdgT1X+Ps{>VOEUAw-;l*Xtg;Oh-`;sCt_QPqpY>k5E5=RSS7Ba(>PT*4 zs4f3Xq;J&jx&nGuT063n*IIw=rvN@4UxXnKywLF8c5i=7^YrTG*mZcJ4K> z0=Kf?$uXm~{-_zhjdY#4*dPvU2rhl53O`X5#m35`y<~;%8}LL9Kb#Uih63ytv0mxeCM1 zqSVpj;TJ=>hih2f!q z&1%kyba(bd+a7Fd#)xGP^S9b&|2o!*K6Rz`HY(maA2m-xJlDC3{VY4p+a1F@wwd=f zzk6IBk?e8qcMA-fAGjHMlz^-A9nqfw+}0+0TaDvNp6!qQMIj)@(!1I=Dl@rEcslOH z`eumVoC2$~g8Zh&$2tVYpWC^~br=0^JoI(C9l#ME>)8M^?$UwtH8-DfJjKr*XUXbZ zHzR9_#nkV$YEYAYW&H1Q!~R{4ZStQ{&J!{5p2l;XIGXBPq3~S1d9QN}vnI$E==z?RF*G{*f zlNz=nwu|?oq}}wjh-of!^@3pMpG>#=PjabGiGQRZ>~PTPwvS1H1EO7=$9VjTKzPRd zXkI$M>38$J&k2EoIj%9o_0yI{f;fr|VrEdNKO$mHK0P~orVH++F*2TF2bnh)ht5|SgwUP>4_fpL`SXv();17w`{skY7~`jegx$~}#-7f;%iCpx8CwRZgu zetk(+;G@LqagCL@a2Ai_W^arzZ>*2(kQaWQ@K^hWkmd=QjE3u8McX_U} zM~`-+8-hdYDZZk6HCE$_wYwdwTU?G8vHD{y=%pCC&O#W&3b30F>WW7?<1S3^oV{1) z;d;gMIXRBwUdiEDTDBg|vo4HhD#vX{|0uQ5vj`{{l1u;zVOo{8BDI7WI+^a3&J$a&DOr@RB#CeDebm$DE7=IHS_ zSDa_^ZK<7(t(RT2k<8KYif27uD~q+-5Cw^(`?{DOVB@K-wywn@rOd6N_54$yx^d$mKY1CZc9b8tw&$5OLxxLv3ag z-Ad5#>-b(IT=}E?igp2daM4D0VXuXIXRZXcmpV9Zs};y++>dRYYn2<1HvM`WEBm$V zRi51uL2oF3eo!~Uj7dn4xd5_+vYa@nEKal z{qXK?&K_r*ZhUNH_P^!Y#>#+a2AEel_qybKd(fo#hC*9I z`~S1|t~-}Cy>`&s{eH<#2nkZy;vk`HDMBEA<}SDc?mI$=A0ZMF$0P~_fubn;?Z(5d zQRQ;EPV4aW)4jjhz1FOUvtJ0R7J$sCy@4G}* z<}v8B%7g286Hbrg3B7lPwwvCls{Ot~s(5HHEa1=Qwx_wVYq8UF&-Kb4=Pt&VpL5JJ z&y>khcO07e#bjb_J)G17_Bf7}Nz3yJ^*$YEH;z6%HcA+rFMmdYid<+%KIq69b-??L zxGIw*!DeSy@t?9Wi9QT$L^0bRHz*u;t7C5$NnO)?LF|mEf5fKPj=3YL+u!itV4aKC zH;+d4GPhWh?D4?~Si1Yz9K0r(tC-8`IUTdN^=*qRuD!2`_eZd30@lM}j>a_X0=~B( zV|Efp9DEQr-81MZV51Owjs97l;wBqUjNk;*+m!sq7|T^n6sv6zqU%Mw8AFWsae5E^ z2v$A4*zTeudKV>e^F3bZfF*k@tjywYI5rI@C-aum;l!W#a`%NKo(RB*oDAJ;a}cQO zyaqgA`hntr&nPLwi?l#PRl4T|&oK5BZ9>}2Ao!a`m|gw!Oo-igmn+}lAa3HG#d|83 z-%FKY9R}t|VbMJ#318%k0Qht_K8gmtHXl?4z*Hj@SliE9^Z7^5De=oVLOa<4%5gp`2}TQRYYmy8O%Y4GK%{B5@F`9UJm zH@n0Oc;Ji<>4`O6{P^jMuA?a_X8UNL;riN$b%r-ndKSc>rAGPhBJpn^5iVjh0Rz5n z)QbS;#P9f9Wo6KMH6viPD+ZL=+XOVm9_s+G9t|Tn!{1PXCa(6-VN8e%^($8|=#P@6reQG^_z`Z z>=2iGcudyzShTavW4xYnFGE{LU$}gn_68m#mIwN?Z>Qs9NQUOm2C@zy?RoMz;rnE> z&`KO(=9{iD>3B+)ZN}bE($a&+N7`wRJGS)L7?&fBYm@|E@wH)Yv)j)BB1e?iGc7P9 zUjbrg&DJvZ{Mn)z^FeFXvy)S(KZOVlV#9JWGER&|O!{=boEi1lTMa-7>v2|PcgJP9)10ClL*IT99ZMH9wMhZGFa^}lCjM=Mm;!l-Vy5tF=?hbpJ1`% zYPdD22GlNe(#6AXf0Xfc5f_l+<%#EcZ+F_JKkgA==PME+o)VK+sr^LfacBcu{YiU1 zBS5!pblX^PY=4_2!h#c`b`UX!!;o7LZ)`nMe|9Y+LCJu0-X@cWapF40Z|r#!#eq)G zEgl`(;0q#lF&FqZJI;vf_6%lSeVxgBI}Z9VQqVVB zpg`KNNpPCM(nqxTGu8HHlOpO9bUc|?;iQq(UMBPAPmR^j({as=%Dj5T-~uxI|n~#rZEeZolV+V zqvD(!cy3+kwT?!GvyS@#EEf%9HiF7cM41nVQf|;U8U2a0_{I9yag}omvZOar1V?+! zWieA(9w!45tUpgxF&U~r8y;(IdNrRKXZ7A}hxm&M*6ImQ=-}XzcqnhWcFh8vZGzK- z(P9PSTfOG{-EIVfOAPeQAj!S5=+9KxH|-$D@a;R$KmY!|C6r zLdd3P+{9^|>fh>3Q3cCUU{Cf==5VS9`QesAGbal^wyM0f?yz!S&u)KXcBv7ByzR0-UwWy zwpxu!js?y67Ht5nZ}D%oY?v;K+i;?HDR50a4(rX|GA`^4Qv^moJmX06Tmt|Cq0nEk zEbWM?_VjIwM1)QI)qW8PFdPZ;XEu}+Y7Y`o#RQlSL@~*6pcrT8alwtJ(>C-w%wPmT zFfyL{dl9KgE(}BoXm{+vgzGTcvlN*Q{_<_+M~|1fmeBV5Z+{3C&clAQJcz{22le!f zcU(!z80is)mTjAAc7;hny9dpg`G)>=%KJq;FHoG1;@qq8h zZ?;XVm;xHHlyGm>pYb`ad#i~3TyreI$2#TOy_jaJyTv58D>HZ!FD%s3#ZI?@V>JRA zy>k!$vlwP_t2snv_pL&FNTiIP$41b0-4QeMIg@vEu9M(Jlt{%Uml_##e$r-G$~~6h zM2?-@>)Fos^qJ|r%y4TowDREfqx9l&;u+uC9*bghcYa>4o%9P-XL`bWenQa5?`##Lv#M95=Yqs*e(ajuXe!J^wU!4~*_5 zCbx4YC%5}iKNsmTXC)Z9)$`l$h|LAZ3!CcQ>8k7njb(g=zjKX?BY%N(5`!Pu46m;c z;0X_|`9l_F*1wosa-g-XNzse3ah`B|$6-T2A#>PcMxI`O+(U@+K!n*tBf(VuP24yI zA31jXjg+mw)r3Ij^}f9&wioyrY;)}E5f03qyUbISX&#Q=I1&^1^)bFMjvCMpZ)lcX z6q`z!=0Frdw_$QVTQjaqp2JTC3)-()zODKa56+=+^Sn_v>z~@pZnDjIQ@Mm(c@RFG zb0~OMwQSas=c2PWf?6LieWOf7dZWeT#0YN`;gh>Ox7wAEtr_{xFN;pj^Qwax9%X~A ze)|cY4Dt@N}ja(^)4jU&q2Y}AmKzAI|p=vSB$kH8^E507}e z*E$Zb^)Y$*x_z5^;N7KAa`tNe^c!!j+gc$}p09yk(Q0!u7AJL&*b|*O7AGFk}c+7}}z< zWnZ%WO|DDvQ-FdiSrVmW;w!#gVL;>!dXVua1A)aA5#@i#_3c-DJE<(XnrpP>|FW!#DN;36Y)0~=tgdYfo>*^yp4dgo6PpZ! zu~S}iDZ(;EqJ>lvsR`33Yj*XAH^eZ1xSo(*ve8GPs-hLfxfeW-LNkR+jkgz9-if&C zr$IZ!Nz<}}Xi5@LZ&v)BxqVx!6SYqGK!R~L^{i!YuQqM$o2JB7V6%K9U-lv4fQKDL z$+)1_cm+e4jz1X$L={6j5I`tOjZO9*19jbsuGMMPlmGCP2}CKu zg~tg_4a!sFY%Q-(+XZUzAGi*>`8lgMyj?$f>v#05X6~3VVY3PY(<7W&1XzK1R%?2EJKNSj#;_`&jDvQC z^NU>f>GdCd1UejqmljdpTo1gqOP+2v_SR!6z7EF^_D^9;P?u&a`XZ&1D~hC-Skx zIEllpo15(}wl(ve=RKG5;lc+G{Lv@9A`JUAO`;9SdEd7fL$-S9U7e%|qH0{<|zKbQ4R$K2T*M7dt-;+PGaR$3zW zu;aND9$?4IYR{IpVR!5&r?`-2o-)};*;0i?C)@gw^t}v!BRh+cj17%>Z$0RJPj3`L z;DrFKHmtRAQx1{O?>t5e?ccaf394{5ClxR>(ihE(fKvRx%2XC2q$FT!zx*5-`gWBe z$B_O_BnW6|xyGAYegocYz(3w1P%F%Z^Wp8$u0MMx0qEFZ1QXfS7y)!!H@yJiqriMP zoceeDN1KStKW=!QwY%{}Eb~@US#xQ5^HNygEqy#g-q)|rN07ndW;2etMVm`TZCHy* z+P%0EO~h6I+6HqrXVrKB%eHK-N^t(@%BUcFblmOe?3uf`C*&Q5aZj*bUG2Qfjh!C* z!1J-dR}~uGM+pMrhLM*2FWR>2a7~=HDqpI-6B?Htb2l;UyzGv-wSAJvV(=Vq^IGdX zxN5m=Em-xv#+ zS5dj-nW=v=IWo{+8~kJgsNvq%k)QoaGilslCln8feN`fcJPy3M#4W3L&qAEv=X&{D zrw;TBeDkO!$&KsHP58{yn>ohKm2dJ#UE@s_j|H24QfM_C1$nDUTW~9yiPeXRnYsR* zQ}3P#FFR~MVY>E^XEe^K{Y(chXL3gT#K%{BlOm_gjkZ#d@z6dY2KGmtB<7Pujn;;A z?By;})sM+8?nDNIqEZ=dg0#DC+pKv&@4+;g%-ihRtPk$74q#({ut)gvDjVbHZ0Zn2 zj*}td!Eedx-#3B)0JrgPY!gcre4e~0nBit}^6Q?t4;SAd#Li^e(E+>aeGOF zdMVnzZz!DmY=rDLX0%{|joz$-TZh??v#EA?;+*&_)tmhKO_ISR7t|o+S{IR(c|;Aw zap;9^`6j8?wOG6ha8+_upnhz_9t^<9)Maxga(oeh+|sRd+Ad7jJBDy%2v6Bo;xESq zWAw;Oh6x9w4*}_BTJ#V`Ed$_%G=jaVaXo;)Yh-m+4}CF&U%dh;-=Z*IQW*mJ{@Y(` z4)M8ct54YDfpZ9K@eLNSkZ(2V2EVdtIM%f15~GHtb>fwb(Z&jm#o#bvk2qDwaSkAd zcg+%#liWAy`_}TtZicP#m+>QpD${_Fdy%+1Tc$5_(&Y(jd?!!_J~0OD+p$NjxNtEv zX=}kRFn~obssj`Xy@Wv}*#;5y*n3;`sX{L;h7ayo#W3$!QCoG4$d%Q3=Vo#4;CMI& z_F<2<&6G(!hVAOdAgxrj%=!9V7wc3L7NMk80T=4nm2o ziOFFS?cvy!yz26zcrhudbts#EaLL-*yzj;pO@1sHIBe1-u}86qI9@Ls+hTbJ98E7Ij8%{IaVRMhY%te#Y|^i7XQ8!< zF{D}tlqNV8+KY!C;~f+~o!~Ip$+&E#vy7u|k+<}39f_QEozPU#409{5gikcgXI4#_ z>%-(ecti(AO-Ji8A& z`^pzm8N;MFdgu{IV?RXp^o!o@T%6)9&ULiVp7L=BE5?u^Hr9d6SG2=T z8T{)u>G}&|-Xa`lTW;f|7n>d1L!Fb@l{omvNWy6L{sYI};ME8mBM%%WsBI27?7x*h z=4_ldAO9ZV(Oq`oBe2`N&BjuEEdr|ZE|~7dgbSi#oa~XNhVKk#Q3HaIBi@;I%^|*1 z!;aSY@adMMdZHjHRFLBTea_Xd| zLBhrEQOB%C=TDdeK2EKO=l;fShSj4pu5ISR)6DCSA{zA9n7wb6~CbSPs! zt&ca>OejA906+jqL_t(^v(<;_o_E$87*^)cMg3&%;g9(mZM+i5eEW`1xY1uB!y8E| zs^n%{-(X6pI;e}6)HLaE6dvp&PcxZo8ph=bLKmOMr0oHF<}c++h4*~OA?q|!;sZRZ zjpsH!Z8%^(tVEVE;7H5lpqPz-a(|R^9m5Y;#4UMMJP*a7YD3}wdvwEgkKC^N}fxP?Bd^-}%>K8a)FLT_AJ$m~Y`WTNN z`ExO&X5V%1>9NSN`O0LEvEN(Gd{5*m_DA;ww+O^6db_?y<0fq_>TGY<_IAAe0^dC9 z2e<0Y64Ke=#U}3XEx}Ow3GEmj?<{?S_RQ~==J5z$Vp-$El|=1$Y6$1c_tiz1r~RNd zF50)%k&gS>082i%&d>eqFJMlcalmUlQMzwWUBF;Kj)|obvDT7WyP=8h_hanfPj@uV z#l^P1mY4W(O4oZTVW2jC3j->>AQxePrEzAyPh}+ZcpnS(b&ppDGER^2F+%=%wqIS|u4GosK4(dYG5cyNPcXtmKg!9D9W!|5Ek?Yc!dxmA#<-~~HY&?pKqhdM zE>4s3zu2N-+tQYxr}r4s;~UN_oQFqPYTh0(euIt9!vnmt8tkc%>)ZpS-1m0Y!>5Z; zFvE;m;+lXwuw{F>A0nEf?`oR7hyoA3#ZP)1b7&J+|xelokLbr;_V z0e@oWO&)KbWzqPFMKI&|G=Bn76b4VY+;H{Bq2f3mEHc;>Z@jIqEqNM!QNulR{UzLi z$M$>>PAmCzABzH;I>&zKu(Oj+-$da&wXO6(MU{~R<@B>i;_~jA>`st>J`?8 znP;Qp5Pv#&F$?d-G~Nh4hT zt)m93EjJ5O8L!7G;Ghxbh9;>$46O`LPa&>02E0#0a=NW}kAo0>>=jT^BEZJ_)MkwKigxxIEL${H1bVj2`e%p(iXcNVZIKaQ=8IAN=@~~VIE@|p=B0U6dqDR}2t&*A(fq8n4L5JGzVyRabJ&sQWKBIHdI{+H z+&mKoR!xhbkAw5tb9;<$69t*K95K+Ebkvc>_NJF}L3cV(oxe!zjXqcJwQ)-7xPttS zG_sF&wvBnqP%oFw!hs{v{h+8G9OkY_XSAy%%xpeZ{sn({cDBi|@zZtv_Gm810{g=8 zq9WKIUzmscx!8_0QU(JzQVzcEeaykEVt$4OQ!u>lFN0$B@bp6bM~&?jx#c`&To~U+ zkI8a}XkK&xJu(?JDY!ApSw1DAalvb1kwwqbK2h(F6|(?NjS4}(t9XHcb%w0C-u$5+ ze9Zj(nEH5V81FZlC28;spwz&yu=K#Dw;5msHF-Netrm_0=pD^^X?zyT%;ZdN<3Gbn z?Y($dYrmJyF5zq6LHiJQV&p`=cHk`@zr9|x`i6zA#Y%%u_j{w`$$_;uY%4s&Yq#le zMji1XJC|L0f!S-%E!~T4aZ~$r8SbuNobl!eGNbUIFu9WI&u;6W3vZWAcAx`Xc3wn5 zjSWNvizYs+=WQUX0w~HDVDjz_G5W`izixaNhV-{HVNQFT+?dyQVNh3Cr3EEpV6Jex zxAmIkF4mnMOn6IRh0}OTAdCl5Lf(xf2tpUG-nMmdY`tI<9LW}}fRsN_^q9xjhyLcB zIqA74;fHuM@UU(`R=F~K1yq#MR52RSZiEV`{9L!kCb&)%)-AZY-8#OFF^;#a?jh^t z!g@m-{KC|3c>81o&}Da*sy_Zk&g;J>u~s%b$n+7Eai0c9l%D%2TWZwyPz4GIG2**G6^SwLz z&c`4t-xmDN+TS|=Y=j<*b>^jKksizmbW|L|fd6CyEF$_@q_6WgSU9{s^jz9w?t5I+ zaPy+SfidSg!y#TbL329M;%6ZAVw--7RaQ@H!d%OUo3@M(0{9Gm8}4sV>!BRr4W#f1^=Zn? z0m~wrTigJ~+mdNL&CX#nd5NP`u#3tMbksWF3!0wa`}Nd#gV*=_Hu4m=@8tyLHBDwx zUYD9}lQI8I?qd|GCoPT@A;-9n1#{&41!_Bd`!M0@FkL6+ppTM0q(U!8ifxFz_%2HL z*KZ2BKwPt+1e3BfwdTJW`svVb#1$3lR&Ts&--H^s@;7@Db4={(USRXJxp7$T&C<6! zF6sC=@@?Q^Kiby5xYgy|&$mv5l1RWBw89OCG05nmT;>9D{gx5l(35oo-x*VzGHQIo zNb~D$!3?^RFkn#YR(r*F3&G;h=kNr3cQaf408$$Pzv@cRp!3^tKAjP49^GziJ1@m& zCzJe1B4jRb7M9$KQuXC`e^jl3vV}F@Y*d^)oy3PMVoJvIv-yV$&9pT%CPa|AhK$h_ zcoJ1F!qh)81&%Bmfm7F}IMjO65mf2e0H0wpgqNku#lYxJ|vPZ6hfLZ lzoSxPOvkdgiQA& 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