diff --git a/.github/workflows/test-neureka.yml b/.github/workflows/test-neureka.yml index c458122..a1ea66d 100644 --- a/.github/workflows/test-neureka.yml +++ b/.github/workflows/test-neureka.yml @@ -49,5 +49,5 @@ jobs: export PULP_RISCV_GCC_TOOLCHAIN=$GITHUB_WORKSPACE/toolchain/gnu source pulp-sdk/configs/siracusa.sh cd pulp-nnx/test - pytest test.py -T tests -R -A neureka --build-flow=make --wmem=tcdm - pytest test.py -T tests -R -A neureka --build-flow=make --wmem=sram + pytest test.py --test-dir tests --recursive --accelerator neureka --build-flow=make --wmem=tcdm + pytest test.py --test-dir tests --recursive --accelerator neureka --build-flow=make --wmem=sram diff --git a/.github/workflows/test-neureka_v2.yml b/.github/workflows/test-neureka_v2.yml index 4ee3049..604e6ec 100644 --- a/.github/workflows/test-neureka_v2.yml +++ b/.github/workflows/test-neureka_v2.yml @@ -57,4 +57,5 @@ jobs: export TOOLCHAIN_GNU_INSTALL_DIR=$GITHUB_WORKSPACE/toolchain/gnu export GVSOC=$GITHUB_WORKSPACE/gvsoc/install/bin/gvsoc cd pulp-nnx/test - pytest test.py -T tests -R -A neureka_v2 --build-flow=cmake --wmem=mram + pytest test.py --test-dir=tests --recursive --accelerator=neureka_v2 --build-flow=cmake --wmem=mram --app=pulp-nnx + pytest test.py --test-dir=tests --recursive --accelerator=neureka_v2 --build-flow=cmake --wmem=mram --app=pulp-nnx-hal diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 38d3372..b932c98 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -26,4 +26,4 @@ run_ne16_test: artifacts: untracked: true script: - - cd test && pytest test.py --test-dir tests --recursive -A ne16 + - cd test && pytest test.py --test-dir tests --recursive --accelerator ne16 diff --git a/CMakeLists.txt b/CMakeLists.txt index ccc952d..4c1a431 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,7 @@ project(pulp-nnx add_library(pulp-nnx STATIC) -target_sources(pulp-nnx PRIVATE util/pulp_nnx_util.c util/hwpe.c) -target_include_directories(pulp-nnx PUBLIC inc util) +target_include_directories(pulp-nnx PUBLIC inc) option(USE_NE16 "Use the NE16 accelerator.") option(USE_NEUREKA "Use the N-EUREKA accelerator.") @@ -20,6 +19,8 @@ endif() if (${USE_NE16}) message(STATUS "[PULP-NNX] Using the NE16 accelerator.") + add_subdirectory(ne16/hal) + target_link_libraries(pulp-nnx PUBLIC pulp-nnx-hal-ne16) target_sources(pulp-nnx PRIVATE ne16/bsp/ne16_pulp_bsp.c @@ -37,34 +38,32 @@ endif() if (${USE_NEUREKA}) message(STATUS "[PULP-NNX] Using the N-EUREKA accelerator.") + add_subdirectory(neureka/hal) + target_link_libraries(pulp-nnx PUBLIC pulp-nnx-hal-neureka) target_sources(pulp-nnx PRIVATE neureka/bsp/neureka_siracusa_bsp.c - neureka/hal/neureka.c - neureka/hal/neureka_task.c src/pulp_nnx_neureka.c ) target_include_directories(pulp-nnx PUBLIC neureka/bsp - neureka/hal neureka/gvsoc ) endif() if (${USE_NEUREKA_V2}) message(STATUS "[PULP-NNX] Using the N-EUREKA v2 accelerator.") + add_subdirectory(neureka_v2/hal) + target_link_libraries(pulp-nnx PUBLIC pulp-nnx-hal-neureka-v2) target_sources(pulp-nnx PRIVATE neureka_v2/bsp/neureka_v2_siracusa_bsp.c - neureka_v2/hal/neureka_v2.c - neureka_v2/hal/neureka_v2_task.c src/pulp_nnx_neureka_v2.c ) target_include_directories(pulp-nnx PUBLIC neureka_v2/bsp - neureka_v2/hal neureka_v2/gvsoc ) endif() diff --git a/ne16/hal/CMakeLists.txt b/ne16/hal/CMakeLists.txt new file mode 100644 index 0000000..1ec87db --- /dev/null +++ b/ne16/hal/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.18) + +project(pulp-nnx-hal-ne16 LANGUAGES C) + +add_library(pulp-nnx-hal-ne16 + STATIC + ne16.c + ne16_task.c +) + +target_include_directories(pulp-nnx-hal-ne16 PUBLIC .) + +add_subdirectory(../../util pulp-nnx-util) +target_link_libraries(pulp-nnx-hal-ne16 PUBLIC pulp-nnx-util) diff --git a/neureka/hal/CMakeLists.txt b/neureka/hal/CMakeLists.txt new file mode 100644 index 0000000..14b9f20 --- /dev/null +++ b/neureka/hal/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.18) + +project(pulp-nnx-hal-neureka LANGUAGES C) + +add_library(pulp-nnx-hal-neureka + STATIC + neureka.c + neureka_task.c +) + +target_include_directories(pulp-nnx-hal-neureka PUBLIC .) + +add_subdirectory(../../util pulp-nnx-util) +target_link_libraries(pulp-nnx-hal-neureka PUBLIC pulp-nnx-util) diff --git a/neureka_v2/hal/CMakeLists.txt b/neureka_v2/hal/CMakeLists.txt new file mode 100644 index 0000000..ae80728 --- /dev/null +++ b/neureka_v2/hal/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.18) + +project(pulp-nnx-hal-neureka-v2 LANGUAGES C) + +add_library(pulp-nnx-hal-neureka-v2 + STATIC + neureka_v2.c + neureka_v2_task.c +) + +target_include_directories(pulp-nnx-hal-neureka-v2 PUBLIC .) + +add_subdirectory(../../util pulp-nnx-util) +target_link_libraries(pulp-nnx-hal-neureka-v2 PUBLIC pulp-nnx-util) diff --git a/test/.gitignore b/test/.gitignore index 50a0e48..ac1b249 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1,10 +1,10 @@ BUILD build -app/build* +apps/**/build* +apps/**/gen __pycache__ .cache .pytest_cache -app/gen **/compile_commands.json **/*.log **/*.pt diff --git a/test/NnxBuildFlow.py b/test/NnxBuildFlow.py index ecd4e8d..7271591 100644 --- a/test/NnxBuildFlow.py +++ b/test/NnxBuildFlow.py @@ -8,10 +8,34 @@ from NnxMapping import NnxName +class AppName(Enum): + pulp_nnx = "pulp-nnx" + pulp_nnx_hal = "pulp-nnx-hal" + + def __str__(self): + return self.value + + def path(self): + return f"apps/{self}" + + +class Toolchain(Enum): + gnu = "gnu" + llvm = "llvm" + + def __str__(self): + return self.value + + class NnxBuildFlow(ABC): @abstractmethod - def __init__(self, nnxName: NnxName) -> None: ... + def __init__( + self, nnxName: NnxName, appName: AppName, toolchain: Toolchain + ) -> None: + self.nnxName = nnxName + self.appName = appName + self.toolchain = toolchain @abstractmethod def build(self) -> None: ... @@ -31,11 +55,10 @@ def cmd_run(cmd: str, env=None) -> str: class MakeBuildFlow(NnxBuildFlow): - BUILD_CMD = "make -C app all platform=gvsoc" - RUN_CMD = "make -C app run platform=gvsoc" - - def __init__(self, nnxName: NnxName) -> None: - self.nnxName = nnxName + def __init__( + self, nnxName: NnxName, appName: AppName, toolchain: Toolchain + ) -> None: + super().__init__(nnxName, appName, toolchain) def env(self) -> os._Environ: _env = os.environ @@ -43,11 +66,15 @@ def env(self) -> os._Environ: return _env def build(self) -> None: - Path("app/src/nnx_layer.c").touch() - _ = NnxBuildFlow.cmd_run(MakeBuildFlow.BUILD_CMD, self.env()) + Path(f"{self.appName.path()}/src/nnx_layer.c").touch() + _ = NnxBuildFlow.cmd_run( + f"make -C {self.appName.path()} all platform=gvsoc", self.env() + ) def run(self) -> str: - return NnxBuildFlow.cmd_run(MakeBuildFlow.RUN_CMD, self.env()) + return NnxBuildFlow.cmd_run( + f"make -C {self.appName.path()} run platform=gvsoc", self.env() + ) def __str__(self) -> str: return "make" @@ -55,19 +82,23 @@ def __str__(self) -> str: class CmakeBuildFlow(NnxBuildFlow): BINARY_NAME = "test-pulp-nnx" - TOOLCHAIN_FILE = "cmake/toolchain_gnu.cmake" GVSOC_TARGET = "siracusa" - def __init__(self, nnxName: NnxName) -> None: - self.nnxName = nnxName - self.build_dir = os.path.abspath(f"app/build_{nnxName}") + def __init__( + self, nnxName: NnxName, appName: AppName, toolchain: Toolchain + ) -> None: + super().__init__(nnxName, appName, toolchain) + self.build_dir = os.path.abspath( + f"{self.appName.path()}/build_{nnxName}_{toolchain}" + ) self.gvsoc_workdir = os.path.join(self.build_dir, "gvsoc_workdir") assert "GVSOC" in os.environ, "The GVSOC environment variable is not set." + self.toolchain_file = f"../../cmake/toolchain_{self.toolchain}.cmake" def prepare(self) -> None: os.makedirs(self.gvsoc_workdir, exist_ok=True) subprocess.run( - f"cmake -Sapp -B{self.build_dir} -GNinja -DCMAKE_TOOLCHAIN_FILE={CmakeBuildFlow.TOOLCHAIN_FILE} -DACCELERATOR={self.nnxName}".split(), + f"cmake -S{self.appName.path()} -B{self.build_dir} -GNinja -DCMAKE_TOOLCHAIN_FILE={self.toolchain_file} -DACCELERATOR={self.nnxName}".split(), check=True, ) diff --git a/test/NnxTestClasses.py b/test/NnxTestClasses.py index ae5856f..e7fc4eb 100644 --- a/test/NnxTestClasses.py +++ b/test/NnxTestClasses.py @@ -406,15 +406,11 @@ def source_generate( class NnxTestHeaderGenerator: - DEFAULT_HEADERS_DIR = "app/gen" - def __init__( self, nnxWeight: NnxWeight, - headers_dir: Optional[Union[str, os.PathLike]] = None, + headers_dir: Union[str, os.PathLike], ): - if headers_dir is None: - headers_dir = NnxTestHeaderGenerator.DEFAULT_HEADERS_DIR self.header_writer = HeaderWriter(headers_dir) # function that takes the weights in CoutCinK format, bitwidth, and a depthwise flag, # and returns a numpy array of dtype=np.uint8 of data in a layout correct for the accelerator diff --git a/test/README.md b/test/README.md index 5cc3e93..7f58afc 100644 --- a/test/README.md +++ b/test/README.md @@ -2,7 +2,7 @@ ## Repository structure -- app: test application +- app_*: test application - inc: test application headers - src: test application sources - gen_inc: generated test headers for data and test information @@ -36,6 +36,7 @@ $ pytest test.py --help For more information you can run the script with the `-h` flag. -## Application +## Applications -For information on the testing application and how to build it, take a look in its [README.md](app/README.md). +There are 2 applications provided, one testing the more abstract pulp_nnx interface and another one just the hardware abstraction layer, called `app_pulp_nnx` and `app_pulp_nnx_hal`. +For information on the testing applications and how to build them, take a look in their dedicated readmes: [app_pulp_nnx/README.md](app_pulp_nnx/README.md) and [app_pulp_nnx_hal/README.md](app_pulp_nnx_hal/README.md). diff --git a/test/app/cmake/pulp-sdk-siracusa.cmake b/test/app/cmake/pulp-sdk-siracusa.cmake deleted file mode 100644 index 1c117d7..0000000 --- a/test/app/cmake/pulp-sdk-siracusa.cmake +++ /dev/null @@ -1,62 +0,0 @@ -include(cmake/pulp-sdk-base.cmake) - -set(PULP_SDK_HOME $ENV{PULP_SDK_HOME}) - -set(SIRACUSA_COMPILE_FLAGS - -include ${PULP_SDK_HOME}/rtos/pulpos/pulp/include/pos/chips/siracusa/config.h - -DCONFIG_SIRACUSA - -DCONFIG_BOARD_VERSION_SIRACUSA - -DCONFIG_PROFILE_SIRACUSA - -DSKIP_PLL_INIT - -DUSE_HYPERFLASH - -DUSE_HYPERRAM - -DPULP_CHIP_STR=siracusa -) - -set(SIRACUSA_INCLUDES - ${PULP_SDK_HOME}/rtos/pulpos/pulp/include/pos/chips/siracusa - ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/i3c/include - ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/siracusa_padmux/include -) - -set(PULP_SDK_SIRACUSA_C_SOURCE - ${PULP_SDK_HOME}/rtos/pulpos/pulp/kernel/chips/siracusa/pll.c - ${PULP_SDK_HOME}/rtos/pulpos/pulp/kernel/chips/siracusa/soc.c - ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/i3c/src/cdn_print.c - ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/i3c/src/command_list.c - #${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/i3c/src/i3c.c - ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/i3c/src/i3c_obj_if.c - ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/i3c/src/cps_impl.c - ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/siracusa_padmux/src/siracusa_padctrl.c -) - -set_source_files_properties(${PULP_SDK_SIRACUSA_ASM_SOURCE} PROPERTIES COMPILE_FLAGS -DLANGUAGE_ASSEMBLY) - -add_library(pulp-sdk OBJECT ${PULP_SDK_BASE_C_SOURCE} ${PULP_SDK_BASE_ASM_SOURCE} ${PULP_SDK_SIRACUSA_C_SOURCE} ${PULP_SDK_SIRACUSA_ASM_SOURCE}) - -set(PULP_SDK_COMPILE_FLAGS ${SIRACUSA_COMPILE_FLAGS} ${PULP_SDK_BASE_COMPILE_FLAGS}) -set(PULP_SDK_INCLUDES ${SIRACUSA_INCLUDES} ${PULP_SDK_BASE_INCLUDE}) - -target_include_directories(pulp-sdk SYSTEM PUBLIC ${PULP_SDK_INCLUDES}) -target_compile_options(pulp-sdk PUBLIC ${PULP_SDK_COMPILE_FLAGS}) -target_compile_options(pulp-sdk PRIVATE - -Wno-sign-conversion - -Wno-unused-function - -Wno-unused-parameter - -Wno-conversion - -Wno-sign-conversion - -Wno-unused-variable - -Wno-sign-compare - -Wno-return-type - -fno-inline-functions -) - -target_compile_options(pulp-sdk INTERFACE - -Wno-unused-function -) - -target_link_options(pulp-sdk PUBLIC - -Wl,--gc-sections - -L${PULP_SDK_HOME}/rtos/pulpos/pulp/kernel - -Tchips/siracusa/link.ld -) diff --git a/test/app/README.md b/test/apps/README.md similarity index 62% rename from test/app/README.md rename to test/apps/README.md index aa9a03a..ff12af7 100644 --- a/test/app/README.md +++ b/test/apps/README.md @@ -1,4 +1,10 @@ -# Test application +# Test applications + +There are 2 testing applications: +1. pulp-nnx - tests the whole library +2. pulp-nnx-hal - tests just the hardware abstraction layer parts + +Both apps are very similar except for the fact that the Make build flow is not implemented for the pulp-nnx-hal app. ## Build @@ -6,6 +12,13 @@ There are two build flows given for the test app, the Make one and the CMake one Both flows use a flag `ACCELERATOR` to decide which accelerator to build the application for. Choices are _neureka_ and _neureka_v2_. +### Environment variables + +Both build fows expect some environment variables to be set and will fail if they are not set: +- `GVSOC` - path to the `gvsoc` executable (not the directory) +- `TOOLCHAIN_LLVM_INSTALL_DIR` - path to the llvm install directory +- `PULP_SDK_HOME` - path to the pulp-sdk directory + ### Make For the Make flow you need to specify the `ACCELERATOR` flag either as an environment variable @@ -30,7 +43,3 @@ cmake --build build ``` No need to regenerate the project (1st cmake command) after altering the sources, just rerun the build. - -## TODO - -- environment variables that need to be set diff --git a/test/apps/pulp-nnx-hal/CMakeLists.txt b/test/apps/pulp-nnx-hal/CMakeLists.txt new file mode 100644 index 0000000..a4326d6 --- /dev/null +++ b/test/apps/pulp-nnx-hal/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.18) + +# This is to omit the cross-compilation test +set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") + +project(test-pulp-nnx + LANGUAGES C ASM) + +add_executable(test-pulp-nnx) + +file(GLOB gen_srcs CONFIGURE_DEPENDS gen/src/*.c) +set(app_srcs src/main.c src/nnx_layer.c) + +target_sources(test-pulp-nnx PRIVATE ${app_srcs} ${gen_srcs}) +target_include_directories(test-pulp-nnx PRIVATE inc gen/inc) + +set(NUM_CORES 8 CACHE STRING "Set the number of cores used. Default 8") +set(ACCELERATOR neureka CACHE STRING "Choose an accelerator to compile the library for. Default ne16") +set_property(CACHE ACCELERATOR PROPERTY STRINGS neureka neureka_v2) + +add_compile_options(-DNUM_CORES=${NUM_CORES}) + +include(../../cmake/pulp-sdk-siracusa.cmake) +target_link_libraries(test-pulp-nnx PRIVATE pulp-sdk) + +if(${ACCELERATOR} STREQUAL neureka) + add_subdirectory(../../../neureka/hal pulp-nnx-hal) + target_link_libraries(test-pulp-nnx PRIVATE pulp-nnx-hal-neureka) + target_compile_definitions(test-pulp-nnx PRIVATE NNX_ACCELERATOR="neureka" NNX_NEUREKA) +elseif(${ACCELERATOR} STREQUAL neureka_v2) + add_subdirectory(../../../neureka_v2/hal pulp-nnx-hal) + target_link_libraries(test-pulp-nnx PRIVATE pulp-nnx-hal-neureka-v2) + target_compile_definitions(test-pulp-nnx PRIVATE NNX_ACCELERATOR="neureka_v2" NNX_NEUREKA_V2) +else() + message(FATAL_ERROR "Unrecognized accelerator detected: \"${ACCELERATOR}\"") +endif() diff --git a/test/app/inc/layer_util.h b/test/apps/pulp-nnx-hal/inc/layer_util.h similarity index 100% rename from test/app/inc/layer_util.h rename to test/apps/pulp-nnx-hal/inc/layer_util.h diff --git a/test/app/inc/nnx_layer.h b/test/apps/pulp-nnx-hal/inc/nnx_layer.h similarity index 100% rename from test/app/inc/nnx_layer.h rename to test/apps/pulp-nnx-hal/inc/nnx_layer.h diff --git a/test/app/src/main.c b/test/apps/pulp-nnx-hal/src/main.c similarity index 100% rename from test/app/src/main.c rename to test/apps/pulp-nnx-hal/src/main.c diff --git a/test/apps/pulp-nnx-hal/src/nnx_layer.c b/test/apps/pulp-nnx-hal/src/nnx_layer.c new file mode 100644 index 0000000..f39dc79 --- /dev/null +++ b/test/apps/pulp-nnx-hal/src/nnx_layer.c @@ -0,0 +1,259 @@ +/* + * Luka Macan + * + * Copyright 2023 ETH Zurich and University of Bologna + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nnx_layer.h" +#include + +#ifdef NNX_NE16 + +#include "ne16.h" +#include "ne16_task.h" + +typedef ne16_norm_mode_e nnx_norm_mode_e; +typedef ne16_quant_t nnx_quant_t; +typedef ne16_quant_function_e nnx_quant_function_e; +typedef ne16_norm_t nnx_norm_t; +typedef ne16_task_t nnx_task_t; +typedef ne16_task_flag_e nnx_task_flag_e; +typedef ne16_task_data_t nnx_task_data_t; + +// Minimal copy from ne16/bsp/ne16_pulp_bsp.c +#ifndef NE16_PULP_BASE_ADDR +#define NE16_PULP_BASE_ADDR (0x00201000) +#endif +static const ne16_dev_t nnx_dev = { + .hwpe_dev = (struct hwpe_dev_t){ + .base_addr = (volatile uint32_t *)NE16_PULP_BASE_ADDR}}; + +#define nnxTaskFlagTrue ne16TaskFlagTrue +#define nnxTaskFlagFalse ne16TaskFlagFalse + +#define nnx_task_init ne16_task_init +#define nnx_task_set_op_to_conv ne16_task_set_op_to_conv +#define nnx_task_set_bits ne16_task_set_bits +#define nnx_task_set_norm_quant ne16_task_set_norm_quant +#define nnx_task_set_weight_offset ne16_task_set_weight_offset +#define nnx_task_set_dims ne16_task_set_dims +#define nnx_task_set_dims_stride2x2 ne16_task_set_dims_stride2x2 +#define nnx_task_set_addr_conv ne16_task_set_addr_conv +#define nnx_task_set_addr_norm_quant ne16_task_set_addr_norm_quant + +#define nnx_task_queue_empty ne16_task_queue_empty + +#elif defined NNX_NEUREKA + +#include "neureka.h" +#include "neureka_task.h" + +typedef neureka_norm_mode_e nnx_norm_mode_e; +typedef neureka_quant_t nnx_quant_t; +typedef neureka_quant_function_e nnx_quant_function_e; +typedef neureka_norm_t nnx_norm_t; +typedef neureka_task_t nnx_task_t; +typedef neureka_task_flag_e nnx_task_flag_e; +typedef neureka_task_data_t nnx_task_data_t; + +// Minimal copy from neureka/bsp/neureka_siracusa_bsp.c +#ifndef NEUREKA_SIRACUSA_BASE_ADDR +#define NEUREKA_SIRACUSA_BASE_ADDR (0x00201000) +#endif +static const neureka_dev_t nnx_dev = { + .hwpe_dev = (struct hwpe_dev_t){ + .base_addr = (volatile uint32_t *)NEUREKA_SIRACUSA_BASE_ADDR}}; + +#define nnxTaskFlagTrue neurekaTaskFlagTrue +#define nnxTaskFlagFalse neurekaTaskFlagFalse + +#define nnx_task_init neureka_task_init +#define nnx_task_set_op_to_conv neureka_task_set_op_to_conv +#define nnx_task_set_bits neureka_task_set_bits +#define nnx_task_set_norm_quant neureka_task_set_norm_quant +#define nnx_task_set_weight_offset neureka_task_set_weight_offset +#define nnx_task_set_dims neureka_task_set_dims +#define nnx_task_set_addr_conv neureka_task_set_addr_conv +#define nnx_task_set_addr_norm_quant neureka_task_set_addr_norm_quant + +#define nnx_task_queue_empty neureka_task_queue_empty + +#elif defined NNX_NEUREKA_V2 + +#include "neureka_v2.h" +#include "neureka_v2_task.h" + +typedef neureka_v2_norm_mode_e nnx_norm_mode_e; +typedef neureka_v2_quant_t nnx_quant_t; +typedef neureka_v2_quant_function_e nnx_quant_function_e; +typedef neureka_v2_norm_t nnx_norm_t; +typedef neureka_v2_task_t nnx_task_t; +typedef neureka_v2_task_flag_e nnx_task_flag_e; +typedef neureka_v2_task_data_t nnx_task_data_t; + +// Minimal copy from neureka_v2/bsp/neureka_v2_siracusa_bsp.c +#ifndef NEUREKA_V2_SIRACUSA_BASE_ADDR +#define NEUREKA_V2_SIRACUSA_BASE_ADDR (0x00201000) +#endif +static const neureka_v2_dev_t nnx_dev = { + .hwpe_dev = (struct hwpe_dev_t){ + .base_addr = (volatile uint32_t *)NEUREKA_V2_SIRACUSA_BASE_ADDR}}; + +#define nnxTaskFlagTrue neurekaV2TaskFlagTrue +#define nnxTaskFlagFalse neurekaV2TaskFlagFalse + +#define nnx_task_init neureka_v2_task_init +#define nnx_task_set_op_to_conv neureka_v2_task_set_op_to_conv +#define nnx_task_set_bits neureka_v2_task_set_bits +#define nnx_task_set_norm_quant neureka_v2_task_set_norm_quant +#define nnx_task_set_weight_offset neureka_v2_task_set_weight_offset +#define nnx_task_set_dims neureka_v2_task_set_dims +#define nnx_task_set_addr_conv neureka_v2_task_set_addr_conv +#define nnx_task_set_addr_norm_quant neureka_v2_task_set_addr_norm_quant + +#define nnx_task_queue_empty neureka_v2_task_queue_empty + +#endif // NNX_NE16 || NNX_NEUREKA || NNX_NEUREKA_V2 + +// Generated headers +#include "input.h" +#include "output.h" +#include "weight.h" + +#include "layer_conf.h" + +// The HAS_NORM_QUANT and HAS_BIAS are defined in layer_conf.h +#if HAS_NORM_QUANT != 0 +#include "scale.h" +#if HAS_BIAS != 0 +#include "bias.h" +#endif +#endif + +static void task_prepare(nnx_task_t *task) { + nnx_task_init(task); +#if defined NNX_NEUREKA || defined NNX_NEUREKA_V2 + nnx_task_set_op_to_conv(task, WEIGHT_HEIGHT, GROUPS > 1); +#else + nnx_task_set_op_to_conv(task, WEIGHT_HEIGHT, GROUPS > 1, STRIDE_HEIGHT); +#endif + nnx_task_set_bits(task, INPUT_BITS, OUTPUT_BITS, WEIGHT_BITS); + +#if defined NNX_NE16 || defined NNX_NEUREKA + nnx_task_set_weight_offset(task, weightOffsetModeLayerWise, WEIGHT_OFFSET); +#elif defined NNX_NEUREKA_V2 + nnx_task_set_weight_offset(task, WEIGHT_OFFSET); +#endif + +#ifdef NNX_NEUREKA +#if INPUT_SIGNED == 1 + neureka_task_set_input_signed(task); +#else + neureka_task_set_input_unsigned(task); +#endif +#if defined WMEM_SRAM || defined WMEM_MRAM + neureka_task_set_weight_source(task, neurekaWeightSourceWmem); +#else + neureka_task_set_weight_source(task, neurekaWeightSourceTcdm); +#endif +#endif + +#ifdef NNX_NEUREKA_V2 +#if INPUT_SIGNED == 1 + neureka_v2_task_set_activation_signed(task); +#else + neureka_v2_task_set_activation_unsigned(task); +#endif +#if OUTPUT_SIGNED == 1 + neureka_v2_task_set_outfeat_signed(task); +#else + neureka_v2_task_set_outfeat_unsigned(task); +#endif +#if defined WMEM_SRAM || defined WMEM_MRAM + neureka_v2_task_set_weight_source(task, neurekaV2WeightSourceWmem); +#else + neureka_v2_task_set_weight_source(task, neurekaV2WeightSourceTcdm); +#endif +#endif + + const uint32_t w_in_stride = INPUT_CHANNEL * INPUT_BITS / 8; + const uint32_t h_in_stride = INPUT_WIDTH * w_in_stride; + const uint32_t w_out_stride = OUTPUT_CHANNEL * OUTPUT_BITS / 8; + const uint32_t h_out_stride = OUTPUT_WIDTH * w_out_stride; + +#if STRIDE_HEIGHT == 2 && STRIDE_WIDTH == 2 + nnx_task_set_dims_stride2x2( + task, INPUT_HEIGHT, INPUT_WIDTH, INPUT_CHANNEL, h_in_stride, w_in_stride, + OUTPUT_HEIGHT, OUTPUT_WIDTH, OUTPUT_CHANNEL, h_out_stride, w_out_stride, + WEIGHT_HEIGHT, WEIGHT_WIDTH, PADDING_TOP, PADDING_BOTTOM, PADDING_LEFT, + PADDING_RIGHT); +#else + nnx_task_set_dims(task, INPUT_WIDTH, INPUT_CHANNEL, h_in_stride, w_in_stride, + OUTPUT_HEIGHT, OUTPUT_WIDTH, OUTPUT_CHANNEL, h_out_stride, + w_out_stride, PADDING_TOP, PADDING_BOTTOM, PADDING_LEFT, + PADDING_RIGHT); +#endif + + nnx_task_set_addr_conv(task, (uint32_t)input, INPUT_WIDTH, w_in_stride, + PADDING_TOP, PADDING_LEFT, (uint32_t)output, + (uint32_t)weight); + +#if HAS_NORM_QUANT == 1 +#if SCALE_BITS == 8 + const nnx_norm_mode_e normMode = normMode8Bit; +#elif SCALE_BITS == 32 + const nnx_norm_mode_e normMode = normMode32Bit; +#endif + + const nnx_task_flag_e flag_bias = + HAS_BIAS ? nnxTaskFlagTrue : nnxTaskFlagFalse; +#if HAS_BIAS == 1 + const uint32_t bias_addr = (uint32_t)bias; +#else + const uint32_t bias_addr = (uint32_t)NULL; +#endif + + nnx_quant_function_e quant_function = + HAS_RELU ? quantFunctionRelu : quantFunctionIdentity; + + nnx_task_set_norm_quant(task, + (nnx_quant_t){.shift_amount = OUTSHIFT, + .function = quant_function, + .flag_rounding = nnxTaskFlagFalse}, + (nnx_norm_t){.mode = normMode, + .flag_bias = flag_bias, + .flag_shift = nnxTaskFlagFalse}); + + nnx_task_set_addr_norm_quant(task, (uint32_t)scale, (uint32_t)NULL, + bias_addr); +#endif // HAS_NORM_QUANT +} + +static void task_execute(nnx_task_t *task) { + hwpe_task_queue_acquire_task(&nnx_dev.hwpe_dev, &task->id); + hwpe_task_queue_write_task(&nnx_dev.hwpe_dev, (uint32_t *)&task->data, + (int)(sizeof(nnx_task_data_t) / 4)); + hwpe_task_queue_release_and_run(&nnx_dev.hwpe_dev); + while (!nnx_task_queue_empty(&nnx_dev)) + ; +} + +void execute_nnx_layer(void *args) { + nnx_task_t task; + task_prepare(&task); + task_execute(&task); +} diff --git a/test/app/CMakeLists.txt b/test/apps/pulp-nnx/CMakeLists.txt similarity index 94% rename from test/app/CMakeLists.txt rename to test/apps/pulp-nnx/CMakeLists.txt index 1c44488..f9b3728 100644 --- a/test/app/CMakeLists.txt +++ b/test/apps/pulp-nnx/CMakeLists.txt @@ -20,7 +20,7 @@ set_property(CACHE ACCELERATOR PROPERTY STRINGS neureka neureka_v2) add_compile_options(-DNUM_CORES=${NUM_CORES}) -include(cmake/pulp-sdk-siracusa.cmake) +include(../../cmake/pulp-sdk-siracusa.cmake) target_link_libraries(test-pulp-nnx PRIVATE pulp-sdk) if(${ACCELERATOR} STREQUAL neureka) @@ -33,7 +33,7 @@ else() message(FATAL_ERROR "Unrecognized accelerator detected: \"${ACCELERATOR}\"") endif() -add_subdirectory(../.. pulp-nnx) +add_subdirectory(../../.. pulp-nnx) target_link_libraries(pulp-nnx PUBLIC pulp-sdk) target_include_directories(pulp-nnx SYSTEM PUBLIC ${PULP_SDK_INCLUDES}) target_link_libraries(test-pulp-nnx PRIVATE pulp-nnx) diff --git a/test/app/Makefile b/test/apps/pulp-nnx/Makefile similarity index 98% rename from test/app/Makefile rename to test/apps/pulp-nnx/Makefile index ca65892..b150d30 100644 --- a/test/app/Makefile +++ b/test/apps/pulp-nnx/Makefile @@ -21,7 +21,7 @@ ACCELERATOR ?= ne16 APP := main -LIBDIR := $(abspath ../..) +LIBDIR := $(abspath ../../..) ACC_DIR := $(LIBDIR)/$(ACCELERATOR) diff --git a/test/apps/pulp-nnx/inc/layer_util.h b/test/apps/pulp-nnx/inc/layer_util.h new file mode 100644 index 0000000..e44ede9 --- /dev/null +++ b/test/apps/pulp-nnx/inc/layer_util.h @@ -0,0 +1,40 @@ +/* + * Luka Macan + * + * Copyright 2023 ETH Zurich and University of Bologna + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __LAYER_UTIL_H__ +#define __LAYER_UTIL_H__ + +#include "layer_conf.h" +#include + +static void layer_info() { + printf("Layer info:\n" + " - input: (%dx%dx%d)\n" + " - output: (%dx%dx%d)\n" + " - weight: (%dx%dx%dx%d)\n" + " - stride: (%dx%d)\n" + " - padding: (%dx%dx%dx%d)\n", + INPUT_HEIGHT, INPUT_WIDTH, INPUT_CHANNEL, OUTPUT_HEIGHT, OUTPUT_WIDTH, + OUTPUT_CHANNEL, WEIGHT_CHANNEL_OUT, WEIGHT_HEIGHT, WEIGHT_WIDTH, + WEIGHT_CHANNEL_IN, STRIDE_HEIGHT, STRIDE_WIDTH, PADDING_TOP, + PADDING_BOTTOM, PADDING_LEFT, PADDING_RIGHT); +} + +#endif // __LAYER_UTIL_H__ diff --git a/test/apps/pulp-nnx/inc/nnx_layer.h b/test/apps/pulp-nnx/inc/nnx_layer.h new file mode 100644 index 0000000..cbaf4b9 --- /dev/null +++ b/test/apps/pulp-nnx/inc/nnx_layer.h @@ -0,0 +1,26 @@ +/* + * Luka Macan + * + * Copyright 2023 ETH Zurich and University of Bologna + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __NNX_LAYER_H__ +#define __NNX_LAYER_H__ + +void execute_nnx_layer(void *unused_args); + +#endif // __NNX_LAYER_H__ diff --git a/test/apps/pulp-nnx/src/main.c b/test/apps/pulp-nnx/src/main.c new file mode 100644 index 0000000..d488a3b --- /dev/null +++ b/test/apps/pulp-nnx/src/main.c @@ -0,0 +1,66 @@ +/* + * Luka Macan + * + * Copyright 2023 ETH Zurich and University of Bologna + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "layer_util.h" +#include "nnx_layer.h" +#include "output.h" +#ifdef NNX_NEUREKA_V2 +#include "string.h" +#include "weight.h" +#include "weight_l2.h" +#endif + +int main() { + struct pi_device cl_dev; + struct pi_cluster_conf cl_conf; + struct pi_cluster_task cl_task; + + printf("\nTest " TEST_NAME " starting\n"); + + printf("\nAccelerator: " NNX_ACCELERATOR "\n"); + + printf("\n"); + layer_info(); + +#ifdef NNX_NEUREKA_V2 + // We have to initialize the mram/sram weight memory from l2 + memcpy((void *)weight, (void *)weight_l2, WEIGHT_SIZE); +#endif + + pi_cluster_conf_init(&cl_conf); + pi_open_from_conf(&cl_dev, &cl_conf); + if (pi_cluster_open(&cl_dev)) { + printf("ERROR: Failed to open cluster.\n"); + pmsis_exit(-1); + } + pi_cluster_send_task_to_cl( + &cl_dev, pi_cluster_task(&cl_task, execute_nnx_layer, NULL)); + + printf("\n"); + check_output(); + + pi_cluster_close(&cl_dev); + + printf("\nTest " TEST_NAME " finished\n"); + + return 0; +} diff --git a/test/app/src/nnx_layer.c b/test/apps/pulp-nnx/src/nnx_layer.c similarity index 100% rename from test/app/src/nnx_layer.c rename to test/apps/pulp-nnx/src/nnx_layer.c diff --git a/test/app/cmake/pulp-sdk-base.cmake b/test/cmake/pulp-sdk-siracusa.cmake similarity index 61% rename from test/app/cmake/pulp-sdk-base.cmake rename to test/cmake/pulp-sdk-siracusa.cmake index 850373b..e0c063f 100644 --- a/test/app/cmake/pulp-sdk-base.cmake +++ b/test/cmake/pulp-sdk-siracusa.cmake @@ -73,3 +73,62 @@ set(PULP_SDK_BASE_COMPILE_FLAGS ) set_source_files_properties(${PULP_SDK_BASE_ASM_SOURCE} PROPERTIES COMPILE_FLAGS -DLANGUAGE_ASSEMBLY) + +set(SIRACUSA_COMPILE_FLAGS + -include ${PULP_SDK_HOME}/rtos/pulpos/pulp/include/pos/chips/siracusa/config.h + -DCONFIG_SIRACUSA + -DCONFIG_BOARD_VERSION_SIRACUSA + -DCONFIG_PROFILE_SIRACUSA + -DSKIP_PLL_INIT + -DUSE_HYPERFLASH + -DUSE_HYPERRAM + -DPULP_CHIP_STR=siracusa +) + +set(SIRACUSA_INCLUDES + ${PULP_SDK_HOME}/rtos/pulpos/pulp/include/pos/chips/siracusa + ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/i3c/include + ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/siracusa_padmux/include +) + +set(PULP_SDK_SIRACUSA_C_SOURCE + ${PULP_SDK_HOME}/rtos/pulpos/pulp/kernel/chips/siracusa/pll.c + ${PULP_SDK_HOME}/rtos/pulpos/pulp/kernel/chips/siracusa/soc.c + ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/i3c/src/cdn_print.c + ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/i3c/src/command_list.c + #${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/i3c/src/i3c.c + ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/i3c/src/i3c_obj_if.c + ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/i3c/src/cps_impl.c + ${PULP_SDK_HOME}/rtos/pulpos/pulp/drivers/siracusa_padmux/src/siracusa_padctrl.c +) + +set_source_files_properties(${PULP_SDK_SIRACUSA_ASM_SOURCE} PROPERTIES COMPILE_FLAGS -DLANGUAGE_ASSEMBLY) + +add_library(pulp-sdk OBJECT ${PULP_SDK_BASE_C_SOURCE} ${PULP_SDK_BASE_ASM_SOURCE} ${PULP_SDK_SIRACUSA_C_SOURCE} ${PULP_SDK_SIRACUSA_ASM_SOURCE}) + +set(PULP_SDK_COMPILE_FLAGS ${SIRACUSA_COMPILE_FLAGS} ${PULP_SDK_BASE_COMPILE_FLAGS}) +set(PULP_SDK_INCLUDES ${SIRACUSA_INCLUDES} ${PULP_SDK_BASE_INCLUDE}) + +target_include_directories(pulp-sdk SYSTEM PUBLIC ${PULP_SDK_INCLUDES}) +target_compile_options(pulp-sdk PUBLIC ${PULP_SDK_COMPILE_FLAGS}) +target_compile_options(pulp-sdk PRIVATE + -Wno-sign-conversion + -Wno-unused-function + -Wno-unused-parameter + -Wno-conversion + -Wno-sign-conversion + -Wno-unused-variable + -Wno-sign-compare + -Wno-return-type + -fno-inline-functions +) + +target_compile_options(pulp-sdk INTERFACE + -Wno-unused-function +) + +target_link_options(pulp-sdk PUBLIC + -Wl,--gc-sections + -L${PULP_SDK_HOME}/rtos/pulpos/pulp/kernel + -Tchips/siracusa/link.ld +) diff --git a/test/app/cmake/toolchain_gnu.cmake b/test/cmake/toolchain_gnu.cmake similarity index 100% rename from test/app/cmake/toolchain_gnu.cmake rename to test/cmake/toolchain_gnu.cmake diff --git a/test/cmake/toolchain_llvm.cmake b/test/cmake/toolchain_llvm.cmake new file mode 100644 index 0000000..d979ee3 --- /dev/null +++ b/test/cmake/toolchain_llvm.cmake @@ -0,0 +1,63 @@ +if (NOT DEFINED ENV{TOOLCHAIN_LLVM_INSTALL_DIR}) + message(FATAL_ERROR "Environment variable TOOLCHAIN_LLVM_INSTALL_DIR not defined.") +endif() + +if (NOT DEFINED ENV{TOOLCHAIN_LLVM_LIBC_DIR}) + message(FATAL_ERROR "Environemnt variable TOOLCHAIN_LLVM_LIBC_DIR not defined.") +endif() + +if (NOT DEFINED ENV{TOOLCHAIN_LLVM_COMPILER_RT_DIR}) + message(FATAL_ERROR "Environemnt variable TOOLCHAIN_LLVM_COMPILER_RT_DIR not defined.") +endif() + +set(TOOLCHAIN_BIN $ENV{TOOLCHAIN_LLVM_INSTALL_DIR}/bin) +set(LIBC $ENV{TOOLCHAIN_LLVM_LIBC_DIR}) +set(COMPILER_RT $ENV{TOOLCHAIN_LLVM_COMPILER_RT_DIR}) + +set(CMAKE_SYSTEM_NAME Generic) + +set(CMAKE_C_COMPILER ${TOOLCHAIN_BIN}/clang) +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_BIN}/clang++) +set(CMAKE_ASM_COMPILER ${TOOLCHAIN_BIN}/clang) +set(CMAKE_OBJCOPY ${TOOLCHAIN_BIN}/llvm-objcopy) +set(CMAKE_OBJDUMP ${TOOLCHAIN_BIN}/llvm-objdump) + +set(ISA rv32imc_zfinx_xpulpv2) + +set(CMAKE_EXECUTABLE_SUFFIX ".elf") + +add_compile_options( + -target riscv32-unknown-elf + -march=${ISA} + -ffunction-sections + -fdata-sections + -fomit-frame-pointer + -mno-relax + -O3 + -DNUM_CORES=${NUM_CORES} + -MMD + -MP + --sysroot=${LIBC} + -fno-builtin-memcpy + -fno-builtin-memset +) + +add_link_options( + -target riscv32-unknown-elf + -MMD + -MP + -nostartfiles + -march=${ISA} + --sysroot=${LIBC} + -L${COMPILER_RT} + -z norelro + -fno-builtin-memcpy + -fno-builtin-memset +) + +link_libraries( + -lm +) + +add_compile_definitions(__LINK_LD) +add_compile_definitions(__TOOLCHAIN_LLVM__) diff --git a/test/conftest.py b/test/conftest.py index dfbb909..f24f8ff 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -22,7 +22,7 @@ import pydantic import pytest -from NnxBuildFlow import CmakeBuildFlow, NnxBuildFlowName +from NnxBuildFlow import AppName, CmakeBuildFlow, NnxBuildFlowName, Toolchain from NnxMapping import NnxMapping, NnxName from NnxTestClasses import NnxTest, NnxTestGenerator, NnxWmem from TestClasses import implies @@ -76,6 +76,20 @@ def pytest_addoption(parser): default=NnxWmem.tcdm, help="Choose the weight memory destination. Default: tcdm", ) + parser.addoption( + "--app", + type=AppName, + choices=list(AppName), + default=AppName.pulp_nnx, + help="Choose an app to test. Default: pulp-nnx", + ) + parser.addoption( + "--toolchain", + type=Toolchain, + choices=list(Toolchain), + default=Toolchain.gnu, + help="Choose an app to test. Default: gnu", + ) @pytest.fixture @@ -86,14 +100,24 @@ def nnxName(request) -> NnxName: @pytest.fixture def buildFlowName(request) -> NnxBuildFlowName: nnxName = request.config.getoption("--accelerator") + appName = request.config.getoption("app") buildFlowName = request.config.getoption("buildFlowName") + toolchain = request.config.getoption("--toolchain") assert implies( buildFlowName == NnxBuildFlowName.cmake, nnxName == NnxName.neureka_v2 ), "The cmake build flow has been tested only with the neureka_v2 accelerator" + assert implies( + buildFlowName == NnxBuildFlowName.make, appName == AppName.pulp_nnx + ), "The make build flow is only tested by the app_pulp_nnx" + + assert implies( + buildFlowName == NnxBuildFlowName.make, toolchain == Toolchain.gnu + ), "The make build flow has only been tested with the gnu toolchain" + if buildFlowName == NnxBuildFlowName.cmake: - CmakeBuildFlow(nnxName).prepare() + CmakeBuildFlow(nnxName, appName, toolchain).prepare() return buildFlowName @@ -109,6 +133,16 @@ def wmem(request) -> NnxWmem: return _wmem +@pytest.fixture +def appName(request) -> AppName: + return request.config.getoption("--app") + + +@pytest.fixture +def toolchain(request) -> Toolchain: + return request.config.getoption("--toolchain") + + def _find_test_dirs(path: Union[str, os.PathLike]): return [dirpath for dirpath, _, _ in os.walk(path) if NnxTest.is_test_dir(dirpath)] diff --git a/test/test.py b/test/test.py index 86aa1ed..401c993 100644 --- a/test/test.py +++ b/test/test.py @@ -18,7 +18,7 @@ import re -from NnxBuildFlow import NnxBuildFlowClsMapping, NnxBuildFlowName +from NnxBuildFlow import AppName, NnxBuildFlowClsMapping, NnxBuildFlowName, Toolchain from NnxMapping import NnxMapping, NnxName from NnxTestClasses import NnxTest, NnxTestHeaderGenerator, NnxWmem @@ -38,15 +38,19 @@ def test( buildFlowName: NnxBuildFlowName, wmem: NnxWmem, nnxTestName: str, + appName: AppName, + toolchain: Toolchain, ): testConfCls, weightCls = NnxMapping[nnxName] # conftest.py makes sure the test is valid and generated nnxTest = NnxTest.load(testConfCls, nnxTestName) - NnxTestHeaderGenerator(weightCls(wmem)).generate(nnxTestName, nnxTest) + NnxTestHeaderGenerator(weightCls(wmem), f"{appName.path()}/gen").generate( + nnxTestName, nnxTest + ) - buildFlow = NnxBuildFlowClsMapping[buildFlowName](nnxName) + buildFlow = NnxBuildFlowClsMapping[buildFlowName](nnxName, appName, toolchain) buildFlow.build() stdout = buildFlow.run() diff --git a/test/testgen.py b/test/testgen.py index 37c1ba9..ce495a1 100644 --- a/test/testgen.py +++ b/test/testgen.py @@ -24,6 +24,7 @@ import toml +from NnxBuildFlow import AppName from NnxMapping import NnxMapping, NnxName from NnxTestClasses import ( NnxTest, @@ -46,7 +47,7 @@ def headers_gen( assert test is not None if not test.is_valid(): test = NnxTestGenerator.from_conf(test.conf) - NnxTestHeaderGenerator(nnxWeight).generate(args.test_dir, test) + NnxTestHeaderGenerator(nnxWeight, args.app).generate(args.test_dir, test) def print_tensors(test: NnxTest): @@ -165,6 +166,13 @@ def add_common_arguments(parser: argparse.ArgumentParser): default=NnxWmem.tcdm, help="Choose the weight memory destination. Default: tcdm", ) + parser.add_argument( + "--app", + type=AppName, + choices=list(AppName), + default=AppName.pulp_nnx, + help="Choose an app to test. Default: pulp-nnx", + ) parser = argparse.ArgumentParser( diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt new file mode 100644 index 0000000..27e8fe7 --- /dev/null +++ b/util/CMakeLists.txt @@ -0,0 +1,7 @@ +add_library(pulp-nnx-util + OBJECT + hwpe.c + pulp_nnx_util.c +) + +target_include_directories(pulp-nnx-util PUBLIC .)