1#!/usr/bin/env bash 2# 3# SPDX-FileCopyrightText: Copyright 2024 Arm Limited and/or its affiliates <open-source-office@arm.com> 4# 5# SPDX-License-Identifier: Apache-2.0 6# 7# Licensed under the Apache License, Version 2.0 (the License); you may 8# not use this file except in compliance with the License. 9# You may obtain a copy of the License at 10# 11# www.apache.org/licenses/LICENSE-2.0 12# 13# Unless required by applicable law or agreed to in writing, software 14# distributed under the License is distributed on an AS IS BASIS, WITHOUT 15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16# See the License for the specific language governing permissions and 17# limitations under the License. 18# 19# Version: 1.0 20# Date: 2024-05-21 21# This bash script downloads unit test dependencies, builds unit tests and also runs the tests. 22 23CPU="cortex-m55" 24OPTIMIZATION="-Ofast" 25QUIET=0 26BUILD=1 27RUN=1 28SETUP_ENVIRONMENT=1 29USE_ARM_COMPILER=0 30USE_PYTHON_VENV=1 31USE_FVP_FROM_DOWNLOAD=1 32USE_GCC_FROM_DOWNLOAD=1 33 34ETHOS_U_CORE_PLATFORM_PATH="" 35CMSIS_5_PATH="" 36 37 38usage=" 39Helper script to setup, build and run CMSIS-NN unit tests 40 41args: 42 -h Display this message. 43 -c Target cpu. Takes multiple arguments as a comma seperated list. eg cortex-m3,cortex-m7,cortex-m55 (default: cortex-m55) 44 -o Optimization level. (default: '-Ofast') 45 -q Quiet mode. This reduces the amount of info printed from building and running cmsis-unit tests. 46 -b Disable CMake build. Only works with previously built targets. Designed to quickly rerun cpu targets. 47 -r Disable running the unit tests. Designed to test build only or allow user to manually run individual test cases outside of this script. 48 -e Disable environment setup. This flag will stop the script from attempting to download dependencies. This is just a quiet mode to reduce print outs. 49 -a Use Arm Compiler that is previously available on machine. Ensure compiler directory is added to path and export CC. 50 -p Disable the usage of python venv from download directory. Requires dependencies to be install before calling script. 51 -f Disable the usage of FVP from download directory. Requires FVP to be in path before calling script. 52 -u Path to ethos-u-core-platform 53 -g Disable the usage of GCC that is already from download directory. Requires gcc to be in path before calling script. 54 -C Path to cmsis 5 55 56 example usage: $(basename "$0") -c cortex-m3,cortex-m4 -o '-O2' -q 57" 58 59while getopts hc:o:qbreapfu:gC: flag 60do 61 case "${flag}" in 62 h) echo "${usage}" 63 exit 1;; 64 c) CPU=${OPTARG};; 65 o) OPTIMIZATION=${OPTARG};; 66 q) QUIET=1;; 67 b) BUILD=0;; 68 r) RUN=0;; 69 e) SETUP_ENVIRONMENT=0;; 70 a) USE_ARM_COMPILER=1;; 71 p) USE_PYTHON_VENV=0;; 72 f) USE_FVP_FROM_DOWNLOAD=0;; 73 u) ETHOS_U_CORE_PLATFORM_PATH="${OPTARG}";; 74 g) USE_GCC_FROM_DOWNLOAD=0;; 75 C) CMSIS_5_PATH="${OPTARG}";; 76 esac 77done 78 79Setup_Environment() { 80 set -e 81 echo "++ Downloading Corstone300" 82 if [[ -d ${WORKING_DIR}/corstone300_download ]]; then 83 echo "Corstone300 already installed. If you wish to install a new version, please delete the old folder." 84 else 85 if [[ ${UNAME_M} == x86_64 ]]; then 86 CORSTONE_URL=https://developer.arm.com/-/media/Arm%20Developer%20Community/Downloads/OSS/FVP/Corstone-300/FVP_Corstone_SSE-300_11.24_13_Linux64.tgz 87 elif [[ ${UNAME_M} == aarch64 ]]; then 88 CORSTONE_URL=https://developer.arm.com/-/media/Arm%20Developer%20Community/Downloads/OSS/FVP/Corstone-300/FVP_Corstone_SSE-300_11.24_13_Linux64_armv8l.tgz 89 fi 90 91 TEMPFILE=$(mktemp -d)/temp_file 92 wget ${CORSTONE_URL} -O ${TEMPFILE} >&2 93 94 TEMPDIR=$(mktemp -d) 95 tar -C ${TEMPDIR} -xvzf ${TEMPFILE} >&2 96 mkdir ${WORKING_DIR}/corstone300_download 97 ${TEMPDIR}/FVP_Corstone_SSE-300.sh --i-agree-to-the-contained-eula --no-interactive -d ${WORKING_DIR}/corstone300_download >&2 98 fi 99 100 echo "++ Downloading GCC" 101 if [[ -d ${WORKING_DIR}/arm_gcc_download ]]; then 102 echo "Arm GCC already installed. If you wish to install a new version, please delete the old folder." 103 else 104 if [[ ${UNAME_M} == x86_64 ]]; then 105 GCC_URL="https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-arm-none-eabi.tar.xz" 106 elif [[ ${UNAME_M} == aarch64 ]]; then 107 GCC_URL="https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-aarch64-arm-none-eabi.tar.xz" 108 fi 109 110 TEMPFILE=$(mktemp -d)/temp_file 111 wget ${GCC_URL} -O ${TEMPFILE} >&2 112 mkdir ${WORKING_DIR}/arm_gcc_download 113 114 tar -C ${WORKING_DIR}/arm_gcc_download --strip-components=1 -xJf ${TEMPFILE} >&2 115 fi 116 117 echo "++ Cloning CMSIS-5" 118 if [[ -d ${WORKING_DIR}/CMSIS_5 ]]; then 119 echo "CMSIS-5 already installed. If you wish to install a new version, please delete the old folder." 120 else 121 git clone https://github.com/ARM-software/CMSIS_5.git 122 fi 123 124 echo "++ Cloning Ethos-U core platform" 125 if [[ -d ${WORKING_DIR}/ethos-u-core-platform ]]; then 126 echo "Ethos-U core platform already installed. If you wish to install a new version, please delete the old folder." 127 else 128 git clone https://review.mlplatform.org/ml/ethos-u/ethos-u-core-platform 129 fi 130 131 echo "++ Setting up python environment" 132 if [[ -d ${WORKING_DIR}/cmsis_nn_venv ]]; then 133 echo "Python venv already installed. If you wish to install a new version, please delete the old folder." 134 else 135 python3 -m venv cmsis_nn_venv 136 source cmsis_nn_venv/bin/activate 137 pip3 install -r ../requirements.txt 138 deactivate 139 fi 140} 141 142Build_Tests() { 143 set -e 144 echo "++ Building Tests" 145 if [[ ${QUIET} -eq 0 ]]; then 146 cmake -S ./ -B build-${cpu}-${compiler} -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE} -DTARGET_CPU=${cpu} -DCMSIS_PATH=${CMSIS_5_PATH} -DCMSIS_OPTIMIZATION_LEVEL=${OPTIMIZATION} 147 cmake --build build-${cpu}-${compiler}/ 148 149 echo "Built successfully into build-${cpu}-${compiler}" 150 else 151 cmake_command=$(cmake -S ./ -B build-${cpu}-${compiler} -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE} -DTARGET_CPU=${cpu} -DCMSIS_PATH=${CMSIS_5_PATH} -DCMSIS_OPTIMIZATION_LEVEL=${OPTIMIZATION} 2>&1) 152 make_command=$(cmake --build build-${cpu}-${compiler}/ 2>&1) 153 echo "${cmake_command}" > build-${cpu}-${compiler}/cmake_command.txt 154 echo "${make_command}" > build-${cpu}-${compiler}/make_command.txt 155 156 echo "Built successfully into build-${cpu}-${compiler}" 157 fi 158} 159 160Run_Tests() { 161 set +e 162 echo "++ Running Unit Tests" 163 readarray -d '' tests < <(find ./build-${cpu}-${compiler}/ -iname "*.elf" -print0) 164 for test in "${tests[@]}" 165 do 166 echo "Test: ${test}" 167 output=$(FVP_Corstone_SSE-300_Ethos-U55 -C mps3_board.uart0.shutdown_on_eot=1 -C mps3_board.visualisation.disable-visualisation=1 -C mps3_board.telnetterminal0.start_telnet=0 -C mps3_board.uart0.out_file="-" -C mps3_board.uart0.unbuffered_output=1 ${test}) 168 echo "$output" | grep "0 Failures" -vqz 169 if [[ $? -eq 0 ]]; then 170 echo "${output}" 171 echo "${test} failed. Script exiting." 172 exit 1 173 elif [[ ${QUIET} -eq 0 ]]; then 174 echo "${output}" 175 fi 176 done 177 echo "Tests for ${cpu} ran successfully." 178} 179 180if [[ ${BUILD} -eq 0 && ${RUN} -eq 0 && ${SETUP_ENVIRONMENT} -eq 0 ]]; then 181 echo "All script functions are disabled. Script will exit and do nothing." 182 exit 1 183fi 184 185UNAME_M=$(uname -m) 186UNAME_S=$(uname -s) 187 188if [[ ${UNAME_S} != Linux ]]; then 189 echo "Error: This script only supports Linux." 190 exit 1 191fi 192 193mkdir -p downloads 194pushd downloads 195WORKING_DIR=$(pwd) 196 197if [[ ${SETUP_ENVIRONMENT} -eq 1 ]]; then 198 echo "++ Setting Environment" 199 Setup_Environment 200fi 201 202if [[ ${USE_PYTHON_VENV} -eq 1 ]]; then 203 source cmsis_nn_venv/bin/activate 204fi 205 206if [[ -z "${ETHOS_U_CORE_PLATFORM_PATH}" ]]; then 207 ETHOS_U_CORE_PLATFORM_PATH="${WORKING_DIR}/ethos-u-core-platform" 208fi 209 210if [[ -z "${CMSIS_5_PATH}" ]]; then 211 CMSIS_5_PATH="${WORKING_DIR}/CMSIS_5" 212fi 213 214popd 215IFS=',' read -r -a cpu_array <<< "$CPU" 216 217if [[ ${BUILD} -eq 1 || ${RUN} -eq 1 ]]; then 218 for cpu in "${cpu_array[@]}" 219 do 220 echo "++ Targetting ${cpu}" 221 if [[ ${USE_ARM_COMPILER} -eq 1 ]]; then 222 compiler="arm-compiler" 223 TOOLCHAIN_FILE=${ETHOS_U_CORE_PLATFORM_PATH}/cmake/toolchain/armclang.cmake 224 else 225 if [[ ${USE_GCC_FROM_DOWNLOAD} -eq 1 ]]; then 226 export PATH=${WORKING_DIR}/arm_gcc_download/bin/:${PATH} 227 fi 228 compiler="gcc" 229 TOOLCHAIN_FILE=${ETHOS_U_CORE_PLATFORM_PATH}/cmake/toolchain/arm-none-eabi-gcc.cmake 230 fi 231 232 if [[ $USE_FVP_FROM_DOWNLOAD -eq 1 ]]; then 233 if [[ ${UNAME_M} == x86_64 ]]; then 234 export PATH=${WORKING_DIR}/corstone300_download/models/Linux64_GCC-9.3/:${PATH} 235 elif [[ ${UNAME_M} == aarch64 ]]; then 236 export PATH=${WORKING_DIR}/corstone300_download/models/Linux64_armv8l_GCC-9.3/:${PATH} 237 fi 238 fi 239 240 if [[ ${BUILD} -eq 1 ]]; then 241 Build_Tests 242 fi 243 244 if [[ ${RUN} -eq 1 ]]; then 245 Run_Tests 246 fi 247 done 248fi 249 250echo "" 251echo "++ Tests for ${CPU} ran successfully" 252if [[ ${USE_PYTHON_VENV} -eq 1 ]]; then 253 deactivate 254fi