Browse Source

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 years ago
parent
commit
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.")
 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")
     set(CMAKE_EXECUTABLE_SUFFIX ".elf")
 endif()
 endif()
 
 
@@ -85,33 +89,58 @@ execute_process(COMMAND ${MAKE_CMD} ${MAKE_CMD_SCRIPT} ${MAKE_CMD_SCRIPT_OPTION}
                         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
                         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 add_subdirectory(Unity)
 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")
     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")
     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()
     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()
 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 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
 ## 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.
 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.
 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.
 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).
 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.
 For generating new data, the python3 packages tensorflow, numpy and packaging are required. Tensorflow version 2 is required as a minimum.
 
 
 ## Getting started
 ## 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:
 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.
 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:
 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:
 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
+
 Generating new test data is done with the following script. Use the -h flag to get more info.
 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
 ## 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.
 - `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.
 - `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` - 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
 - `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