diff --git a/DirectProgramming/C++SYCL_FPGA/README.md b/DirectProgramming/C++SYCL_FPGA/README.md index 1a1a94554a..e9fdf29812 100644 --- a/DirectProgramming/C++SYCL_FPGA/README.md +++ b/DirectProgramming/C++SYCL_FPGA/README.md @@ -56,6 +56,7 @@ flowchart LR |:--- |:--- |:--- | [fpga_compile](Tutorials/GettingStarted/fpga_compile) | [Tutorials/GettingStarted](Tutorials/GettingStarted) | How and why compiling SYCL* code for FPGA differs from CPU or GPU
FPGA device image types and when to use them.
The compile options used to target FPGA | [fast_recompile](Tutorials/GettingStarted/fast_recompile) | [Tutorials/GettingStarted](Tutorials/GettingStarted) | Why to separate host and device code compilation in your FPGA project
How to use the `-reuse-exe` and device link.
Which method to choose for your project +| [fpga_template](Tutorials/GettingStarted/fpga_template) | [Tutorials/GettingStarted](Tutorials/GettingStarted) | Showcases the CMake build system that is used in other code samples, and serves as a template that you can re-use in your own designs. #### Tier 2: Explore the Fundamentals @@ -92,7 +93,7 @@ flowchart LR | [pipes](Tutorials/Features/pipes) | [Tutorials/Features](Tutorials/Features) | The basics of using SYCL*-compliant pipes extension for FPGA
How to declare and use pipes | [printf](Tutorials/Features/printf) | [Tutorials/DesignPatterns](Tutorials/DesignPatterns) | How to declare and use `printf` in program -#### Tier 3: Explore the Advances Techniques +#### Tier 3: Explore the Advanced Techniques ```mermaid flowchart LR diff --git a/DirectProgramming/C++SYCL_FPGA/Tutorials/GettingStarted/fpga_template/CMakeLists.txt b/DirectProgramming/C++SYCL_FPGA/Tutorials/GettingStarted/fpga_template/CMakeLists.txt new file mode 100644 index 0000000000..bf8590091c --- /dev/null +++ b/DirectProgramming/C++SYCL_FPGA/Tutorials/GettingStarted/fpga_template/CMakeLists.txt @@ -0,0 +1,320 @@ +# Direct CMake to use icpx rather than the default C++ compiler/linker on Linux +# and icx-cl on Windows +if(UNIX) + set(CMAKE_CXX_COMPILER icpx) +else() # Windows + include (CMakeForceCompiler) + CMAKE_FORCE_CXX_COMPILER (icx-cl IntelDPCPP) + include (Platform/Windows-Clang) +endif() + +cmake_minimum_required (VERSION 3.7.2) + +project(fpga_template CXX) + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + +############################################################################### +### Customize these build variables +############################################################################### +set(SOURCE_FILES src/fpga_template.cpp) +set(TARGET_NAME fpga_template) + +# Use cmake -DFPGA_DEVICE=: to choose a +# different device. Here are a few device examples (this list is not +# exhaustive): +# intel_s10sx_pac:pac_s10 +# intel_s10sx_pac:pac_s10_usm +# intel_a10gx_pac:pac_a10 +# Note that depending on your installation, you may need to specify the full +# path to the board support package (BSP), this usually is in your install +# folder. +# +# You can also specify a device family (E.g. "Arria10" or "Stratix10") or a +# specific part number (E.g. "10AS066N3F40E2SG") to generate a standalone IP. +if(NOT DEFINED FPGA_DEVICE) + set(FPGA_DEVICE "intel_s10sx_pac:pac_s10_usm") +endif() + +# Use cmake -DUSER_FPGA_FLAGS= to set extra flags for FPGA backend +# compilation. +set(USER_FPGA_FLAGS ${USER_FPGA_FLAGS}) + +# Use cmake -DUSER_FLAGS= to set extra flags for general compilation. +set(USER_FLAGS ${USER_FLAGS}) + +# Use cmake -DUSER_INCLUDE_PATHS= to set extra paths for general +# compilation. +set(USER_INCLUDE_PATHS ../../../include;${USER_INCLUDE_PATHS}) + +############################################################################### +### no changes after here +############################################################################### + +# Print the device being used for the compiles +message(STATUS "Configuring the design to run on FPGA board ${FPGA_DEVICE}") + +# Set the names of the makefile targets to be generated by cmake +set(EMULATOR_TARGET fpga_emu) +set(SIMULATOR_TARGET fpga_sim) +set(REPORT_TARGET report) +set(FPGA_TARGET fpga) +set(IP_EXPORT_TARGET fpga_ip_export) + +# Set the names of the generated files per makefile target +set(EMULATOR_OUTPUT_NAME ${TARGET_NAME}.${EMULATOR_TARGET}) +set(SIMULATOR_OUTPUT_NAME ${TARGET_NAME}.${SIMULATOR_TARGET}) +set(REPORT_OUTPUT_NAME ${TARGET_NAME}.${REPORT_TARGET}) +set(FPGA_OUTPUT_NAME ${TARGET_NAME}.${FPGA_TARGET}) +set(IP_EXPORT_OUTPUT_NAME ${TARGET_NAME}.${IP_EXPORT_TARGET}) + +message(STATUS "Additional USER_FPGA_FLAGS=${USER_FPGA_FLAGS}") +message(STATUS "Additional USER_FLAGS=${USER_FLAGS}") + +include_directories(${USER_INCLUDE_PATHS}) +message(STATUS "Additional USER_INCLUDE_PATHS=${USER_INCLUDE_PATHS}") + +link_directories(${USER_LIB_PATHS}) +message(STATUS "Additional USER_LIB_PATHS=${USER_LIB_PATHS}") + +link_libraries(${USER_LIBS}) +message(STATUS "Additional USER_LIBS=${USER_LIBS}") + +if(WIN32) + # add qactypes for Windows + set(QACTYPES "-Qactypes") + # This is a Windows-specific flag that enables exception handling in host code + set(WIN_FLAG "/EHsc") +else() + # add qactypes for Linux + set(QACTYPES "-qactypes") +endif() + +set(COMMON_COMPILE_FLAGS -fsycl -fintelfpga -Wall ${WIN_FLAG} ${QACTYPES} ${USER_FLAGS}) +set(COMMON_LINK_FLAGS -fsycl -fintelfpga ${QACTYPES} ${USER_FLAGS}) + +# A SYCL ahead-of-time (AoT) compile processes the device code in two stages. +# 1. The "compile" stage compiles the device code to an intermediate +# representation (SPIR-V). +# 2. The "link" stage invokes the compiler's FPGA backend before linking. For +# this reason, FPGA backend flags must be passed as link flags in CMake. +set(EMULATOR_COMPILE_FLAGS -DFPGA_EMULATOR) +set(EMULATOR_LINK_FLAGS ) +set(REPORT_COMPILE_FLAGS -DFPGA_HARDWARE) +set(REPORT_LINK_FLAGS -Xshardware -Xstarget=${FPGA_DEVICE} ${USER_FPGA_FLAGS} -fsycl-link=early) +set(SIMULATOR_COMPILE_FLAGS -Xssimulation -DFPGA_SIMULATOR) +set(SIMULATOR_LINK_FLAGS -Xssimulation -Xsghdl -Xstarget=${FPGA_DEVICE} ${USER_FPGA_FLAGS} -reuse-exe=${CMAKE_BINARY_DIR}/${SIMULATOR_OUTPUT_NAME}) +set(FPGA_COMPILE_FLAGS -DFPGA_HARDWARE) +set(FPGA_LINK_FLAGS -Xshardware -Xstarget=${FPGA_DEVICE} ${USER_FPGA_FLAGS} -reuse-exe=${CMAKE_BINARY_DIR}/${FPGA_OUTPUT_NAME}) +# get rid of this once host pipes work properly +set(IP_EXPORT_COMPILE_FLAGS -DFPGA_HARDWARE) +set(IP_EXPORT_LINK_FLAGS -Xshardware -Xstarget=${FPGA_DEVICE} ${USER_FPGA_FLAGS} -fsycl-link=early -fsycl-device-code-split=per_kernel) + +############################################################################### +### FPGA Emulator +############################################################################### +add_executable(${EMULATOR_TARGET} ${SOURCE_FILES}) +target_compile_options(${EMULATOR_TARGET} PRIVATE ${COMMON_COMPILE_FLAGS}) +target_compile_options(${EMULATOR_TARGET} PRIVATE ${EMULATOR_COMPILE_FLAGS}) +target_link_libraries(${EMULATOR_TARGET} ${COMMON_LINK_FLAGS}) +target_link_libraries(${EMULATOR_TARGET} ${EMULATOR_LINK_FLAGS}) +set_target_properties(${EMULATOR_TARGET} PROPERTIES OUTPUT_NAME ${EMULATOR_OUTPUT_NAME}) + +############################################################################### +### FPGA Simulator +############################################################################### +add_executable(${SIMULATOR_TARGET} ${SOURCE_FILES}) +target_compile_options(${SIMULATOR_TARGET} PRIVATE ${COMMON_COMPILE_FLAGS}) +target_compile_options(${SIMULATOR_TARGET} PRIVATE ${SIMULATOR_COMPILE_FLAGS}) +target_link_libraries(${SIMULATOR_TARGET} ${COMMON_LINK_FLAGS}) +target_link_libraries(${SIMULATOR_TARGET} ${SIMULATOR_LINK_FLAGS}) +set_target_properties(${SIMULATOR_TARGET} PROPERTIES OUTPUT_NAME ${SIMULATOR_OUTPUT_NAME}) + +############################################################################### +### Generate Report +############################################################################### +add_executable(${REPORT_TARGET} ${SOURCE_FILES}) +target_compile_options(${REPORT_TARGET} PRIVATE ${COMMON_COMPILE_FLAGS}) +target_compile_options(${REPORT_TARGET} PRIVATE ${REPORT_COMPILE_FLAGS}) + +# The report target does not need the QACTYPES flag at link stage +set(MODIFIED_COMMON_LINK_FLAGS_REPORT ${COMMON_LINK_FLAGS}) +list(REMOVE_ITEM MODIFIED_COMMON_LINK_FLAGS_REPORT ${QACTYPES}) + +target_link_libraries(${REPORT_TARGET} ${MODIFIED_COMMON_LINK_FLAGS_REPORT}) +target_link_libraries(${REPORT_TARGET} ${REPORT_LINK_FLAGS}) +set_target_properties(${REPORT_TARGET} PROPERTIES OUTPUT_NAME ${REPORT_OUTPUT_NAME}) + +############################################################################### +### FPGA Hardware +############################################################################### +add_executable(${FPGA_TARGET} EXCLUDE_FROM_ALL ${SOURCE_FILES}) +target_compile_options(${FPGA_TARGET} PRIVATE ${COMMON_COMPILE_FLAGS}) +target_compile_options(${FPGA_TARGET} PRIVATE ${FPGA_COMPILE_FLAGS}) +target_link_libraries(${FPGA_TARGET} ${COMMON_LINK_FLAGS}) +target_link_libraries(${FPGA_TARGET} ${FPGA_LINK_FLAGS}) +set_target_properties(${FPGA_TARGET} PROPERTIES OUTPUT_NAME ${FPGA_OUTPUT_NAME}) + +############################################################################### +### FPGA IP Export (only necessary until native host pipes) +############################################################################### +add_executable(${IP_EXPORT_TARGET} ${SOURCE_FILES}) +target_compile_options(${IP_EXPORT_TARGET} PRIVATE ${COMMON_COMPILE_FLAGS}) +target_compile_options(${IP_EXPORT_TARGET} PRIVATE ${IP_EXPORT_COMPILE_FLAGS}) + +# The ip export target does not need the QACTYPES flag at link stage +set(MODIFIED_COMMON_LINK_FLAGS_EXPORT ${COMMON_LINK_FLAGS}) +list(REMOVE_ITEM MODIFIED_COMMON_LINK_FLAGS_EXPORT ${QACTYPES}) + +target_link_libraries(${IP_EXPORT_TARGET} ${MODIFIED_COMMON_LINK_FLAGS_EXPORT}) +target_link_libraries(${IP_EXPORT_TARGET} ${IP_EXPORT_LINK_FLAGS}) +set_target_properties(${IP_EXPORT_TARGET} PROPERTIES OUTPUT_NAME ${IP_EXPORT_OUTPUT_NAME}) + +############################################################################### +### This part only manipulates cmake variables to print the commands to the user +############################################################################### + +# set the correct object file extension depending on the target platform +if(WIN32) + set(OBJ_EXTENSION "obj") +else() + set(OBJ_EXTENSION "o") +endif() + +# Set the source file names in a string +set(SOURCE_FILE_NAME "${SOURCE_FILES}") + +function(getCompileCommands common_compile_flags special_compile_flags common_link_flags special_link_flags target output_name) + + set(file_names ${SOURCE_FILE_NAME}) + set(COMPILE_COMMAND ) + set(LINK_COMMAND ) + + foreach(source ${file_names}) + # Get the relative path to the source and object files + file(RELATIVE_PATH CURRENT_SOURCE_FILE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR}/${source}) + file(RELATIVE_PATH OBJ_FILE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}.dir/${source}.${OBJ_EXTENSION}) + + # Creating a string that contains the compile command + # Start by the compiler invocation + set(COMPILE_COMMAND "${COMPILE_COMMAND}${CMAKE_CXX_COMPILER}") + + # Add all the potential includes + foreach(INCLUDE ${USER_INCLUDE_PATHS}) + if(NOT IS_ABSOLUTE ${INCLUDE}) + file(RELATIVE_PATH INCLUDE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR}/${INCLUDE}) + endif() + set(COMPILE_COMMAND "${COMPILE_COMMAND} -I${INCLUDE}") + endforeach() + + # Add all the common compile flags + foreach(FLAG ${common_compile_flags}) + set(COMPILE_COMMAND "${COMPILE_COMMAND} ${FLAG}") + endforeach() + + # Add all the specific compile flags + foreach(FLAG ${special_compile_flags}) + set(COMPILE_COMMAND "${COMPILE_COMMAND} ${FLAG}") + endforeach() + + # Get the location of the object file + file(RELATIVE_PATH OBJ_FILE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}.dir/${source}.${OBJ_EXTENSION}) + + # Add the source file and the output file + set(COMPILE_COMMAND "${COMPILE_COMMAND} -c ${CURRENT_SOURCE_FILE} -o ${OBJ_FILE}\n") + endforeach() + + set(COMPILE_COMMAND "${COMPILE_COMMAND}" PARENT_SCOPE) + + # Creating a string that contains the link command + # Start by the compiler invocation + set(LINK_COMMAND "${LINK_COMMAND}${CMAKE_CXX_COMPILER}") + + # Add all the common link flags + foreach(FLAG ${common_link_flags}) + set(LINK_COMMAND "${LINK_COMMAND} ${FLAG}") + endforeach() + + # Add all the specific link flags + foreach(FLAG ${special_link_flags}) + set(LINK_COMMAND "${LINK_COMMAND} ${FLAG}") + endforeach() + + # Add the output file + set(LINK_COMMAND "${LINK_COMMAND} -o ${output_name}") + + foreach(source ${file_names}) + # Get the relative path to the source and object files + file(RELATIVE_PATH OBJ_FILE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}.dir/${source}.${OBJ_EXTENSION}) + + # Add the source file and the output file + set(LINK_COMMAND "${LINK_COMMAND} ${OBJ_FILE}") + endforeach() + + # Add all the potential library paths + foreach(LIB_PATH ${USER_LIB_PATHS}) + if(NOT IS_ABSOLUTE ${LIB_PATH}) + file(RELATIVE_PATH LIB_PATH ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR}/${LIB_PATH}) + endif() + if(NOT WIN32) + set(LINK_COMMAND "${LINK_COMMAND} -L${LIB_PATH}") + else() + set(LINK_COMMAND "${LINK_COMMAND} -L${LIB_PATH} -Wl,-rpath,${LIB_PATH}") + endif() + endforeach() + + # Add all the potential includes + foreach(LIB ${USER_LIBS}) + set(LINK_COMMAND "${LINK_COMMAND} -l${LIB}") + endforeach() + + set(LINK_COMMAND "${LINK_COMMAND}" PARENT_SCOPE) + +endfunction() + +# Windows executable is going to have the .exe extension +if(WIN32) + set(EXECUTABLE_EXTENSION ".exe") +endif() + +# Display the compile instructions in the emulation flow +getCompileCommands("${COMMON_COMPILE_FLAGS}" "${EMULATOR_COMPILE_FLAGS}" "${COMMON_LINK_FLAGS}" "${EMULATOR_LINK_FLAGS}" "${EMULATOR_TARGET}" "${EMULATOR_OUTPUT_NAME}${EXECUTABLE_EXTENSION}") + +add_custom_target( displayEmulationCompileCommands ALL + ${CMAKE_COMMAND} -E cmake_echo_color --cyan "" + COMMENT "To compile manually:\n${COMPILE_COMMAND}\nTo link manually:\n${LINK_COMMAND}") +add_dependencies(${EMULATOR_TARGET} displayEmulationCompileCommands) + +# Display the compile instructions in the simulation flow +getCompileCommands("${COMMON_COMPILE_FLAGS}" "${SIMULATOR_COMPILE_FLAGS}" "${COMMON_LINK_FLAGS}" "${SIMULATOR_LINK_FLAGS}" "${SIMULATOR_TARGET}" "${SIMULATOR_OUTPUT_NAME}${EXECUTABLE_EXTENSION}") + +add_custom_target( displaySimulationCompileCommands ALL + ${CMAKE_COMMAND} -E cmake_echo_color --cyan "" + COMMENT "To compile manually:\n${COMPILE_COMMAND}\nTo link manually:\n${LINK_COMMAND}") +add_dependencies(${SIMULATOR_TARGET} displaySimulationCompileCommands) + +# Display the compile instructions in the report flow +getCompileCommands("${COMMON_COMPILE_FLAGS}" "${REPORT_COMPILE_FLAGS}" "${MODIFIED_COMMON_LINK_FLAGS_REPORT}" "${REPORT_LINK_FLAGS}" "${REPORT_TARGET}" "${REPORT_OUTPUT_NAME}${EXECUTABLE_EXTENSION}") + +add_custom_target( displayReportCompileCommands ALL + ${CMAKE_COMMAND} -E cmake_echo_color --cyan "" + COMMENT "To compile manually:\n${COMPILE_COMMAND}\nTo link manually:\n${LINK_COMMAND}") +add_dependencies(${REPORT_TARGET} displayReportCompileCommands) + +# Display the compile instructions in the IP export flow (Remove after native host pipes work properly) +getCompileCommands("${COMMON_COMPILE_FLAGS}" "${IP_EXPORT_COMPILE_FLAGS}" "${MODIFIED_COMMON_LINK_FLAGS_EXPORT}" "${IP_EXPORT_LINK_FLAGS}" "${IP_EXPORT_TARGET}" "${IP_EXPORT_OUTPUT_NAME}${EXECUTABLE_EXTENSION}") + +add_custom_target( displayExportCompileCommands ALL + ${CMAKE_COMMAND} -E cmake_echo_color --cyan "" + COMMENT "To compile manually:\n${COMPILE_COMMAND}\nTo link manually:\n${LINK_COMMAND}") +add_dependencies(${IP_EXPORT_TARGET} displayExportCompileCommands) + +# Display the compile instructions in the fpga flow +getCompileCommands("${COMMON_COMPILE_FLAGS}" "${FPGA_COMPILE_FLAGS}" "${COMMON_LINK_FLAGS}" "${FPGA_LINK_FLAGS}" "${FPGA_TARGET}" "${FPGA_OUTPUT_NAME}${EXECUTABLE_EXTENSION}") + +add_custom_target( displayFPGACompileCommands ALL + ${CMAKE_COMMAND} -E cmake_echo_color --cyan "" + COMMENT "To compile manually:\n${COMPILE_COMMAND}\nTo link manually:\n${LINK_COMMAND}") +add_dependencies(${FPGA_TARGET} displayFPGACompileCommands) diff --git a/DirectProgramming/C++SYCL_FPGA/Tutorials/GettingStarted/fpga_template/README.md b/DirectProgramming/C++SYCL_FPGA/Tutorials/GettingStarted/fpga_template/README.md new file mode 100644 index 0000000000..0353f9edc5 --- /dev/null +++ b/DirectProgramming/C++SYCL_FPGA/Tutorials/GettingStarted/fpga_template/README.md @@ -0,0 +1,234 @@ +# `FPGA Template` Sample + +This project serves as a template for Intel® oneAPI FPGA designs. + +| Optimized for | Description +|:--- |:--- +| OS | Linux* Ubuntu* 18.04/20.04
RHEL*/CentOS* 8
SUSE* 15
Windows* 10 +| Hardware | Intel® Agilex™, Arria® 10, and Stratix® 10 FPGAs +| Software | Intel® oneAPI DPC++/C++ Compiler +| What you will learn | Best practices for creating and managing a oneAPI FPGA project +| Time to complete | 10 minutes + +> **Note**: Even though the Intel DPC++/C++ OneAPI compiler is enough to compile for emulation, generating reports and generating RTL, there are extra software requirements for the simulation flow and FPGA compiles. +> +> To use the simulator flow, Intel® Quartus® Prime Pro Edition and one of the following simulators must be installed and accessible through your PATH: +> - Questa*-Intel® FPGA Edition +> - Questa*-Intel® FPGA Starter Edition +> - ModelSim® SE +> +> When using the hardware compile flow, Intel® Quartus® Prime Pro Edition must be installed and accessible through your PATH. +> +> :warning: Make sure you add the device files associated with the FPGA that you are targeting to your Intel® Quartus® Prime installation. + +> **Note**: In oneAPI full systems, kernels that use SYCL Unified Shared Memory (USM) host allocations or USM shared allocations (and therefore the code in this tutorial) are only supported by Board Support Packages (BSPs) with USM support (e.g. the Intel® FPGA PAC D5005 (with Intel Stratix® 10 SX) `intel_s10sx_pac:pac_s10_usm`). Kernels that use these types of allocations can always be used to generate standalone IPs. + +## Prerequisites + +This sample is part of the FPGA code samples. +It is categorized as a Tier 1 sample that helps you getting started. + +```mermaid +flowchart LR + tier1("Tier 1: Get Started") + tier2("Tier 2: Explore the Fundamentals") + tier3("Tier 3: Explore the Advanced Techniques") + tier4("Tier 4: Explore the Reference Designs") + + tier1 --> tier2 --> tier3 --> tier4 + + style tier1 fill:#f96,stroke:#333,stroke-width:1px,color:#fff + style tier2 fill:#0071c1,stroke:#0071c1,stroke-width:1px,color:#fff + style tier3 fill:#0071c1,stroke:#0071c1,stroke-width:1px,color:#fff + style tier4 fill:#0071c1,stroke:#0071c1,stroke-width:1px,color:#fff +``` + +Find more information about how to navigate this part of the code samples in the [FPGA top-level README.md](/DirectProgramming/DPC++FPGA/README.md). +You can also find more information about [troubleshooting build errors](/DirectProgramming/DPC++FPGA/README.md#troubleshooting), [running the sample on the Intel® DevCloud](/DirectProgramming/DPC++FPGA/README.md#build-and-run-the-samples-on-intel-devcloud-optional), [using Visual Studio Code with the code samples](/DirectProgramming/DPC++FPGA/README.md#use-visual-studio-code-vs-code-optional), [links to selected documentation](/DirectProgramming/DPC++FPGA/README.md#documentation), etc. + +## Purpose + +Use this project as a starting point when you build designs for the Intel® oneAPI DPC++/C++ compiler when targeting FPGAs. It includes a CMake build system to automate selecting the various command-line flags for the oneAPI DPC++/C++ compiler, and a simple single-source design to serve as an example. You can customize the build flags by modifying the top part of `CMakeLists.txt`: if you want to pass additional flags to the Intel® oneAPI DPC++/C++ compiler, you can change the `USER_FLAGS` and `USER_HARDWARE_FLAGS` variables defined in `CMakeLists.txt`. Similarly, you can add additional include paths to the `USER_INCLUDE_PATHS` variable. You can also explicitly define these variables at the command-line if you don't want to make change to the CMake build system. + +> **Note**: The code sample in this design only uses USM for improved code simplicity as compared with buffers/accessors. The included CMake build system can also be used for designs that do not use USM. + +| Variable | Description +|:--- |:--- +| `USER_HARDWARE_FLAGS` | This semicolon-separated list of flags applies only to flows that generate FPGA hardware (i.e. report, simulation, hardware). You can specify flags such as `-Xsclock` or `-Xshyper-optimized-handshaking=off` +| `USER_FLAGS` | This semicolon-separated list of flags applies to all flows, including emulation. You can specify flags such as `-v` or define macros such as `-DYOUR_OWN_MACRO=3` +| `USER_INCLUDE_PATHS` | This semicolon-separated list of include paths applies to all flows, including emulation. Specify include paths relative to the `CMakeLists.txt` file, or using absolute paths in the filesystem. + +```bash +############################################################################### +### Customize these build variables +############################################################################### +set(SOURCE_FILES src/fpga_template.cpp) +set(TARGET_NAME fpga_template) + +# Use cmake -DFPGA_DEVICE=: to choose a +# different device. Here are a few device examples (this list is not +# exhaustive): +# intel_s10sx_pac:pac_s10 +# intel_s10sx_pac:pac_s10_usm +# intel_a10gx_pac:pac_a10 +# Note that depending on your installation, you may need to specify the full +# path to the board support package (BSP), this usually is in your install +# folder. +# +# You can also specify a device family (E.g. "Arria10" or "Stratix10") or a +# specific part number (E.g. "10AS066N3F40E2SG") to generate a standalone IP. +if(NOT DEFINED FPGA_DEVICE) + set(FPGA_DEVICE "intel_s10sx_pac:pac_s10_usm") +endif() + +# Use cmake -DUSER_FPGA_FLAGS= to set extra flags for FPGA backend +# compilation. +set(USER_FPGA_FLAGS ${USER_FPGA_FLAGS}) + +# Use cmake -DUSER_FLAGS= to set extra flags for general compilation. +set(USER_FLAGS ${USER_FLAGS}) + +# Use cmake -DUSER_INCLUDE_PATHS= to set extra paths for general +# compilation. +set(USER_INCLUDE_PATHS ../../../../include;${USER_INCLUDE_PATHS}) +``` + +Everything below this in the `CMakeLists.txt` is necessary for selecting the compiler flags that are necessary to support the build targets specified below, and should not need to be modified. + +## Building the `fpga_template` Tutorial + +> **Note**: When working with the command-line interface (CLI), you should configure the oneAPI toolkits using environment variables. +> Set up your CLI environment by sourcing the `setvars` script located in the root of your oneAPI installation every time you open a new terminal window. +> This practice ensures that your compiler, libraries, and tools are ready for development. +> +> Linux*: +> - For system wide installations: `. /opt/intel/oneapi/setvars.sh` +> - For private installations: ` . ~/intel/oneapi/setvars.sh` +> - For non-POSIX shells, like csh, use the following command: `bash -c 'source /setvars.sh ; exec csh'` +> +> Windows*: +> - `C:\Program Files(x86)\Intel\oneAPI\setvars.bat` +> - Windows PowerShell*, use the following command: `cmd.exe "/K" '"C:\Program Files (x86)\Intel\oneAPI\setvars.bat" && powershell'` +> +> For more information on configuring environment variables, see [Use the setvars Script with Linux* or macOS*](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-programming-guide/top/oneapi-development-environment-setup/use-the-setvars-script-with-linux-or-macos.html) or [Use the setvars Script with Windows*](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-programming-guide/top/oneapi-development-environment-setup/use-the-setvars-script-with-windows.html). + +Use these commands to run the design, depending on your OS. + +### On a Linux* System +This design uses CMake to generate a build script for GNU/make. + +1. Change to the sample directory. + +2. Configure the build system for the Agilex™ device family, which is the default. + + ``` + mkdir build + cd build + cmake .. + ``` + + > **Note**: You can change the default target by using the command: + > ``` + > cmake .. -DFPGA_DEVICE= + > ``` + > + > Alternatively, you can target an explicit FPGA board variant and BSP by using the following command: + > ``` + > cmake .. -DFPGA_DEVICE=: + > ``` + > + > You will only be able to run an executable on the FPGA if you specified a BSP. + +3. Compile the design through the generated `Makefile`. The following build targets are provided, matching the recommended development flow: + + | Target | Expected Time | Output | Description + |:--- |:--- |:--- |:--- + | `make fpga_emu` | Seconds | x86-64 binary | Compiles the FPGA device code to the CPU. Use the Intel® FPGA Emulation Platform for OpenCL™ software to verify your SYCL code’s functional correctness. + | `make report` | Minutes | RTL + FPGA reports | Compiles the FPGA device code to RTL and generates an optimization report that describes the structures generated on the FPGA, identifies performance bottlenecks, and estimates resource utilization. This report will include the interfaces defined in your selected Board Support Package. + | `make fpga_sim` | Minutes | RTL + FPGA reports + x86-64 binary | Compiles the FPGA device code to RTL and generates a simulation testbench. Use the Questa*-Intel® FPGA Edition simulator to verify your design. + | `make fpga` | Multiple Hours | Quartus Place & Route (Full accelerator) + FPGA reports + x86-64 host binary | Compiles the FPGA device code to RTL and compiles the generated RTL using Intel® Quartus® Prime. If you specified a BSP with `FPGA_DEVICE`, this will generate an FPGA image that you can run on the corresponding accelerator board. + | `make fpga_ip_export` | Minutes | RTL + FPGA reports | Compiles the FPGA device code to RTL that may be exported to Intel® Quartus Prime software + + The `fpga_emu`, `fpga_sim` and `fpga` targets produce binaries that you can run. The executables will be called `TARGET_NAME.fpga_emu`, `TARGET_NAME.fpga_sim`, and `TARGET_NAME.fpga`, where `TARGET_NAME` is the value you specify in `CMakeLists.txt`. + +### On a Windows* System +This design uses CMake to generate a build script for `nmake`. + +1. Change to the sample directory. + +2. Configure the build system for the Agilex™ device family, which is the default. + ``` + mkdir build + cd build + cmake -G "NMake Makefiles" .. + ``` + + > **Note**: You can change the default target by using the command: + > ``` + > cmake -G "NMake Makefiles" .. -DFPGA_DEVICE= + > ``` + > + > Alternatively, you can target an explicit FPGA board variant and BSP by using the following command: + > ``` + > cmake -G "NMake Makefiles" .. -DFPGA_DEVICE=: + > ``` + > + > You will only be able to run an executable on the FPGA if you specified a BSP. + +3. Compile the design through the generated `Makefile`. The following build targets are provided, matching the recommended development flow: + + | Target | Expected Time | Output | Description + |:--- |:--- |:--- |:--- + | `nmake fpga_emu` | Seconds | x86-64 binary | Compiles the FPGA device code to the CPU. Use the Intel® FPGA Emulation Platform for OpenCL™ software to verify your SYCL code’s functional correctness. + | `nmake report` | Minutes | RTL + FPGA reports | Compiles the FPGA device code to RTL and generates an optimization report that describes the structures generated on the FPGA, identifies performance bottlenecks, and estimates resource utilization. This report will include the interfaces defined in your selected Board Support Package. + | `nmake fpga_sim` | Minutes | RTL + FPGA reports + x86-64 binary | Compiles the FPGA device code to RTL and generates a simulation testbench. Use the Questa*-Intel® FPGA Edition simulator to verify your design. + | `nmake fpga` | Multiple Hours | Quartus Place & Route (Full accelerator) + FPGA reports + x86-64 host binary | Compiles the FPGA device code to RTL and compiles the generated RTL using Intel® Quartus® Prime. If you specified a BSP with `FPGA_DEVICE`, this will generate an FPGA image that you can run on the corresponding accelerator board. + | `nmake fpga_ip_export` | Minutes | RTL + FPGA reports | Compiles the FPGA device code to RTL that may be exported to Intel® Quartus Prime software + + The `fpga_emu`, `fpga_sim`, and `fpga` targets also produce binaries that you can run. The executables will be called `TARGET_NAME.fpga_emu.exe`, `TARGET_NAME.fpga_sim.exe`, and `TARGET_NAME.fpga.exe`, where `TARGET_NAME` is the value you specify in `CMakeLists.txt`. + + > **Note**: If you encounter any issues with long paths when compiling under Windows*, you may have to create your ‘build’ directory in a shorter path, for example c:\samples\build. You can then run cmake from that directory, and provide cmake with the full path to your sample directory. + +## Run the `fpga_template` Executable + +### On Linux +1. Run the sample on the FPGA emulator (the kernel executes on the CPU). + ``` + ./fpga_template.fpga_emu + ``` +2. Run the sample on the FPGA simulator device. + ``` + CL_CONTEXT_MPSIM_DEVICE_INTELFPGA=1 ./fpga_template.fpga_sim + ``` +3. Alternatively, run the sample on the FPGA device (only if you ran `cmake` with `-DFPGA_DEVICE=:`). + ``` + ./fpga_template.fpga + ``` +### On Windows +1. Run the sample on the FPGA emulator (the kernel executes on the CPU). + ``` + fpga_template.fpga_emu.exe + ``` +2. Run the sample on the FPGA simulator device. + ``` + set CL_CONTEXT_MPSIM_DEVICE_INTELFPGA=1 + fpga_template.fpga_sim.exe + set CL_CONTEXT_MPSIM_DEVICE_INTELFPGA= + ``` +3. Alternatively, run the sample on the FPGA device (only if you ran `cmake` with `-DFPGA_DEVICE=:`). + ``` + fpga_template.fpga.exe + ``` + +## Example Output + +``` +Running on device: Intel(R) FPGA Emulation Device +add two vectors of size 256 +PASSED +``` +## License +Code samples are licensed under the MIT license. See +[License.txt](https://github.com/oneapi-src/oneAPI-samples/blob/master/License.txt) for details. + +Third party program Licenses can be found here: [third-party-programs.txt](https://github.com/oneapi-src/oneAPI-samples/blob/master/third-party-programs.txt). \ No newline at end of file diff --git a/DirectProgramming/C++SYCL_FPGA/Tutorials/GettingStarted/fpga_template/sample.json b/DirectProgramming/C++SYCL_FPGA/Tutorials/GettingStarted/fpga_template/sample.json new file mode 100644 index 0000000000..9627694c9e --- /dev/null +++ b/DirectProgramming/C++SYCL_FPGA/Tutorials/GettingStarted/fpga_template/sample.json @@ -0,0 +1,71 @@ +{ + "guid": "418AA4D8-0A61-4FDB-845A-CDA4DA0655E7", + "name": "FPGA Template", + "categories": ["Toolkit/oneAPI Direct Programming/C++SYCL FPGA/Getting Started Tutorials"], + "description": "This project serves as a template for Intel® oneAPI DPC++/C++ designs targeting FPGAs. ", + "toolchain": ["icpx"], + "os": ["linux", "windows"], + "targetDevice": ["FPGA"], + "builder": ["cmake"], + "languages": [{"cpp":{}}], + "commonFolder": { + "base": "../../..", + "include": [ + "README.md", + "Tutorials/GettingStarted/fpga_template", + "include" + ], + "exclude": [] + }, + "ciTests": { + "linux": [ + { + "id": "fpga_emu", + "steps": [ + "dpcpp --version", + "mkdir build", + "cd build", + "cmake ..", + "make fpga_emu", + "./fpga_template.fpga_emu" + ] + }, + { + "id": "report", + "steps": [ + "dpcpp --version", + "mkdir build", + "cd build", + "cmake ..", + "make report" + ] + } + ], + "windows": [ + { + "id": "fpga_emu", + "steps": [ + "dpcpp --version", + "cd ../../../..", + "mkdir build", + "cd build", + "cmake -G \"NMake Makefiles\" ../Tutorials/GettingStarted/fpga_template", + "nmake fpga_emu", + "fpga_template.fpga_emu.exe" + ] + }, + { + "id": "report", + "steps": [ + "dpcpp --version", + "cd ../../../..", + "mkdir build", + "cd build", + "cmake -G \"NMake Makefiles\" ../Tutorials/GettingStarted/fpga_template", + "nmake report" + ] + } + ] + }, + "expertise": "Getting Started" +} diff --git a/DirectProgramming/C++SYCL_FPGA/Tutorials/GettingStarted/fpga_template/src/fpga_template.cpp b/DirectProgramming/C++SYCL_FPGA/Tutorials/GettingStarted/fpga_template/src/fpga_template.cpp new file mode 100644 index 0000000000..e40cb39698 --- /dev/null +++ b/DirectProgramming/C++SYCL_FPGA/Tutorials/GettingStarted/fpga_template/src/fpga_template.cpp @@ -0,0 +1,111 @@ +#include + +// oneAPI headers +#include +#include + +#include "exception_handler.hpp" + +// Forward declare the kernel name in the global scope. This is an FPGA best +// practice that reduces name mangling in the optimization reports. +class VectorAddID; + +struct VectorAdd { + int *const a_in; + int *const b_in; + int *const c_out; + int len; + + void operator()() const { + for (int idx = 0; idx < len; idx++) { + int a_val = a_in[idx]; + int b_val = b_in[idx]; + int sum = a_val + b_val; + c_out[idx] = sum; + } + } +}; + +constexpr int kVectSize = 256; + +int main() { + bool passed = false; + + try { +// This design is tested with 2023.0, but also accounts for a syntax change in +// 2023.1 +#if __INTEL_CLANG_COMPILER >= 20230100 +#if FPGA_SIMULATOR + auto selector = sycl::ext::intel::fpga_simulator_selector_v; +#elif FPGA_HARDWARE + auto selector = sycl::ext::intel::fpga_selector_v; +#else // #if FPGA_EMULATOR + auto selector = sycl::ext::intel::fpga_emulator_selector_v; +#endif +#elif __INTEL_CLANG_COMPILER >= 20230000 +#if FPGA_SIMULATOR + auto selector = sycl::ext::intel::fpga_simulator_selector{}; +#elif FPGA_HARDWARE + auto selector = sycl::ext::intel::fpga_selector{}; +#else // #if FPGA_EMULATOR + auto selector = sycl::ext::intel::fpga_emulator_selector{}; +#endif +#else + assert(false) && "this design requires oneAPI 2023.0 or 2023.1!" +#endif + + sycl::queue q(selector, fpga_tools::exception_handler, + sycl::property::queue::enable_profiling{}); + + auto device = q.get_device(); + std::cout << "Running on device: " + << device.get_info().c_str() + << std::endl; + + // declare arrays and fill them + // allocate in shared memory so the kernel can see them + int *a = sycl::malloc_shared(kVectSize, q); + int *b = sycl::malloc_shared(kVectSize, q); + int *c = sycl::malloc_shared(kVectSize, q); + for (int i = 0; i < kVectSize; i++) { + a[i] = i; + b[i] = (kVectSize - i); + } + + std::cout << "add two vectors of size " << kVectSize << std::endl; + + q.single_task(VectorAdd{a, b, c, kVectSize}).wait(); + + // verify that VC is correct + passed = true; + for (int i = 0; i < kVectSize; i++) { + int expected = a[i] + b[i]; + if (c[i] != expected) { + std::cout << "idx=" << i << ": result " << c[i] << ", expected (" + << expected << ") A=" << a[i] << " + B=" << b[i] << std::endl; + passed = false; + } + } + + std::cout << (passed ? "PASSED" : "FAILED") << std::endl; + + sycl::free(a, q); + sycl::free(b, q); + sycl::free(c, q); + } catch (sycl::exception const &e) { + // Catches exceptions in the host code. + std::cerr << "Caught a SYCL host exception:\n" << e.what() << "\n"; + + // Most likely the runtime couldn't find FPGA hardware! + if (e.code().value() == CL_DEVICE_NOT_FOUND) { + std::cerr << "If you are targeting an FPGA, please ensure that your " + "system has a correctly configured FPGA board.\n"; + std::cerr << "Run sys_check in the oneAPI root directory to verify.\n"; + std::cerr << "If you are targeting the FPGA emulator, compile with " + "-DFPGA_EMULATOR.\n"; + } + std::terminate(); + } + + return passed ? EXIT_SUCCESS : EXIT_FAILURE; +} \ No newline at end of file