1#
2# SPDX-FileCopyrightText: Copyright 2019-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
3#
4# SPDX-License-Identifier: Apache-2.0
5#
6# Licensed under the Apache License, Version 2.0 (the License); you may
7# not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10# www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an AS IS BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19cmake_minimum_required(VERSION 3.15.6)
20
21project(cmsis_nn_unit_tests VERSION 0.0.1)
22
23set(CMSIS_PATH "</path/to/CMSIS>" CACHE PATH "Path to CMSIS.")
24
25add_compile_options(-Ofast
26                    -fomit-frame-pointer
27                    -Werror
28                    -Wimplicit-function-declaration
29                    -Wunused-variable
30                    -Wunused-function
31                    -Wno-redundant-decls)
32
33option(BUILD_CMSIS_NN_UNIT "If building the unit tests from another project, i.e. \
34platform dependencies need to be provided externally." OFF)
35
36if (${CMSIS_PATH} STREQUAL "</path/to/CMSIS>")
37  message(FATAL_ERROR "CMSIS_PATH not set. Did you provide -DCMSIS_PATH=<path/to/CMSIS>?")
38endif()
39
40if(NOT BUILD_CMSIS_NN_UNIT)
41    set(BUILD_CMSIS_NN_UNIT_TESTS_FOR_FVP_BASED_CORSTONE_300 ON)
42else()
43    set(BUILD_CMSIS_NN_UNIT_TESTS_FOR_FVP_BASED_CORSTONE_300 OFF)
44endif()
45
46if(BUILD_CMSIS_NN_UNIT_TESTS_FOR_FVP_BASED_CORSTONE_300)
47    set(FVP_CORSTONE_300_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Corstone-300" CACHE PATH
48        "Dependencies for using FVP based on Arm Corstone-300 software.")
49    set(CMAKE_EXECUTABLE_SUFFIX ".elf")
50endif()
51
52# Build the functions to be tested.
53add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../.. cmsis-nn)
54
55# Target for all unit tests.
56add_custom_target(cmsis_nn_unit_tests)
57
58# This function should be used instead of add_executable.
59set_property(GLOBAL PROPERTY cmsis_nn_unit_test_executables)
60function(add_cmsis_nn_unit_test_executable)
61    get_property(tmp GLOBAL PROPERTY cmsis_nn_unit_test_executables)
62    foreach(target ${ARGV})
63        set(tmp "${tmp} ${target}")
64        add_executable(${target})
65        if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
66            target_link_options(${target} PRIVATE "--specs=nosys.specs")
67        endif()
68        add_dependencies(cmsis_nn_unit_tests ${target})
69    endforeach()
70    set_property(GLOBAL PROPERTY cmsis_nn_unit_test_executables "${tmp}")
71endfunction(add_cmsis_nn_unit_test_executable)
72
73add_subdirectory(TestCases/test_arm_avgpool_s16)
74add_subdirectory(TestCases/test_arm_avgpool_s8)
75add_subdirectory(TestCases/test_arm_convolve_1x1_s8_fast)
76add_subdirectory(TestCases/test_arm_convolve_fast_s16)
77add_subdirectory(TestCases/test_arm_convolve_s16)
78add_subdirectory(TestCases/test_arm_convolve_s8)
79add_subdirectory(TestCases/test_arm_convolve_1_x_n_s8)
80add_subdirectory(TestCases/test_arm_depthwise_conv_3x3_s8)
81add_subdirectory(TestCases/test_arm_depthwise_conv_fast_s16)
82add_subdirectory(TestCases/test_arm_depthwise_conv_s16)
83add_subdirectory(TestCases/test_arm_depthwise_conv_s8)
84add_subdirectory(TestCases/test_arm_depthwise_conv_s8_opt)
85add_subdirectory(TestCases/test_arm_elementwise_add_s16)
86add_subdirectory(TestCases/test_arm_elementwise_add_s8)
87add_subdirectory(TestCases/test_arm_elementwise_mul_s16)
88add_subdirectory(TestCases/test_arm_elementwise_mul_s8)
89add_subdirectory(TestCases/test_arm_fully_connected_s16)
90add_subdirectory(TestCases/test_arm_fully_connected_s8)
91add_subdirectory(TestCases/test_arm_lstm_unidirectional_s16_s8)
92add_subdirectory(TestCases/test_arm_max_pool_s16)
93add_subdirectory(TestCases/test_arm_max_pool_s8)
94add_subdirectory(TestCases/test_arm_softmax_s16)
95add_subdirectory(TestCases/test_arm_softmax_s8)
96add_subdirectory(TestCases/test_arm_softmax_s8_s16)
97add_subdirectory(TestCases/test_arm_svdf_s8)
98add_subdirectory(TestCases/test_arm_svdf_state_s16_s8)
99add_subdirectory(TestCases/test_arm_ds_cnn_l_s8)
100add_subdirectory(TestCases/test_arm_ds_cnn_s_s8)
101
102set(MAKE_CMD "python3")
103set(MAKE_CMD_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/unittest_targets.py")
104set(MAKE_CMD_SCRIPT_OPTION "--download-and-generate-test-runners")
105set(MAKE_CMD_SCRIPT_CMSIS_PATH "-p ${CMSIS_PATH}")
106MESSAGE(STATUS "Downloading Unity and generating test runners for CMSIS-NN unit tests if needed..")
107execute_process(COMMAND ${MAKE_CMD} ${MAKE_CMD_SCRIPT} ${MAKE_CMD_SCRIPT_OPTION} ${MAKE_CMD_SCRIPT_CMSIS_PATH}
108                        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
109add_subdirectory(Unity)
110
111# Link common dependencies.
112get_property(executables GLOBAL PROPERTY cmsis_nn_unit_test_executables)
113string(REPLACE " " ";" cmsis_nn_unit_test_list_of_executables ${executables})
114foreach(target ${cmsis_nn_unit_test_list_of_executables})
115    target_link_libraries(${target} LINK_PUBLIC unity)
116    target_link_libraries(${target} LINK_PUBLIC cmsis-nn)
117endforeach()
118
119if(BUILD_CMSIS_NN_UNIT_TESTS_FOR_FVP_BASED_CORSTONE_300)
120    add_library(retarget STATIC
121        ${FVP_CORSTONE_300_PATH}/retarget.c
122        ${FVP_CORSTONE_300_PATH}/uart.c)
123
124    # Build CMSIS startup dependencies based on TARGET_CPU.
125    string(REGEX REPLACE "^cortex-m([0-9]+)$" "ARMCM\\1" ARM_CPU ${CMAKE_SYSTEM_PROCESSOR})
126    if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "cortex-m33")
127        set(ARM_FEATURES "_DSP_FP")
128    elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "cortex-m4")
129        set(ARM_FEATURES "_FP")
130    elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "cortex-m7")
131        set(ARM_FEATURES "_DP")
132    else()
133        set(ARM_FEATURES "")
134    endif()
135    add_library(cmsis_startup STATIC)
136    target_sources(cmsis_startup PRIVATE
137        ${CMSIS_PATH}/Device/ARM/${ARM_CPU}/Source/startup_${ARM_CPU}.c
138        ${CMSIS_PATH}/Device/ARM/${ARM_CPU}/Source/system_${ARM_CPU}.c)
139    target_include_directories(cmsis_startup PUBLIC
140        ${CMSIS_PATH}/Device/ARM/${ARM_CPU}/Include
141        ${CMSIS_PATH}/CMSIS/Core/Include)
142    target_compile_options(cmsis_startup INTERFACE -include${ARM_CPU}${ARM_FEATURES}.h)
143    target_compile_definitions(cmsis_startup PRIVATE ${ARM_CPU}${ARM_FEATURES})
144
145    # Linker file settings.
146    set(LINK_FILE "${FVP_CORSTONE_300_PATH}/linker" CACHE PATH "Linker file.")
147    if (CMAKE_CXX_COMPILER_ID STREQUAL "ARMClang")
148        set(LINK_FILE "${FVP_CORSTONE_300_PATH}/linker.scatter")
149        set(LINK_FILE_OPTION "--scatter")
150        set(LINK_ENTRY_OPTION "--entry")
151        set(LINK_ENTRY "Reset_Handler")
152    elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
153        set(LINK_FILE "${FVP_CORSTONE_300_PATH}/linker.ld")
154        set(LINK_FILE_OPTION "-T")
155        set(LINK_ENTRY_OPTION "")
156        set(LINK_ENTRY "")
157    endif()
158
159    # Link in FVP dependencies to every unit test.
160    get_property(executables GLOBAL PROPERTY cmsis_nn_unit_test_executables)
161    string(REPLACE " " ";" cmsis_nn_unit_test_list_of_executables ${executables})
162    foreach(target ${cmsis_nn_unit_test_list_of_executables})
163        target_link_libraries(${target} PRIVATE retarget)
164        target_link_libraries(${target} PRIVATE $<TARGET_OBJECTS:cmsis_startup> cmsis_startup)
165
166        add_dependencies(${target} retarget cmsis_startup)
167
168        target_compile_definitions(${target} PUBLIC USING_FVP_CORSTONE_300)
169
170        target_link_options(${target} PRIVATE ${LINK_FILE_OPTION} ${LINK_FILE} ${LINK_ENTRY_OPTION} ${LINK_ENTRY})
171        set_target_properties(${target} PROPERTIES LINK_DEPENDS ${LINK_FILE})
172    endforeach()
173endif()
174