Просмотр исходного кода

CMSIS-NN: Make unit test more independent

Copying linker files and uart code from Arm
Ethos-U Core Platform project.
Updating CMake and README.
Måns Nilsson 5 лет назад
Родитель
Сommit
c3fa9d64da

+ 60 - 31
CMSIS/NN/Tests/UnitTest/CMakeLists.txt

@@ -22,14 +22,18 @@ project(cmsis_nn_unit_tests VERSION 0.0.1)
 
 set(CMSIS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../.." CACHE PATH "Path to CMSIS.")
 
-# External dependencies.
-set(USE_ETHOSU_CORE_PLATFORM_DEFAULT OFF)
-set(ETHOSU_CORE_PLATFORM_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../core_platform" CACHE PATH "Path to Arm Ethos-U Core Platform project.")
-set(FVP_CORSTONE_300_PATH "${ETHOSU_CORE_PLATFORM_PATH}/targets/corstone-300")
+set(BUILD_CMSIS_NN_UNIT_DEFAULT OFF)
+option(BUILD_CMSIS_NN_UNIT "If building the unit tests from another project." ${BUILD_CMSIS_NN_UNIT_DEFAULT})
 
-option(USE_ETHOSU_CORE_PLATFORM "Use Arm Ethos-U Core Platform project." ${USE_ETHOSU_CORE_PLATFORM_DEFAULT})
+if(NOT BUILD_CMSIS_NN_UNIT)
+    set(BUILD_CMSIS_NN_UNIT_TESTS_FOR_FVP_BASED_CORSTONE_300 ON)
+else()
+    set(BUILD_CMSIS_NN_UNIT_TESTS_FOR_FVP_BASED_CORSTONE_300 OFF)
+endif()
 
-if(USE_ETHOSU_CORE_PLATFORM)
+if(BUILD_CMSIS_NN_UNIT_TESTS_FOR_FVP_BASED_CORSTONE_300)
+    set(FVP_CORSTONE_300_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Corstone-300" CACHE PATH
+        "Dependencies for using FVP based on Arm Corstone-300 software.")
     set(CMAKE_EXECUTABLE_SUFFIX ".elf")
 endif()
 
@@ -85,33 +89,58 @@ execute_process(COMMAND ${MAKE_CMD} ${MAKE_CMD_SCRIPT} ${MAKE_CMD_SCRIPT_OPTION}
                         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 add_subdirectory(Unity)
 
-if(USE_ETHOSU_CORE_PLATFORM)
-add_subdirectory(${FVP_CORSTONE_300_PATH} fvp_corstone_300)
-
-add_library(retarget STATIC
-                     ${FVP_CORSTONE_300_PATH}/retarget.c
-                     ${FVP_CORSTONE_300_PATH}/uart.c)
-
-# Link in dependencies to every unit test.
-get_property(executables GLOBAL PROPERTY cmsis_nn_unit_test_executables)
-string(REPLACE " " ";" cmsis_nn_unit_test_list_of_executables ${executables})
-foreach(target ${cmsis_nn_unit_test_list_of_executables})
-    target_link_libraries(${target} PRIVATE $<TARGET_OBJECTS:retarget> retarget)
-    target_link_libraries(${target} PRIVATE $<TARGET_OBJECTS:cmsis_startup> cmsis_device)
-    add_dependencies(${target} retarget cmsis_startup)
-
-    target_compile_definitions(${target} PUBLIC USING_FVP_CORSTONE_300)
-    target_link_options(${target} PRIVATE --entry Reset_Handler)
-
-    # Copy linker files.
+if(BUILD_CMSIS_NN_UNIT_TESTS_FOR_FVP_BASED_CORSTONE_300)
+    add_library(retarget STATIC
+        ${FVP_CORSTONE_300_PATH}/retarget.c
+        ${FVP_CORSTONE_300_PATH}/uart.c)
+
+    # Build CMSIS startup dependencies based on TARGET_CPU.
+    string(REGEX REPLACE "^cortex-m([0-9]+)$" "ARMCM\\1" ARM_CPU ${CMAKE_SYSTEM_PROCESSOR})
+    if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "cortex-m33")
+        set(ARM_FEATURES "_DSP_FP")
+    elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "cortex-m4")
+        set(ARM_FEATURES "_FP")
+    elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "cortex-m7")
+        set(ARM_FEATURES "_DP")
+    else()
+        set(ARM_FEATURES "")
+    endif()
+    add_library(cmsis_startup STATIC)
+    target_sources(cmsis_startup PRIVATE
+        ${CMSIS_PATH}/Device/ARM/${ARM_CPU}/Source/startup_${ARM_CPU}.c
+        ${CMSIS_PATH}/Device/ARM/${ARM_CPU}/Source/system_${ARM_CPU}.c)
+    target_include_directories(cmsis_startup PUBLIC
+        ${CMSIS_PATH}/Device/ARM/${ARM_CPU}/Include
+        ${CMSIS_PATH}/CMSIS/Core/Include)
+    target_compile_options(cmsis_startup INTERFACE -include${ARM_CPU}${ARM_FEATURES}.h)
+    target_compile_definitions(cmsis_startup PRIVATE ${ARM_CPU}${ARM_FEATURES})
+
+    # Linker file settings.
+    set(LINK_FILE "${FVP_CORSTONE_300_PATH}/linker" CACHE PATH "Linker file.")
     if (CMAKE_CXX_COMPILER_ID STREQUAL "ARMClang")
-        configure_file(${FVP_CORSTONE_300_PATH}/platform.scatter
-        ${CMAKE_CURRENT_SOURCE_DIR}/platform_${target}.scatter COPYONLY)
+        set(LINK_FILE "${FVP_CORSTONE_300_PATH}/linker.scatter")
+        set(LINK_FILE_OPTION "--scatter")
+        set(LINK_ENTRY_OPTION "--entry")
+        set(LINK_ENTRY "Reset_Handler")
     elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
-        configure_file(${FVP_CORSTONE_300_PATH}/platform.ld
-        ${CMAKE_CURRENT_SOURCE_DIR}/platform_${target}.ld COPYONLY)
+        set(LINK_FILE "${FVP_CORSTONE_300_PATH}/linker.ld")
+        set(LINK_FILE_OPTION "-T")
+        set(LINK_ENTRY_OPTION "")
+        set(LINK_ENTRY "")
     endif()
+ 
+    # Link in FVP dependencies to every unit test.
+    get_property(executables GLOBAL PROPERTY cmsis_nn_unit_test_executables)
+    string(REPLACE " " ";" cmsis_nn_unit_test_list_of_executables ${executables})
+    foreach(target ${cmsis_nn_unit_test_list_of_executables})
+        target_link_libraries(${target} PRIVATE retarget)
+        target_link_libraries(${target} PRIVATE $<TARGET_OBJECTS:cmsis_startup> cmsis_startup)
+
+        add_dependencies(${target} retarget cmsis_startup)
 
-    ethosu_link_options(${target} PRIVATE LINK_FILE platform_${target})
-endforeach()
+        target_compile_definitions(${target} PUBLIC USING_FVP_CORSTONE_300)
+
+        target_link_options(${target} PRIVATE ${LINK_FILE_OPTION} ${LINK_FILE} ${LINK_ENTRY_OPTION} ${LINK_ENTRY})
+        set_target_properties(${target} PROPERTIES LINK_DEPENDS ${LINK_FILE})
+    endforeach()
 endif()

+ 312 - 0
CMSIS/NN/Tests/UnitTest/Corstone-300/linker.ld

@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2009-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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
+ *
+ * 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.
+ */
+
+/*
+ *-------- <<< Use Configuration Wizard in Context Menu >>> -------------------
+ */
+
+/*---------------------- ITCM Configuration ----------------------------------
+  <h> Flash Configuration
+    <o0> Flash Base Address <0x0-0xFFFFFFFF:8>
+    <o1> Flash Size (in Bytes) <0x0-0xFFFFFFFF:8>
+  </h>
+  -----------------------------------------------------------------------------*/
+__ROM_BASE = 0x00000000;
+__ROM_SIZE = 0x00080000;
+
+/*--------------------- DTCM RAM Configuration ----------------------------
+  <h> RAM Configuration
+    <o0> RAM Base Address    <0x0-0xFFFFFFFF:8>
+    <o1> RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
+  </h>
+ -----------------------------------------------------------------------------*/
+__RAM_BASE = 0x20000000;
+__RAM_SIZE = 0x00080000;
+
+/*--------------------- Embedded SRAM Configuration ----------------------------
+  <h> SRAM Configuration
+    <o0> SRAM Base Address    <0x0-0xFFFFFFFF:8>
+    <o1> SRAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
+  </h>
+ -----------------------------------------------------------------------------*/
+__SRAM_BASE = 0x21000000;
+__SRAM_SIZE = 0x00200000;
+
+/*--------------------- Stack / Heap Configuration ----------------------------
+  <h> Stack / Heap Configuration
+    <o0> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
+    <o1> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
+  </h>
+  -----------------------------------------------------------------------------*/
+__STACK_SIZE = 0x00008000;
+__HEAP_SIZE  = 0x00008000;
+
+/*--------------------- Embedded RAM Configuration ----------------------------
+  <h> DDR Configuration
+    <o0> DDR Base Address    <0x0-0xFFFFFFFF:8>
+    <o1> DDR Size (in Bytes) <0x0-0xFFFFFFFF:8>
+  </h>
+ -----------------------------------------------------------------------------*/
+__DDR_BASE = 0x60000000;
+__DDR_SIZE = 0x02000000;
+
+/*
+ *-------------------- <<< end of configuration section >>> -------------------
+ */
+
+MEMORY
+{
+  ITCM  (rx)  : ORIGIN = __ROM_BASE, LENGTH = __ROM_SIZE
+  DTCM  (rwx) : ORIGIN = __RAM_BASE, LENGTH = __RAM_SIZE
+  SRAM  (rwx) : ORIGIN = __SRAM_BASE, LENGTH = __SRAM_SIZE
+  DDR   (rwx) : ORIGIN = __DDR_BASE, LENGTH = __DDR_SIZE
+}
+
+/* Linker script to place sections and symbol values. Should be used together
+ * with other linker script that defines memory regions ITCM and RAM.
+ * It references following symbols, which must be defined in code:
+ *   Reset_Handler : Entry of reset handler
+ *
+ * It defines following symbols, which code can use without definition:
+ *   __exidx_start
+ *   __exidx_end
+ *   __copy_table_start__
+ *   __copy_table_end__
+ *   __zero_table_start__
+ *   __zero_table_end__
+ *   __etext
+ *   __data_start__
+ *   __preinit_array_start
+ *   __preinit_array_end
+ *   __init_array_start
+ *   __init_array_end
+ *   __fini_array_start
+ *   __fini_array_end
+ *   __data_end__
+ *   __bss_start__
+ *   __bss_end__
+ *   __end__
+ *   end
+ *   __HeapLimit
+ *   __StackLimit
+ *   __StackTop
+ *   __stack
+ */
+ENTRY(Reset_Handler)
+
+SECTIONS
+{
+  .text :
+  {
+    KEEP(*(.vectors))
+    *(.text*)
+
+    KEEP(*(.init))
+    KEEP(*(.fini))
+
+    /* .ctors */
+    *crtbegin.o(.ctors)
+    *crtbegin?.o(.ctors)
+    *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+    *(SORT(.ctors.*))
+    *(.ctors)
+
+    /* .dtors */
+    *crtbegin.o(.dtors)
+    *crtbegin?.o(.dtors)
+    *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+    *(SORT(.dtors.*))
+    *(.dtors)
+
+    *(.rodata*)
+
+    KEEP(*(.eh_frame*))
+  } > ITCM
+
+  /*
+   * SG veneers:
+   * All SG veneers are placed in the special output section .gnu.sgstubs. Its start address
+   * must be set, either with the command line option �--section-start� or in a linker script,
+   * to indicate where to place these veneers in memory.
+   */
+/*
+  .gnu.sgstubs :
+  {
+    . = ALIGN(32);
+  } > ITCM
+*/
+  .ARM.extab :
+  {
+    *(.ARM.extab* .gnu.linkonce.armextab.*)
+  } > ITCM
+
+  __exidx_start = .;
+  .ARM.exidx :
+  {
+    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+  } > ITCM
+  __exidx_end = .;
+
+  .copy.table :
+  {
+    . = ALIGN(4);
+    __copy_table_start__ = .;
+    LONG (__etext)
+    LONG (__data_start__)
+    LONG (__data_end__ - __data_start__)
+    /* Add each additional data section here */
+    __copy_table_end__ = .;
+  } > ITCM
+
+  .zero.table :
+  {
+    . = ALIGN(4);
+    __zero_table_start__ = .;
+    /* Add each additional bss section here */
+/*
+    LONG (__bss2_start__)
+    LONG (__bss2_end__ - __bss2_start__)
+*/
+    __zero_table_end__ = .;
+  } > ITCM
+
+  /**
+   * Location counter can end up 2byte aligned with narrow Thumb code but
+   * __etext is assumed by startup code to be the LMA of a section in DTCM
+   * which must be 4byte aligned
+   */
+  __etext = ALIGN (4);
+
+  .data : AT (__etext)
+  {
+    __data_start__ = .;
+    *(vtable)
+    *(.data)
+    *(.data.*)
+
+    . = ALIGN(4);
+    /* preinit data */
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP(*(.preinit_array))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
+
+    . = ALIGN(4);
+    /* init data */
+    PROVIDE_HIDDEN (__init_array_start = .);
+    KEEP(*(SORT(.init_array.*)))
+    KEEP(*(.init_array))
+    PROVIDE_HIDDEN (__init_array_end = .);
+
+
+    . = ALIGN(4);
+    /* finit data */
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP(*(SORT(.fini_array.*)))
+    KEEP(*(.fini_array))
+    PROVIDE_HIDDEN (__fini_array_end = .);
+
+    KEEP(*(.jcr*))
+    . = ALIGN(4);
+    /* All data end */
+    __data_end__ = .;
+
+  } > DTCM
+
+  /*
+   * Secondary data section, optional
+   *
+   * Remember to add each additional data section
+   * to the .copy.table above to asure proper
+   * initialization during startup.
+   */
+/*
+  __etext2 = ALIGN (4);
+
+  .data2 : AT (__etext2)
+  {
+    . = ALIGN(4);
+    __data2_start__ = .;
+    *(.data2)
+    *(.data2.*)
+    . = ALIGN(4);
+    __data2_end__ = .;
+
+  } > RAM2
+*/
+
+  .sram :
+  {
+    . = ALIGN(16);
+    *(.bss.NoInit)
+    . = ALIGN(16);
+  } > SRAM AT > SRAM
+
+  .bss :
+  {
+    . = ALIGN(4);
+    __bss_start__ = .;
+    *(.bss)
+    *(.bss.*)
+    *(COMMON)
+    . = ALIGN(4);
+    __bss_end__ = .;
+  } > DTCM AT > DTCM
+
+
+  /*
+   * Secondary bss section, optional
+   *
+   * Remember to add each additional bss section
+   * to the .zero.table above to asure proper
+   * initialization during startup.
+   */
+/*
+  .bss2 :
+  {
+    . = ALIGN(4);
+    __bss2_start__ = .;
+    *(.bss2)
+    *(.bss2.*)
+    . = ALIGN(4);
+    __bss2_end__ = .;
+  } > RAM2 AT > RAM2
+*/
+
+  .heap (COPY) :
+  {
+    . = ALIGN(8);
+    __end__ = .;
+    PROVIDE(end = .);
+    . = . + __HEAP_SIZE;
+    . = ALIGN(8);
+    __HeapLimit = .;
+  } > DTCM
+
+  .stack (ORIGIN(DTCM) + LENGTH(DTCM) - __STACK_SIZE) (COPY) :
+  {
+    . = ALIGN(8);
+    __StackLimit = .;
+    . = . + __STACK_SIZE;
+    . = ALIGN(8);
+    __StackTop = .;
+  } > DTCM
+  PROVIDE(__stack = __StackTop);
+
+  /* Check if data + heap + stack exceeds DTCM limit */
+  ASSERT(__StackLimit >= __HeapLimit, "region DTCM overflowed with stack")
+}

+ 90 - 0
CMSIS/NN/Tests/UnitTest/Corstone-300/linker.scatter

@@ -0,0 +1,90 @@
+#! cpp
+
+/*
+ * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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
+ *
+ * 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.
+ */
+
+#ifndef STACK_SIZE
+#define STACK_SIZE 0x8000
+#endif
+
+#ifndef HEAP_SIZE
+#define HEAP_SIZE 0x8000
+#endif
+
+#define LR_START   0x10000000
+#define LR_SIZE    0x01000000
+
+#define ITCM_START 0x10000000
+#define ITCM_SIZE  0x00080000
+
+#define BRAM_START 0x11000000
+#define BRAM_SIZE  0x00200000
+
+#define DTCM_START 0x30000000
+#define DTCM_SIZE  0x00080000
+
+#define SRAM_START 0x31000000
+#define SRAM_SIZE  0x00200000
+
+#define DDR_START  0x70000000
+#define DDR_SIZE   0x02000000
+
+#define STACK_HEAP 0x30080000
+
+APP_IMAGE LR_START LR_SIZE
+{
+    ; ITCM 512kB
+    rom_exec ITCM_START ITCM_SIZE
+    {
+        *.o (RESET, +First)
+        *(InRoot$$Sections)
+        ; Make sure reset_handler ends up in root segment, when split across
+        ; ITCM and DTCM
+        startup_ARMCM55.o
+        .ANY (+RO)
+    }
+
+    ; MPS3 BRAM
+    BRAM BRAM_START UNINIT BRAM_SIZE
+    {
+    }
+
+    ; DTCM 512kB
+    ; Only accessible from the Cortex-M
+    DTCM DTCM_START (DTCM_SIZE - STACK_SIZE - HEAP_SIZE)
+    {
+        .ANY1 (+RW +ZI)
+    }
+
+    ; SSE-300 SRAM (3 cycles read latency) from M55/U55
+    ; 2x2MB - only first part mapped
+    SRAM SRAM_START UNINIT SRAM_SIZE
+    {
+    }
+
+    ARM_LIB_HEAP  (STACK_HEAP - STACK_SIZE - HEAP_SIZE) EMPTY ALIGN 8 HEAP_SIZE {}
+    ARM_LIB_STACK (STACK_HEAP - STACK_SIZE) EMPTY ALIGN 8 STACK_SIZE {}
+}
+
+LOAD_REGION_1 DDR_START DDR_SIZE
+{
+    ; 2GB DDR4 available
+    rom_dram DDR_START
+    {
+    }
+}

+ 275 - 0
CMSIS/NN/Tests/UnitTest/Corstone-300/retarget.c

@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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
+ *
+ * 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.
+ */
+
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100) && !defined(GCCCOMPILER)
+#include <rt_misc.h>
+#include <rt_sys.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#else
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#endif
+
+#include "uart.h"
+
+unsigned char UartPutc(unsigned char ch) { return uart_putc(ch); }
+
+unsigned char UartGetc(void) { return uart_putc(uart_getc()); }
+
+__attribute__((noreturn)) void UartEndSimulation(int code)
+{
+    UartPutc((char)0x4);  // End of simulation
+    UartPutc((char)code); // Exit code
+    while (1)
+    {
+    }
+}
+
+void exit(int code)
+{
+    UartEndSimulation(code);
+    while (1)
+    {
+    }
+}
+
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100) && !defined(GCCCOMPILER)
+int fputc(int ch, FILE *f)
+{
+    (void)(f);
+    return UartPutc(ch);
+}
+
+int fgetc(FILE *f)
+{
+    (void)f;
+    return UartPutc(UartGetc());
+}
+#else
+int SER_PutChar(int c) { return UartPutc(c); }
+
+int SER_GetChar(void) { return UartPutc(UartGetc()); }
+#endif
+
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100) && !defined(GCCCOMPILER)
+/**
+   Copied from CMSIS/DSP/Platforms/FVP/ARMv81MML/system_ARMv81MML.c
+*/
+
+#define FH_STDIN 0x8001
+#define FH_STDOUT 0x8002
+#define FH_STDERR 0x8003
+
+const char __stdin_name[] = ":STDIN";
+const char __stdout_name[] = ":STDOUT";
+const char __stderr_name[] = ":STDERR";
+
+/**
+  The following _sys_xxx functions are defined in rt_sys.h.
+*/
+
+__attribute__((weak)) FILEHANDLE _sys_open(const char *name, int openmode)
+{
+    (void)openmode;
+
+    if (name == NULL)
+    {
+        return (-1);
+    }
+
+    if (name[0] == ':')
+    {
+        if (strcmp(name, ":STDIN") == 0)
+        {
+            return (FH_STDIN);
+        }
+        if (strcmp(name, ":STDOUT") == 0)
+        {
+            return (FH_STDOUT);
+        }
+        if (strcmp(name, ":STDERR") == 0)
+        {
+            return (FH_STDERR);
+        }
+        return (-1);
+    }
+
+    return (-1);
+}
+
+__attribute__((weak)) int _sys_close(FILEHANDLE fh)
+{
+
+    switch (fh)
+    {
+    case FH_STDIN:
+        return (0);
+    case FH_STDOUT:
+        return (0);
+    case FH_STDERR:
+        return (0);
+    }
+
+    return (-1);
+}
+
+__attribute__((weak)) int _sys_write(FILEHANDLE fh, const uint8_t *buf, uint32_t len, int mode)
+{
+    (void)buf;
+    (void)len;
+    (void)mode;
+
+    switch (fh)
+    {
+    case FH_STDIN:
+        return (-1);
+    case FH_STDOUT:
+        return (0);
+    case FH_STDERR:
+        return (0);
+    }
+
+    return (-1);
+}
+
+__attribute__((weak)) int _sys_read(FILEHANDLE fh, uint8_t *buf, uint32_t len, int mode)
+{
+    (void)buf;
+    (void)len;
+    (void)mode;
+
+    switch (fh)
+    {
+    case FH_STDIN:
+        return ((int)(len | 0x80000000U));
+    case FH_STDOUT:
+        return (-1);
+    case FH_STDERR:
+        return (-1);
+    }
+
+    return (-1);
+}
+
+__attribute__((weak)) int _sys_istty(FILEHANDLE fh)
+{
+
+    switch (fh)
+    {
+    case FH_STDIN:
+        return (1);
+    case FH_STDOUT:
+        return (1);
+    case FH_STDERR:
+        return (1);
+    }
+
+    return (0);
+}
+
+__attribute__((weak)) int _sys_seek(FILEHANDLE fh, long pos)
+{
+    (void)pos;
+
+    switch (fh)
+    {
+    case FH_STDIN:
+        return (-1);
+    case FH_STDOUT:
+        return (-1);
+    case FH_STDERR:
+        return (-1);
+    }
+
+    return (-1);
+}
+
+__attribute__((weak)) long _sys_flen(FILEHANDLE fh)
+{
+
+    switch (fh)
+    {
+    case FH_STDIN:
+        return (0);
+    case FH_STDOUT:
+        return (0);
+    case FH_STDERR:
+        return (0);
+    }
+
+    return (0);
+}
+
+__attribute__((weak)) char *(_sys_command_string)(char *cmd, int len)
+{
+    (void)len;
+
+    return cmd;
+}
+
+__attribute__((weak)) void(_sys_exit)(int return_code) { exit(return_code); }
+
+#else
+/**
+   Copied from CMSIS/DSP/DSP_Lib_TestSuite/Common/platform/GCC/Retarget.c
+*/
+
+int _open(const char *path, int flags, ...) { return (-1); }
+
+int _close(int fd) { return (-1); }
+
+int _lseek(int fd, int ptr, int dir) { return (0); }
+
+int __attribute__((weak)) _fstat(int fd, struct stat *st)
+{
+    memset(st, 0, sizeof(*st));
+    st->st_mode = S_IFCHR;
+    return (0);
+}
+
+int _isatty(int fd) { return (1); }
+
+int _read(int fd, char *ptr, int len)
+{
+    char c;
+    int i;
+
+    for (i = 0; i < len; i++)
+    {
+        c = SER_GetChar();
+        if (c == 0x0D)
+            break;
+        *ptr++ = c;
+        SER_PutChar(c);
+    }
+    return (len - i);
+}
+
+int _write(int fd, char *ptr, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        SER_PutChar(*ptr++);
+    return (i);
+}
+#endif

+ 101 - 0
CMSIS/NN/Tests/UnitTest/Corstone-300/uart.c

@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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
+ *
+ * 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.
+ */
+
+#include "uart.h"
+#include <stdint.h>
+#include <stdio.h>
+
+#define UART0_BASE 0x49303000
+#define UART0_BAUDRATE 115200
+#define SYSTEM_CORE_CLOCK 25000000
+
+/*------------- Universal Asynchronous Receiver Transmitter (UART) -----------*/
+
+#define __IO volatile
+#define __I volatile const
+#define __O volatile
+
+typedef struct
+{
+    __IO uint32_t DATA;  /* Offset: 0x000 (R/W) Data Register    */
+    __IO uint32_t STATE; /* Offset: 0x004 (R/W) Status Register  */
+    __IO uint32_t CTRL;  /* Offset: 0x008 (R/W) Control Register */
+    union
+    {
+        __I uint32_t INTSTATUS; /* Offset: 0x00C (R/ ) Interrupt Status Register */
+        __O uint32_t INTCLEAR;  /* Offset: 0x00C ( /W) Interrupt Clear Register  */
+    };
+    __IO uint32_t BAUDDIV; /* Offset: 0x010 (R/W) Baudrate Divider Register */
+} CMSDK_UART_TypeDef;
+
+#define CMSDK_UART0_BASE UART0_BASE
+#define CMSDK_UART0 ((CMSDK_UART_TypeDef *)CMSDK_UART0_BASE)
+#define CMSDK_UART0_BAUDRATE UART0_BAUDRATE
+
+void uart_init(void)
+{
+    // SystemCoreClock / 9600
+    CMSDK_UART0->BAUDDIV = SYSTEM_CORE_CLOCK / CMSDK_UART0_BAUDRATE;
+
+    CMSDK_UART0->CTRL = ((1ul << 0) | /* TX enable */
+                         (1ul << 1)); /* RX enable */
+}
+
+// Output a character
+unsigned char uart_putc(unsigned char my_ch)
+{
+    while ((CMSDK_UART0->STATE & 1))
+        ; // Wait if Transmit Holding register is full
+
+    if (my_ch == '\n')
+    {
+        CMSDK_UART0->DATA = '\r';
+        while ((CMSDK_UART0->STATE & 1))
+            ; // Wait if Transmit Holding register is full
+    }
+
+    CMSDK_UART0->DATA = my_ch; // write to transmit holding register
+
+    return (my_ch);
+}
+
+// Get a character
+unsigned char uart_getc(void)
+{
+    unsigned char my_ch;
+    // unsigned int  cnt;
+
+    while ((CMSDK_UART0->STATE & 2) == 0) // Wait if Receive Holding register is empty
+    {
+#if 0
+        cnt = MPS3_FPGAIO->CLK100HZ / 50;
+        if (cnt & 0x8)
+            MPS3_FPGAIO->LED = 0x01 << (cnt & 0x7);
+        else
+            MPS3_FPGAIO->LED = 0x80 >> (cnt & 0x7);
+#endif
+    }
+
+    my_ch = CMSDK_UART0->DATA;
+
+    // Convert CR to LF
+    if (my_ch == '\r')
+        my_ch = '\n';
+
+    return (my_ch);
+}

+ 34 - 0
CMSIS/NN/Tests/UnitTest/Corstone-300/uart.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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
+ *
+ * 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.
+ */
+
+#ifndef _UART_STDOUT_H_
+#define _UART_STDOUT_H_
+
+#if __cplusplus
+extern "C" {
+#endif
+
+void uart_init(void);
+unsigned char uart_putc(unsigned char my_ch);
+unsigned char uart_getc(void);
+
+#if __cplusplus
+}
+#endif
+
+#endif

+ 26 - 23
CMSIS/NN/Tests/UnitTest/README.md

@@ -1,8 +1,8 @@
 # Unit tests for CMSIS-NN
-Unit test CMSIS-NN functions on any Arm Mbed OS supported HW.
 
-Arm Mbed OS is used for building and flashing.
-The Unity test framework is used for running the actual unit tests.
+Unit test CMSIS-NN functions on any [Arm Mbed OS](https://os.mbed.com/mbed-os/) supported HW or using a fixed virtual platform (FVP) based on [Arm Corstone-300 software](https://developer.arm.com/ip-products/subsystem/corstone/corstone-300).
+
+The [Unity test framework](http://www.throwtheswitch.org/unity) is used for running the actual unit tests.
 
 ## Requirements
 
@@ -12,8 +12,7 @@ It has been tested with Python 3.6 and it has been tested on Ubuntu 16 and 18.
 There is a requirement file that can be used to install the dependencies.
 
 ```
-    ``` pip3 install -r requirements.txt```
-
+pip3 install -r requirements.txt
 ```
 
 Note that the exact versions are not required, and there are not a lot of packages to install manually.
@@ -25,8 +24,7 @@ To manually install packages, see below.
 For executing unit tests, the python3 package pyserial is required. Version 3.4 of pyserial has been tested ok.
 
 ```
-    ``` pip3 install pyserial```
-
+pip3 install pyserial
 ```
 
 Other required python packages are mbed-cli and and mbed-ls. It should not matter if those are installed under python2 or python3 as they are command-line tools. These packages have been tested for Python2, with the following versions: mbed-ls(1.7.9) and mbed-cli(1.10.1).
@@ -36,38 +34,41 @@ Other required python packages are mbed-cli and and mbed-ls. It should not matte
 For generating new data, the python3 packages tensorflow, numpy and packaging are required. Tensorflow version 2 is required as a minimum.
 
 ## Getting started
+
+### Using Arm Mbed OS supported hardware
+
 Connect any HW (e.g. NUCLEO_F746ZG) that is supported by Arm Mbed OS. Multiple boards are supported. If all requirements are satisfied you can just run:
 
 ```
-    ```./unittest_targets.py```
-
+./unittest_targets.py
 ```
 
 Use the -h flag to get more info.
 
-It is also possible to build the unit test with Cmake. The binaries can then be used with another test platform, e.g. Fastmodel.
-If using Cmake it is recommended to use Arm Ethos-U Core Platform (https://review.mlplatform.org/admin/repos/ml/ethos-u/ethos-u-core-platform) and Arm Ethos-U Core Software (https://review.mlplatform.org/admin/repos/ml/ethos-u/ethos-u-core-software) projects and a fixed virtual platform (FVP) based on Arm Corstone-300 software (https://developer.arm.com/ip-products/subsystem/corstone/corstone-300).
-First clone the Arm Ethos-U Core Software and Arm Ethos-U Core Platform projects. Arm Ethos-U Core Software is expecting to have Tensorflow cloned but in this case it is enough to create a directory ```tensorflow``` into Arm Ethos-U Core Software. Then build:
+### Using FVP based on Arm Corstone-300 software
+
+It is recommended to use toolchain files from [Arm Ethos-U Core Platform](https://review.mlplatform.org/admin/repos/ml/ethos-u/ethos-u-core-platform) project. These are supporting TARGET_CPU, which is a required argument. Note that if not specifying TARGET_CPU, these toolchains will set some default. The format must be TARGET_CPU=cortex-mXX, see examples below.
+Clone Arm Ethos-U Core Platform project and build:
 
 ```
-    ```mkdir build```
-    ```cd build```
-    ```cmake .. -DCMAKE_TOOLCHAIN_FILE=</path/to/Ethos-u-core-platform>/cmake/toolchain/arm-none-eabi-gcc.cmake -DETHOSU_CORE_PLATFORM_PATH=</path/to/Ethos-u-core-platform> -DUSE_ETHOSU_CORE_PLATFORM=ON -DTARGET_CPU=cortex-m55 -DETHOS_U_CORE_SOFTWARE_PATH=</path/to/Ethos-u-core-software> -DCORE_SOFTWARE_ACCELERATOR=CMSIS-NN -DCORE_SOFTWARE_RTOS=None```
-    ```make cmsis_nn_unit_tests```
+mkdir build
+cd build
+cmake .. -DCMAKE_TOOLCHAIN_FILE=</path/to/Ethos-u-core-platform>/cmake/toolchain/arm-none-eabi-gcc.cmake -DTARGET_CPU=cortex-m55
+make
 ```
 
 This will build all unit tests. You can also just build a specific unit test only, for example:
 
 ```
-    ```make test_arm_depthwise_conv_s8_opt```
+make test_arm_depthwise_conv_s8_opt
 ```
 
-Some more examples, assuming Ethos-u-core-platform and Ethos-u-core_software are cloned into your home directory:
+Some more examples, assuming Ethos-u-core-platform is cloned into your home directory:
 
 ```
-    ```cmake .. -DCMAKE_TOOLCHAIN_FILE=~/ethos-u-core-platform/cmake/toolchain/arm-none-eabi-gcc.cmake -DETHOSU_CORE_PLATFORM_PATH=~/ethos-u-core-platform -DUSE_ETHOSU_CORE_PLATFORM=ON -DTARGET_CPU=cortex-m55 -DETHOS_U_CORE_SOFTWARE_PATH=~/ethos-u-core-software -DCORE_SOFTWARE_ACCELERATOR=CMSIS-NN -DCORE_SOFTWARE_RTOS=None```
-    ```cmake .. -DCMAKE_TOOLCHAIN_FILE=~/ethos-u-core-platform/cmake/toolchain/arm-none-eabi-gcc.cmake -DETHOSU_CORE_PLATFORM_PATH=~/ethos-u-core-platform -DUSE_ETHOSU_CORE_PLATFORM=ON -DTARGET_CPU=cortex-m7 -DETHOS_U_CORE_SOFTWARE_PATH=~/ethos-u-core-software -DCORE_SOFTWARE_ACCELERATOR=CMSIS-NN -DCORE_SOFTWARE_RTOS=None```
-    ```cmake .. -DCMAKE_TOOLCHAIN_FILE=~/ethos-u-core-platform/cmake/toolchain/armclang.cmake -DETHOSU_CORE_PLATFORM_PATH=~/ethos-u-core-platform -DUSE_ETHOSU_CORE_PLATFORM=ON -DTARGET_CPU=cortex-m3 -DETHOS_U_CORE_SOFTWARE_PATH=~/ethos-u-core-software -DCORE_SOFTWARE_ACCELERATOR=CMSIS-NN -DCORE_SOFTWARE_RTOS=None```
+cmake .. -DCMAKE_TOOLCHAIN_FILE=~/ethos-u-core-platform/cmake/toolchain/arm-none-eabi-gcc.cmake -DTARGET_CPU=cortex-m55
+cmake .. -DCMAKE_TOOLCHAIN_FILE=~/ethos-u-core-platform/cmake/toolchain/arm-none-eabi-gcc.cmake -DTARGET_CPU=cortex-m7
+cmake .. -DCMAKE_TOOLCHAIN_FILE=~/ethos-u-core-platform/cmake/toolchain/armclang.cmake -DTARGET_CPU=cortex-m3
 ```
 
 Then you need to download and install the FVP based Arm Corstone-300 software, for example:
@@ -87,10 +88,11 @@ FVP_Corstone_SSE-300_Ethos-U55 --cpulimit 2 -C mps3_board.visualisation.disable-
 ```
 
 ## Generating new test data
+
 Generating new test data is done with the following script. Use the -h flag to get more info.
 
 ```
-    ```./generate_test_data.py -h```
+./generate_test_data.py -h
 
 ```
 
@@ -102,8 +104,9 @@ Once you are happy with the new test data set, it should be added in the load_al
 
 ## Overview of the Folders
 
-- `Output` - This will be created when building.
+- `Corstone-300` - These are dependencies, like linker files etc, needed when building binaries targetting the FVP based on Arm Corstone-300 software. This is mostly taken from Arm Ethos-U Core Platform project.
 - `Mbed` - These are the Arm Mbed OS settings that are used. See Mbed/README.md.
+- `Output` - This will be created when building.
 - `PregeneratedData` - These are tests sets of data that have been previously been generated and are used in the unit tests.
 - `TestCases` - Here are the actual unit tests. For each function under test there is a folder under here.
 - `TestCases/<cmsis-nn function name>` - For each function under test there is a folder with the same name with test_ prepended to the name and it contains a c-file with the actual unit tests. For example for arm_convolve_s8() the file is called test_arm_convolve_s8.c