Skip to content

Commit d06e7b4

Browse files
authored
FPGA: Adding a New Sample: memory_system (#2476)
This code sample demonstrates how to implement an efficient banked memory system. We show the users how to partition the memory system, the effect that memory access has to the system performance, how to mitigate bad memory access/layout, and how the compiler optimizes memory banks.
1 parent b152185 commit d06e7b4

16 files changed

+875
-0
lines changed

DirectProgramming/C++SYCL_FPGA/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ flowchart LR
122122
| [annotated_class_clean_coding (experimental)](Tutorials/Features/experimental/annotated_class_clean_coding) | [Tutorials/Features](Tutorials/Features) | How to use `annotated_class_util.hpp` to simplify your oneAPI code that annotates properties to `pipe`s and `annotated_arg`
123123
| [annotated_ptr (experimental)](Tutorials/Features/experimental/annotated_ptr) | [Tutorials/Features](Tutorials/Features) | How to use `annotated_ptr` to constrain a specific memory access
124124
| [autorun](Tutorials/DesignPatterns/autorun) | [Tutorials/DesignPatterns](Tutorials/DesignPatterns) | How and when to use autorun kernels
125+
| [banked_memory_system](Tutorials/DesignPatterns/banked_memory_system) | [Tutorials/DesignPatterns](Tutorials/DesignPatterns) | How to optimize a banked memory system and improve throughput
125126
| [buffered_host_streaming](Tutorials/DesignPatterns/buffered_host_streaming) | [Tutorials/DesignPatterns](Tutorials/DesignPatterns) | How to optimally stream data between the host and device to maximize throughput
126127
| [compute_units](Tutorials/DesignPatterns/compute_units) | [Tutorials/DesignPatterns](Tutorials/DesignPatterns) | A design pattern to generate multiple compute units using template metaprogramming
127128
| [dsp_control](Tutorials/Features/dsp_control) | [Tutorials/Features](Tutorials/Features) | How to apply global DSP control in command-line interface <br> How to apply local DSP control in source code <br> Scope of datatypes and math operations that support DSP control
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
# Direct CMake to use icpx rather than the default C++ compiler/linker on Linux
2+
# and icx-cl on Windows
3+
if(UNIX)
4+
set(CMAKE_CXX_COMPILER icpx)
5+
else() # Windows
6+
include (CMakeForceCompiler)
7+
CMAKE_FORCE_CXX_COMPILER (icx-cl IntelDPCPP)
8+
include (Platform/Windows-Clang)
9+
endif()
10+
11+
cmake_minimum_required (VERSION 3.7.2)
12+
13+
project(banked_memory_system CXX)
14+
15+
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
16+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
17+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
18+
19+
###############################################################################
20+
### Customize these build variables
21+
###############################################################################
22+
set(SOURCE_FILES src/main.cpp)
23+
set(TARGET_NAME banked_mem)
24+
25+
# Use cmake -DFPGA_DEVICE=<board-support-package>:<board-variant> to choose a
26+
# different device.
27+
# Note that depending on your installation, you may need to specify the full
28+
# path to the board support package (BSP), this usually is in your install
29+
# folder.
30+
#
31+
# You can also specify a device family (E.g. "Arria10" or "Stratix10") or a
32+
# specific part number (E.g. "10AS066N3F40E2SG") to generate a standalone IP.
33+
if(NOT DEFINED FPGA_DEVICE)
34+
set(FPGA_DEVICE "Agilex7")
35+
message(STATUS "FPGA_DEVICE was not specified.\
36+
\nConfiguring the design to the default FPGA family target: ${FPGA_DEVICE}\
37+
\nPlease refer to the README for information on target selection.")
38+
endif()
39+
40+
# Use cmake -DUSER_FPGA_FLAGS=<flags> to set extra flags for FPGA backend
41+
# compilation.
42+
set(USER_FPGA_FLAGS ${USER_FPGA_FLAGS})
43+
44+
# Use cmake -DUSER_FLAGS=<flags> to set extra flags for general compilation.
45+
set(USER_FLAGS ${USER_FLAGS})
46+
47+
# Use cmake -DUSER_INCLUDE_PATHS=<paths> to set extra paths for general
48+
# compilation.
49+
set(USER_INCLUDE_PATHS ../../../include;${USER_INCLUDE_PATHS})
50+
51+
###############################################################################
52+
### no changes after here
53+
###############################################################################
54+
55+
# Set the names of the makefile targets to be generated by cmake
56+
set(EMULATOR_TARGET fpga_emu)
57+
set(SIMULATOR_TARGET fpga_sim)
58+
set(REPORT_TARGET report)
59+
set(FPGA_TARGET fpga)
60+
61+
# Set the names of the generated files per makefile target
62+
set(EMULATOR_OUTPUT_NAME ${TARGET_NAME}.${EMULATOR_TARGET})
63+
set(SIMULATOR_OUTPUT_NAME ${TARGET_NAME}.${SIMULATOR_TARGET})
64+
set(REPORT_OUTPUT_NAME ${TARGET_NAME}.${REPORT_TARGET})
65+
set(FPGA_OUTPUT_NAME ${TARGET_NAME}.${FPGA_TARGET})
66+
67+
message(STATUS "Additional USER_FPGA_FLAGS=${USER_FPGA_FLAGS}")
68+
message(STATUS "Additional USER_FLAGS=${USER_FLAGS}")
69+
70+
include_directories(${USER_INCLUDE_PATHS})
71+
message(STATUS "Additional USER_INCLUDE_PATHS=${USER_INCLUDE_PATHS}")
72+
73+
link_directories(${USER_LIB_PATHS})
74+
message(STATUS "Additional USER_LIB_PATHS=${USER_LIB_PATHS}")
75+
76+
link_libraries(${USER_LIBS})
77+
message(STATUS "Additional USER_LIBS=${USER_LIBS}")
78+
79+
if(WIN32)
80+
# add qactypes for Windows
81+
set(QACTYPES "-Qactypes")
82+
# This is a Windows-specific flag that enables exception handling in host code
83+
set(WIN_FLAG "/EHsc")
84+
else()
85+
# add qactypes for Linux
86+
set(QACTYPES "-qactypes")
87+
endif()
88+
89+
string(TOLOWER "${CMAKE_BUILD_TYPE}" LOWER_BUILD_TYPE)
90+
if(LOWER_BUILD_TYPE MATCHES debug)
91+
# Set debug flags
92+
if(WIN32)
93+
set(DEBUG_FLAGS /DEBUG /Od)
94+
else()
95+
set(DEBUG_FLAGS -g -O0)
96+
endif()
97+
else()
98+
set(DEBUG_FLAGS "")
99+
endif()
100+
101+
if(WIN32)
102+
set(EXT ".exe")
103+
endif()
104+
105+
set(COMMON_COMPILE_FLAGS -fintelfpga -Wall ${WIN_FLAG} ${QACTYPES} ${USER_FLAGS})
106+
set(COMMON_LINK_FLAGS -fintelfpga ${QACTYPES} ${USER_FLAGS})
107+
108+
# A SYCL ahead-of-time (AoT) compile processes the device code in two stages.
109+
# 1. The "compile" stage compiles the device code to an intermediate
110+
# representation (SPIR-V).
111+
# 2. The "link" stage invokes the compiler's FPGA backend before linking. For
112+
# this reason, FPGA backend flags must be passed as link flags in CMake.
113+
set(EMULATOR_COMPILE_FLAGS -DFPGA_EMULATOR ${DEBUG_FLAGS})
114+
set(EMULATOR_LINK_FLAGS )
115+
set(REPORT_COMPILE_FLAGS -DFPGA_HARDWARE)
116+
set(REPORT_LINK_FLAGS -Xshardware -Xstarget=${FPGA_DEVICE} ${USER_FPGA_FLAGS} -fsycl-link=early)
117+
set(SIMULATOR_COMPILE_FLAGS -Xssimulation -DFPGA_SIMULATOR)
118+
set(SIMULATOR_LINK_FLAGS -Xssimulation -Xsghdl=0 -Xstarget=${FPGA_DEVICE} ${USER_FPGA_FLAGS} -reuse-exe=${CMAKE_BINARY_DIR}/${SIMULATOR_OUTPUT_NAME}${EXT})
119+
set(FPGA_COMPILE_FLAGS -DFPGA_HARDWARE)
120+
set(FPGA_LINK_FLAGS -Xshardware -Xstarget=${FPGA_DEVICE} ${USER_FPGA_FLAGS} -reuse-exe=${CMAKE_BINARY_DIR}/${FPGA_OUTPUT_NAME}${EXT})
121+
122+
###############################################################################
123+
### FPGA Emulator
124+
###############################################################################
125+
add_executable(${EMULATOR_TARGET} ${SOURCE_FILES})
126+
target_compile_options(${EMULATOR_TARGET} PRIVATE ${COMMON_COMPILE_FLAGS})
127+
target_compile_options(${EMULATOR_TARGET} PRIVATE ${EMULATOR_COMPILE_FLAGS})
128+
target_link_libraries(${EMULATOR_TARGET} ${COMMON_LINK_FLAGS})
129+
target_link_libraries(${EMULATOR_TARGET} ${EMULATOR_LINK_FLAGS})
130+
set_target_properties(${EMULATOR_TARGET} PROPERTIES OUTPUT_NAME ${EMULATOR_OUTPUT_NAME})
131+
132+
###############################################################################
133+
### FPGA Simulator
134+
###############################################################################
135+
add_executable(${SIMULATOR_TARGET} EXCLUDE_FROM_ALL ${SOURCE_FILES})
136+
target_compile_options(${SIMULATOR_TARGET} PRIVATE ${COMMON_COMPILE_FLAGS})
137+
target_compile_options(${SIMULATOR_TARGET} PRIVATE ${SIMULATOR_COMPILE_FLAGS})
138+
target_link_libraries(${SIMULATOR_TARGET} ${COMMON_LINK_FLAGS})
139+
target_link_libraries(${SIMULATOR_TARGET} ${SIMULATOR_LINK_FLAGS})
140+
set_target_properties(${SIMULATOR_TARGET} PROPERTIES OUTPUT_NAME ${SIMULATOR_OUTPUT_NAME})
141+
142+
###############################################################################
143+
### Generate Report
144+
###############################################################################
145+
add_executable(${REPORT_TARGET} EXCLUDE_FROM_ALL ${SOURCE_FILES})
146+
target_compile_options(${REPORT_TARGET} PRIVATE ${COMMON_COMPILE_FLAGS})
147+
target_compile_options(${REPORT_TARGET} PRIVATE ${REPORT_COMPILE_FLAGS})
148+
149+
# The report target does not need the QACTYPES flag at link stage
150+
set(MODIFIED_COMMON_LINK_FLAGS_REPORT ${COMMON_LINK_FLAGS})
151+
list(REMOVE_ITEM MODIFIED_COMMON_LINK_FLAGS_REPORT ${QACTYPES})
152+
153+
target_link_libraries(${REPORT_TARGET} ${MODIFIED_COMMON_LINK_FLAGS_REPORT})
154+
target_link_libraries(${REPORT_TARGET} ${REPORT_LINK_FLAGS})
155+
set_target_properties(${REPORT_TARGET} PROPERTIES OUTPUT_NAME ${REPORT_OUTPUT_NAME})
156+
157+
###############################################################################
158+
### FPGA Hardware
159+
###############################################################################
160+
add_executable(${FPGA_TARGET} EXCLUDE_FROM_ALL ${SOURCE_FILES})
161+
target_compile_options(${FPGA_TARGET} PRIVATE ${COMMON_COMPILE_FLAGS})
162+
target_compile_options(${FPGA_TARGET} PRIVATE ${FPGA_COMPILE_FLAGS})
163+
target_link_libraries(${FPGA_TARGET} ${COMMON_LINK_FLAGS})
164+
target_link_libraries(${FPGA_TARGET} ${FPGA_LINK_FLAGS})
165+
set_target_properties(${FPGA_TARGET} PROPERTIES OUTPUT_NAME ${FPGA_OUTPUT_NAME})
166+
167+
###############################################################################
168+
### This part only manipulates cmake variables to print the commands cmake is expected to run to the user
169+
###############################################################################
170+
171+
# set the correct object file extension depending on the target platform
172+
if(WIN32)
173+
set(OBJ_EXTENSION "obj")
174+
else()
175+
set(OBJ_EXTENSION "o")
176+
endif()
177+
178+
# Set the source file names in a string
179+
set(SOURCE_FILE_NAME "${SOURCE_FILES}")
180+
181+
function(getCompileCommands common_compile_flags special_compile_flags common_link_flags special_link_flags target output_name)
182+
183+
set(file_names ${SOURCE_FILE_NAME})
184+
set(COMPILE_COMMAND )
185+
set(LINK_COMMAND )
186+
187+
foreach(source ${file_names})
188+
# Get the relative path to the source and object files
189+
file(RELATIVE_PATH CURRENT_SOURCE_FILE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR}/${source})
190+
file(RELATIVE_PATH OBJ_FILE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}.dir/${source}.${OBJ_EXTENSION})
191+
192+
# Creating a string that contains the compile command
193+
# Start by the compiler invocation
194+
set(COMPILE_COMMAND "${COMPILE_COMMAND}${CMAKE_CXX_COMPILER}")
195+
196+
# Add all the potential includes
197+
foreach(INCLUDE ${USER_INCLUDE_PATHS})
198+
if(NOT IS_ABSOLUTE ${INCLUDE})
199+
file(RELATIVE_PATH INCLUDE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR}/${INCLUDE})
200+
endif()
201+
set(COMPILE_COMMAND "${COMPILE_COMMAND} -I${INCLUDE}")
202+
endforeach()
203+
204+
# Add all the common compile flags
205+
foreach(FLAG ${common_compile_flags})
206+
set(COMPILE_COMMAND "${COMPILE_COMMAND} ${FLAG}")
207+
endforeach()
208+
209+
# Add all the specific compile flags
210+
foreach(FLAG ${special_compile_flags})
211+
set(COMPILE_COMMAND "${COMPILE_COMMAND} ${FLAG}")
212+
endforeach()
213+
214+
# Get the location of the object file
215+
file(RELATIVE_PATH OBJ_FILE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}.dir/${source}.${OBJ_EXTENSION})
216+
217+
# Add the source file and the output file
218+
set(COMPILE_COMMAND "${COMPILE_COMMAND} -c ${CURRENT_SOURCE_FILE} -o ${OBJ_FILE}\n")
219+
endforeach()
220+
221+
set(COMPILE_COMMAND "${COMPILE_COMMAND}" PARENT_SCOPE)
222+
223+
# Creating a string that contains the link command
224+
# Start by the compiler invocation
225+
set(LINK_COMMAND "${LINK_COMMAND}${CMAKE_CXX_COMPILER}")
226+
227+
# Add all the common link flags
228+
foreach(FLAG ${common_link_flags})
229+
set(LINK_COMMAND "${LINK_COMMAND} ${FLAG}")
230+
endforeach()
231+
232+
# Add all the specific link flags
233+
foreach(FLAG ${special_link_flags})
234+
set(LINK_COMMAND "${LINK_COMMAND} ${FLAG}")
235+
endforeach()
236+
237+
# Add the output file
238+
set(LINK_COMMAND "${LINK_COMMAND} -o ${output_name}")
239+
240+
foreach(source ${file_names})
241+
# Get the relative path to the source and object files
242+
file(RELATIVE_PATH OBJ_FILE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}.dir/${source}.${OBJ_EXTENSION})
243+
244+
# Add the source file and the output file
245+
set(LINK_COMMAND "${LINK_COMMAND} ${OBJ_FILE}")
246+
endforeach()
247+
248+
# Add all the potential library paths
249+
foreach(LIB_PATH ${USER_LIB_PATHS})
250+
if(NOT IS_ABSOLUTE ${LIB_PATH})
251+
file(RELATIVE_PATH LIB_PATH ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_LIST_DIR}/${LIB_PATH})
252+
endif()
253+
if(NOT WIN32)
254+
set(LINK_COMMAND "${LINK_COMMAND} -L${LIB_PATH}")
255+
else()
256+
set(LINK_COMMAND "${LINK_COMMAND} -L${LIB_PATH} -Wl,-rpath,${LIB_PATH}")
257+
endif()
258+
endforeach()
259+
260+
# Add all the potential includes
261+
foreach(LIB ${USER_LIBS})
262+
set(LINK_COMMAND "${LINK_COMMAND} -l${LIB}")
263+
endforeach()
264+
265+
set(LINK_COMMAND "${LINK_COMMAND}" PARENT_SCOPE)
266+
267+
endfunction()
268+
269+
# Windows executable is going to have the .exe extension
270+
if(WIN32)
271+
set(EXECUTABLE_EXTENSION ".exe")
272+
endif()
273+
274+
# Display the compile instructions in the emulation flow
275+
getCompileCommands("${COMMON_COMPILE_FLAGS}" "${EMULATOR_COMPILE_FLAGS}" "${COMMON_LINK_FLAGS}" "${EMULATOR_LINK_FLAGS}" "${EMULATOR_TARGET}" "${EMULATOR_OUTPUT_NAME}${EXECUTABLE_EXTENSION}")
276+
277+
add_custom_target( displayEmulationCompileCommands
278+
${CMAKE_COMMAND} -E cmake_echo_color --cyan ""
279+
COMMENT "\nTo compile manually:\n${COMPILE_COMMAND}\nTo link manually:\n${LINK_COMMAND}")
280+
add_dependencies(${EMULATOR_TARGET} displayEmulationCompileCommands)
281+
282+
# Display the compile instructions in the simulation flow
283+
getCompileCommands("${COMMON_COMPILE_FLAGS}" "${SIMULATOR_COMPILE_FLAGS}" "${COMMON_LINK_FLAGS}" "${SIMULATOR_LINK_FLAGS}" "${SIMULATOR_TARGET}" "${SIMULATOR_OUTPUT_NAME}${EXECUTABLE_EXTENSION}")
284+
285+
add_custom_target( displaySimulationCompileCommands
286+
${CMAKE_COMMAND} -E cmake_echo_color --cyan ""
287+
COMMENT "\nTo compile manually:\n${COMPILE_COMMAND}\nTo link manually:\n${LINK_COMMAND}")
288+
add_dependencies(${SIMULATOR_TARGET} displaySimulationCompileCommands)
289+
290+
# Display the compile instructions in the report flow
291+
getCompileCommands("${COMMON_COMPILE_FLAGS}" "${REPORT_COMPILE_FLAGS}" "${MODIFIED_COMMON_LINK_FLAGS_REPORT}" "${REPORT_LINK_FLAGS}" "${REPORT_TARGET}" "${REPORT_OUTPUT_NAME}${EXECUTABLE_EXTENSION}")
292+
293+
add_custom_target( displayReportCompileCommands
294+
${CMAKE_COMMAND} -E cmake_echo_color --cyan ""
295+
COMMENT "\nTo compile manually:\n${COMPILE_COMMAND}\nTo link manually:\n${LINK_COMMAND}")
296+
add_dependencies(${REPORT_TARGET} displayReportCompileCommands)
297+
298+
# Display the compile instructions in the fpga flow
299+
getCompileCommands("${COMMON_COMPILE_FLAGS}" "${FPGA_COMPILE_FLAGS}" "${COMMON_LINK_FLAGS}" "${FPGA_LINK_FLAGS}" "${FPGA_TARGET}" "${FPGA_OUTPUT_NAME}${EXECUTABLE_EXTENSION}")
300+
301+
add_custom_target( displayFPGACompileCommands
302+
${CMAKE_COMMAND} -E cmake_echo_color --cyan ""
303+
COMMENT "\nTo compile manually:\n${COMPILE_COMMAND}\nTo link manually:\n${LINK_COMMAND}")
304+
add_dependencies(${FPGA_TARGET} displayFPGACompileCommands)

0 commit comments

Comments
 (0)