aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristofer Jonsson <kristofer.jonsson@arm.com>2022-05-25 16:55:24 +0200
committerKristofer Jonsson <kristofer.jonsson@arm.com>2022-06-13 15:30:33 +0200
commit742261012c087285309bba34b081caf1c6c6ddab (patch)
treef69476623f504ef3d1e0a511ff5d92149d04e6be
parent144b2d2d735d5b2e25894bdeacef7e03761025ad (diff)
downloadethos-u-core-platform-742261012c087285309bba34b081caf1c6c6ddab.tar.gz
Documenting porting guidelines
Change-Id: Icefe078200f9a6a497b410e6c713d80fb9db1ba0
-rw-r--r--PORTING.md201
-rw-r--r--README.md66
-rw-r--r--docs/cmake_components.pngbin0 -> 18842 bytes
-rw-r--r--docs/cmake_components.puml29
-rw-r--r--docs/cmake_components.svg42
-rw-r--r--docs/cmake_target_common.pngbin0 -> 34461 bytes
-rw-r--r--docs/cmake_target_common.puml51
-rw-r--r--docs/cmake_target_common.svg64
-rw-r--r--targets/demo/CMakeLists.txt143
-rw-r--r--targets/demo/retarget.c276
-rw-r--r--targets/demo/target.cpp135
11 files changed, 997 insertions, 10 deletions
diff --git a/PORTING.md b/PORTING.md
new file mode 100644
index 0000000..560b4ae
--- /dev/null
+++ b/PORTING.md
@@ -0,0 +1,201 @@
+# Porting target
+
+Core Platform provides examples how to build and run applications on a few
+target platforms. This guide will demonstrate how to use CMake to extend the
+Core Platform build system with applications, drivers and targets.
+
+The build system is based on the idea that the *target* includes applications
+and drivers. Applications should be platform agnostic without knowledge about
+the target they are executing on, which in theory should allow applications to
+be compiled for a range of targets. Consequently when generating the build
+files, the path to the target is passed to CMake.
+
+```
+$ cmake -B build targets/<your target>
+```
+
+All targets should include [targets/common](targets/common/CMakeLists.txt). This
+directory defines a hierarchy of interface libraries, which are needed by helper
+functions and other CMake targets to configure the build system.
+
+![CMake common targets](docs/cmake_target_common.png "CMake common targets")
+
+For a demo project that extends Core Platform, the subdirectories will be
+included like the figure below illustrates.
+
+![CMake components](docs/cmake_components.png "CMake components")
+
+A complete dependency tree can be generated with Graphviz.
+
+```
+$ cmake -B build --graphviz out.dot targets/<your target>
+$ dot -T png -o out.png out.dot
+```
+
+# Create skeleton
+
+Create a `demo` directory, or name the directory to whatever is preferred. This
+will be the parent directory for the demo project.
+
+```
+$ mkdir demo
+$ cd demo
+```
+
+Create subdirectories for `applications`, `drivers` and `targets`.
+
+```
+$ mkdir applications drivers targets
+$ touch applications/CMakeLists.txt drivers/CMakeLists.txt
+```
+
+# demo/targets/\<your target\>/
+
+Copy [\<core_platform\>/targets/demo](targets/demo) to `<your target>`.
+directory. Rename the directory to whatever is preferred.
+
+```
+$ cp -r <core_platform>/targets/demo targets/
+$ mv targets/demo targets/<your target>
+```
+
+## CMakeLists.txt
+
+Open [targets/\<your target\>/CMakeLists.txt](targets/demo/CMakeLists.txt) and
+customize the settings. The important sections have been marked with `TODO`.
+
+### Default toolchain
+
+Core Platform provides example toolchain files for Arm Clang and GCC. If a
+custom toolchain is needed, then this can be placed under
+`demo/cmake/toolchain/<name>.cmake` and the CMake variable
+`CMAKE_TOOLCHAIN_FILE` set to point at this file.
+
+### CTest
+
+If there exists an emulator for the target platform - for example Arm Virtual
+Hardware or QEmu - then `include(CTest)` can be uncommented and
+`ETHOSU_COMMAND_DEFAULT` configured accordingly. Each of the application elf
+files will be passed to the test command.
+
+Generating the build system, building and testing can be executed like this.
+
+```
+$ cmake -B build targets/<your target>
+$ cmake --build build
+$ ctest --test-dir build
+```
+
+### Memory configuration
+
+[README.md#Memory configurations](README.md#memory-configurations) describes the
+memory configurations that can be considered when mapping the TFLM model, arena
+and fast memory buffer. The scatter file and linker scripts decide where the
+buffers are placed in memory, but can for flexibility be written to switch on
+defines set by the build system.
+
+The provided [CMakeLists.txt](targets/demo/CMakeLists.txt) demonstrates how the
+CMake variables `FAST_MEMORY_SIZE`, `MEMORY_MODEL` and `MEMORY_ARENA` can be
+used to export defines from the build system to the source files.
+
+## target.cpp
+
+`targetSetup()` is invoked from [targets/common/src/init.cpp](init.cpp), after
+the runtime library has been initialized, before the `main()` function is
+invoked. The purpose of this function is to initialize drivers, for example the
+Ethos-U driver or the memory protection unit (MPU).
+
+Open [targets/\<your target\>/target.cpp](targets/demo/target.cpp) in an editor
+and customize the file.
+
+## platform.scatter and platform.ld
+
+Depending on the compiler either a scatter file (Arm Clang) or a linker script
+(GCC) is used to describe the memory layout of the target. Documentation how to
+write scatter files and linker scripts goes beyond the scope of this tutorial,
+but can be found online. The scatter files and linker scripts provided for
+Corstone-300 and Corstone-310 may also be used as reference.
+
+A design decision that needs to be made is if a boot loader or scatter loading
+shall be used. A boot loader copies one or multiple binaries into memory before
+lifting the reset on the Cortex-M CPU. Scatter loading typically means that a
+single firmware binary has been written in flash. The Cortex-M CPU boots from
+flash and copies memory segments from the firmware binary to for example ITCM,
+DTCM and SRAM.
+
+# demo/applications/
+
+Copy the [hello world](applications/hello_world) application to `applications/`.
+This application can be used as template to start with.
+
+```
+$ cp -r <core_platform>/applications/hello_world applications/
+$ mv applications/hello_world applications/demo_app
+```
+
+Open `applications/demo_app/CMakeLists.txt` and rename the application from
+`hello_world` to `demo_app`.
+
+```
+ethosu_add_executable_test(demo_app PRIVATE
+ SOURCES main.cpp)
+```
+
+Edit `applications/CMakeLists.txt` and add the `demo_app` subdirectory.
+
+```
+add_subdirectory(demo_app)
+```
+
+# demo/drivers/
+
+Create a directory structure for a demo driver. Good practice is to separate
+header files with public APIs in a separate folder.
+
+```
+$ mkdir drivers/demo
+$ cd drivers/demo
+
+$ mkdir include src
+$ touch CMakeList.txt include/demo.hpp src/demo.cpp
+```
+
+Add the demo subdirectory to `drivers/CMakeLists.txt`.
+
+```
+add_subdirectory(demo)
+```
+
+Edit `drivers/demo/CMakeLists.txt` and define a static library.
+
+```
+add_library(demo STATIC)
+target_include_directories(demo PUBLIC include)
+target_sources(demo PRIVATE src/demo.cpp)
+```
+
+Edit `drivers/demo/include/demo.hpp` and place types and prototypes here.
+
+```
+void demo();
+```
+
+Edit `drivers/demo/src/demo.cpp`. `printf()` is used for its smaller memory
+footprint, but `iostream` would also work.
+
+```
+#include <stdio.h>
+
+void demo() {
+ printf("Hello Demo\n");
+}
+```
+
+Edit `targets/<your target>/CMakeLists.txt` and link the `demo` library.
+
+```
+target_link_libraries(ethosu_target_startup INTERFACE
+ demo)
+```
+
+Edit `targets/<your target>/target.cpp` and call `demo()` from `targetSetup()`.
diff --git a/README.md b/README.md
index f7ba476..7b922a6 100644
--- a/README.md
+++ b/README.md
@@ -203,7 +203,7 @@ Embedded systems come in very different configurations, but typically they have
a limited amount of high bandwidth low latency memory like SRAM, and some more
low bandwidth high latency memory like flash or DRAM.
-The Tensorflow Lite for Microcontrollers (TFLu) framework needs two buffers to
+The Tensorflow Lite for Microcontrollers (TFLM) framework needs two buffers to
run an inference, the *model* and the *arena*. The model contains static data
like weights and biases. The arena contains read write data like activations,
IFM, OFM, temporary data etc. Please note that the IFM and OFM are located
@@ -218,11 +218,15 @@ are three configurations that make sense for most systems.
| Flash/DRAM | SRAM | No | |
| Flash/DRAM | Flash/DRAM | Yes | Ethos-U65 only |
+Spilling is only available for Ethos-U65 and means that the TFLM model and arena
+are placed in slower memory like flash or DRAM, with a smaller *fast memory*
+buffer placed in faster memory like SRAM.
+
## Model and arena in SRAM
For optimal performance both model and arena should be placed in SRAM.
-## Model flash/DRAM, Arena SRAM
+## Model in flash/DRAM, arena in SRAM
If both model and arena do not fit in SRAM, then it makes most sense to move the
model to flash/DRAM. The performance penalty depends on the network and will
@@ -236,18 +240,60 @@ penalty. To mitigate some of this *spilling* can be used.
Spilling means that a small buffer is reserved in SRAM that acts like a cache
for frequently accessed data. When spilling is enabled
-[Vela](https://git.mlplatform.org/ml/ethos-u/ethos-u-vela.git/about/) will
-prepend and append extra instructions to the command stream to DMA copy data
-between the arena and the spilling buffer.
+[Vela](https://git.mlplatform.org/ml/ethos-u/ethos-u-vela.git/about/) will add
+extra instructions to the command stream to DMA copy data between the arena and
+the spilling buffer.
Some of the data stored in the spilling buffer must be copied back to the arena,
-which is done as DMA transfer over AXI 1. This is only supported by Ethos-U65,
-because Ethos-U55 is equipped with a readonly AXI 1 interface.
+which is done as DMA transfer over AXI interface 1. This is only supported by
+Ethos-U65, because Ethos-U55 is equipped with a readonly AXI 1 interface.
+
+## NPU region configuration
+
+To achieve good performance it is important not to mix slow and fast memory
+transactions on the same AXI interface. The default setup is to map the arena to
+AXI interface 0 and the model to AXI interface 1.
+
+However, if spilling is used the arena should be moved to AXI interface 1 and
+the spilling buffer routed over interface 0. This will ensure that slow memory
+transactions are routed over AXI interface 1 and fast memory transactions over
+AXI interface 0.
+
+The routing of the arena is controlled by define `NPU_REGIONCFG_1`. This define
+is declared in
+[ethosu_config_u55.h](https://git.mlplatform.org/ml/ethos-u/ethos-u-core-driver.git/tree/src/ethosu_config_u55.h)
+or
+[ethosu_config_u65.h](https://git.mlplatform.org/ml/ethos-u/ethos-u-core-driver.git/tree/src/ethosu_config_u65.h)
+depending on which NPU architecture the driver is built for. The default
+configuration is protected by `#ifdef` that can be overridden by the build
+system. Values `0` and `1` map to AXI interface 0 and `2` and `3` map to AXI
+interface 1.
+
+The routing of the model is controlled by `NPU_REGIONCFG_0` and the spilling
+buffer by `NPU_REGIONCFG_2`. For most use cases these configurations should not
+need to be changed.
+
+## NPU burst length
+
+The NPU issues DMA bursts over the AXI interfaces. The burst length is defined
+by the `AXI_LIMIT<nr>_MAX_BEATS_BYTES` in
+[ethosu_config_u55.h](https://git.mlplatform.org/ml/ethos-u/ethos-u-core-driver.git/tree/src/ethosu_config_u55.h)
+or
+[ethosu_config_u65.h](https://git.mlplatform.org/ml/ethos-u/ethos-u-core-driver.git/tree/src/ethosu_config_u65.h)
+and is by default set to its minimum value.
+
+Longer burst lengths will in general yield higher performance. However, burst
+lengths that exceed the maximum supported burst length risk hanging the AXI bus,
+so it is important to configure this value correctly.
+
+# Porting target
+
+Please see [PORTING.md](PORTING.md).
# Multi NPU
-The Tensorflow Lite for Microcontrollers (TFLu) framework supports running
-multiple parallel inferences. Each parallel inference requires a TFLu arena
+The Tensorflow Lite for Microcontrollers (TFLM) framework supports running
+multiple parallel inferences. Each parallel inference requires a TFLM arena
(costs memory) and a stack (requires an RTOS). The examples provided in this
repo are implemented in the application layer, which means that any RTOS could
be used.
@@ -284,7 +330,7 @@ on the network.
For networks that map fully to Ethos-U, the memory bandwidth might become a
limiting factor. For networks that run partly in software, the Cortex-M might
-become the limiting factor. The placement of the TFLu model and arena (flash,
+become the limiting factor. The placement of the TFLM model and arena (flash,
DRAM, SRAM, etc) will also have a big impact on the performance.
# Startup
diff --git a/docs/cmake_components.png b/docs/cmake_components.png
new file mode 100644
index 0000000..2a509ba
--- /dev/null
+++ b/docs/cmake_components.png
Binary files differ
diff --git a/docs/cmake_components.puml b/docs/cmake_components.puml
new file mode 100644
index 0000000..a13abe1
--- /dev/null
+++ b/docs/cmake_components.puml
@@ -0,0 +1,29 @@
+@startuml
+
+skinparam {
+ BackgroundColor #EEEBDC
+ DefaultFontColor white
+}
+
+package "demo/targets/<your target>" #002B49 {
+ package "core_platform/targets/common" #0091BD {
+ package "core_software" #00C1DE {
+ package "core_driver" #7D868C {}
+ package "cmsis" #7D868C {}
+ package "tflite_micro" #7D868C {}
+ package "rtos" #7D868C {}
+ }
+
+ package "core_platform/drivers" #00C1DE {}
+ }
+
+ package "core_platform/applications" #0091BD {}
+ package "demo/applications" #0091BD {}
+ package "demo/drivers" #0091BD {}
+}
+
+"core_platform/applications" -[hidden]> "demo/applications"
+"core_platform/applications" -[hidden]> "demo/drivers"
+"core_platform/targets/common" --[hidden]> "core_platform/applications"
+
+@enduml
diff --git a/docs/cmake_components.svg b/docs/cmake_components.svg
new file mode 100644
index 0000000..706b176
--- /dev/null
+++ b/docs/cmake_components.svg
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="283px" preserveAspectRatio="none" style="width:776px;height:283px;background:#EEEBDC;" version="1.1" viewBox="0 0 776 283" width="776px" zoomAndPan="magnify"><defs><filter height="300%" id="fllzhiafzjk02" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--cluster demo/targets/<your target>--><polygon fill="#002B49" filter="url(#fllzhiafzjk02)" points="14,16,244,16,251,38.2969,754,38.2969,754,271,14,271,14,16" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="14" x2="251" y1="38.2969" y2="38.2969"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="224" x="18" y="30.9951">demo/targets/&lt;your target&gt;</text><!--cluster core_platform/targets/common--><polygon fill="#0091BD" filter="url(#fllzhiafzjk02)" points="22,43,271,43,278,65.2969,746,65.2969,746,166,22,166,22,43" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="22" x2="278" y1="65.2969" y2="65.2969"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="243" x="26" y="57.9951">core_platform/targets/common</text><!--cluster core_software--><polygon fill="#00C1DE" filter="url(#fllzhiafzjk02)" points="282,70,402,70,409,92.2969,738,92.2969,738,158,282,158,282,70" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="282" x2="409" y1="92.2969" y2="92.2969"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="114" x="286" y="84.9951">core_software</text><polygon fill="#7D868C" filter="url(#fllzhiafzjk02)" points="620,97,716,97,723,119.2969,730,119.2969,730,149.5938,620,149.5938,620,97" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="620" x2="723" y1="119.2969" y2="119.2969"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="90" x="624" y="111.9951">core_driver</text><polygon fill="#7D868C" filter="url(#fllzhiafzjk02)" points="519.5,97,570.5,97,577.5,119.2969,584.5,119.2969,584.5,149.5938,519.5,149.5938,519.5,97" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="519.5" x2="577.5" y1="119.2969" y2="119.2969"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="45" x="523.5" y="111.9951">cmsis</text><polygon fill="#7D868C" filter="url(#fllzhiafzjk02)" points="377.5,97,470.5,97,477.5,119.2969,484.5,119.2969,484.5,149.5938,377.5,149.5938,377.5,97" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="377.5" x2="477.5" y1="119.2969" y2="119.2969"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="87" x="381.5" y="111.9951">tflite_micro</text><polygon fill="#7D868C" filter="url(#fllzhiafzjk02)" points="290,97,328,97,335,119.2969,342,119.2969,342,149.5938,290,149.5938,290,97" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="290" x2="335" y1="119.2969" y2="119.2969"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="32" x="294" y="111.9951">rtos</text><polygon fill="#00C1DE" filter="url(#fllzhiafzjk02)" points="30,97,206,97,213,119.2969,220,119.2969,220,149.5938,30,149.5938,30,97" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="30" x2="213" y1="119.2969" y2="119.2969"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="170" x="34" y="111.9951">core_platform/drivers</text><polygon fill="#0091BD" filter="url(#fllzhiafzjk02)" points="141,210,355,210,362,232.2969,369,232.2969,369,262.5938,141,262.5938,141,210" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="141" x2="362" y1="232.2969" y2="232.2969"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="208" x="145" y="224.9951">core_platform/applications</text><polygon fill="#0091BD" filter="url(#fllzhiafzjk02)" points="564.5,210,713.5,210,720.5,232.2969,727.5,232.2969,727.5,262.5938,564.5,262.5938,564.5,210" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="564.5" x2="720.5" y1="232.2969" y2="232.2969"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="143" x="568.5" y="224.9951">demo/applications</text><polygon fill="#0091BD" filter="url(#fllzhiafzjk02)" points="404.5,210,515.5,210,522.5,232.2969,529.5,232.2969,529.5,262.5938,404.5,262.5938,404.5,210" style="stroke: #000000; stroke-width: 2.0;"/><line style="stroke: #000000; stroke-width: 2.0;" x1="404.5" x2="522.5" y1="232.2969" y2="232.2969"/><text fill="#FFFFFF" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="105" x="408.5" y="224.9951">demo/drivers</text><!--link core_platform/applications to demo/applications--><!--link core_platform/applications to demo/drivers--><!--link core_platform/targets/common to core_platform/applications--><!--
+@startuml
+
+skinparam {
+ BackgroundColor #EEEBDC
+ DefaultFontColor white
+}
+
+package "demo/targets/<your target>" #002B49 {
+ package "core_platform/targets/common" #0091BD {
+ package "core_software" #00C1DE {
+ package "core_driver" #7D868C {}
+ package "cmsis" #7D868C {}
+ package "tflite_micro" #7D868C {}
+ package "rtos" #7D868C {}
+ }
+
+ package "core_platform/drivers" #00C1DE {}
+ }
+
+ package "core_platform/applications" #0091BD {}
+ package "demo/applications" #0091BD {}
+ package "demo/drivers" #0091BD {}
+}
+
+"core_platform/applications" -[hidden]> "demo/applications"
+"core_platform/applications" -[hidden]> "demo/drivers"
+"core_platform/targets/common" - -[hidden]> "core_platform/applications"
+
+@enduml
+
+PlantUML version 1.2017.15(Mon Jul 03 18:45:34 CEST 2017)
+(GPL source distribution)
+Java Runtime: OpenJDK Runtime Environment
+JVM: OpenJDK 64-Bit Server VM
+Java Version: 11.0.15+10-Ubuntu-0ubuntu0.18.04.1
+Operating System: Linux
+OS Version: 5.4.0-113-generic
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg> \ No newline at end of file
diff --git a/docs/cmake_target_common.png b/docs/cmake_target_common.png
new file mode 100644
index 0000000..99f686c
--- /dev/null
+++ b/docs/cmake_target_common.png
Binary files differ
diff --git a/docs/cmake_target_common.puml b/docs/cmake_target_common.puml
new file mode 100644
index 0000000..c91b9c8
--- /dev/null
+++ b/docs/cmake_target_common.puml
@@ -0,0 +1,51 @@
+@startuml
+
+skinparam {
+ BackgroundColor #EEEBDC
+ DefaultFontColor black
+}
+
+skinparam component {
+ BackgroundColor #0091BD
+ BorderColor black
+ ArrowColor black
+}
+
+skinparam note {
+ BackgroundColor #00C1DE
+ BorderColor black
+}
+
+[ethosu_target_init] --> [ethosu_target_startup]
+
+[ethosu_target_startup] --> [ethosu_target_link]
+
+[ethosu_target_link] --> [ethosu_target_common]
+
+note right of ethosu_target_init
+ Links drivers and calls targetSetup() to initialize the target.
+end note
+
+note right of ethosu_target_startup
+ Links CMSIS Device and Core libraries.
+
+ CMSIS Device provides startup and system files that are used to initialize
+ the CPU, configure CPU extensions and setup the interrupt vector table.
+
+ CMSIS Core provides an interface to the CPU, for example configuring
+ caches, systick or interrupt handling.
+
+ Some RTOSes provide their own startup files. Those applications should
+ link ethosu_target_link instead.
+end note
+
+note right of ethosu_target_link
+ Adds scatter file or linker script, describing the memory layout of the target.
+end note
+
+note right of ethosu_target_common
+ All applications should depend on this library. It is used to export definitions
+ from the target to the application.
+end note
+
+@enduml
diff --git a/docs/cmake_target_common.svg b/docs/cmake_target_common.svg
new file mode 100644
index 0000000..63bd79c
--- /dev/null
+++ b/docs/cmake_target_common.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="473px" preserveAspectRatio="none" style="width:747px;height:473px;background:#EEEBDC;" version="1.1" viewBox="0 0 747 473" width="747px" zoomAndPan="magnify"><defs><filter height="300%" id="f1f0gza4i4o0zv" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--entity ethosu_target_init--><rect fill="#0091BD" filter="url(#f1f0gza4i4o0zv)" height="36.2969" style="stroke: #000000; stroke-width: 1.5;" width="144" x="26.5" y="8"/><rect fill="#0091BD" height="5" style="stroke: #000000; stroke-width: 1.5;" width="10" x="21.5" y="13"/><rect fill="#0091BD" height="5" style="stroke: #000000; stroke-width: 1.5;" width="10" x="21.5" y="34.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="124" x="36.5" y="30.9951">ethosu_target_init</text><!--entity ethosu_target_startup--><rect fill="#0091BD" filter="url(#f1f0gza4i4o0zv)" height="36.2969" style="stroke: #000000; stroke-width: 1.5;" width="173" x="12" y="166.5"/><rect fill="#0091BD" height="5" style="stroke: #000000; stroke-width: 1.5;" width="10" x="7" y="171.5"/><rect fill="#0091BD" height="5" style="stroke: #000000; stroke-width: 1.5;" width="10" x="7" y="192.7969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="153" x="22" y="189.4951">ethosu_target_startup</text><!--entity ethosu_target_link--><rect fill="#0091BD" filter="url(#f1f0gza4i4o0zv)" height="36.2969" style="stroke: #000000; stroke-width: 1.5;" width="147" x="25" y="325"/><rect fill="#0091BD" height="5" style="stroke: #000000; stroke-width: 1.5;" width="10" x="20" y="330"/><rect fill="#0091BD" height="5" style="stroke: #000000; stroke-width: 1.5;" width="10" x="20" y="351.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="127" x="35" y="347.9951">ethosu_target_link</text><!--entity ethosu_target_common--><rect fill="#0091BD" filter="url(#f1f0gza4i4o0zv)" height="36.2969" style="stroke: #000000; stroke-width: 1.5;" width="185" x="6" y="423"/><rect fill="#0091BD" height="5" style="stroke: #000000; stroke-width: 1.5;" width="10" x="1" y="428"/><rect fill="#0091BD" height="5" style="stroke: #000000; stroke-width: 1.5;" width="10" x="1" y="449.2969"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="165" x="16" y="445.9951">ethosu_target_common</text><polygon fill="#00C1DE" filter="url(#f1f0gza4i4o0zv)" points="206,13.5,206,38.6328,601,38.6328,601,23.5,591,13.5,206,13.5" style="stroke: #000000; stroke-width: 1.0;"/><polygon fill="#00C1DE" points="206,13.5,206,22,170.5801,26,206,30,206,38.6328,601,38.6328,601,23.5,591,13.5,206,13.5" style="stroke: #000000; stroke-width: 1.0;"/><line style="stroke: #000000; stroke-width: 1.0;" x1="591" x2="591" y1="13.5" y2="23.5"/><line style="stroke: #000000; stroke-width: 1.0;" x1="601" x2="591" y1="23.5" y2="23.5"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="374" x="212" y="30.5669">Links drivers and calls targetSetup() to initialize the target.</text><polygon fill="#00C1DE" filter="url(#f1f0gza4i4o0zv)" points="220,104,220,265.3281,707,265.3281,707,114,697,104,220,104" style="stroke: #000000; stroke-width: 1.0;"/><polygon fill="#00C1DE" points="220,104,220,180.5,185.1162,184.5,220,188.5,220,265.3281,707,265.3281,707,114,697,104,220,104" style="stroke: #000000; stroke-width: 1.0;"/><line style="stroke: #000000; stroke-width: 1.0;" x1="697" x2="697" y1="104" y2="114"/><line style="stroke: #000000; stroke-width: 1.0;" x1="707" x2="697" y1="114" y2="114"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="244" x="226" y="121.0669">Links CMSIS Device and Core libraries.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="230" y="136.1997"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="466" x="226" y="151.3325">CMSIS Device provides startup and system files that are used to initialize</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="459" x="226" y="166.4653">the CPU, configure CPU extensions and setup the interrupt vector table.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="230" y="181.5981"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="444" x="226" y="196.731">CMSIS Core provides an interface to the CPU, for example configuring</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="234" x="226" y="211.8638">caches, systick or interrupt handling.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="230" y="226.9966"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="455" x="226" y="242.1294">Some RTOSes provide their own startup files. Those applications should</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="198" x="226" y="257.2622">link ethosu_target_link instead.</text><polygon fill="#00C1DE" filter="url(#f1f0gza4i4o0zv)" points="207,330.5,207,355.6328,712,355.6328,712,340.5,702,330.5,207,330.5" style="stroke: #000000; stroke-width: 1.0;"/><polygon fill="#00C1DE" points="207,330.5,207,339,172.1807,343,207,347,207,355.6328,712,355.6328,712,340.5,702,330.5,207,330.5" style="stroke: #000000; stroke-width: 1.0;"/><line style="stroke: #000000; stroke-width: 1.0;" x1="702" x2="702" y1="330.5" y2="340.5"/><line style="stroke: #000000; stroke-width: 1.0;" x1="712" x2="702" y1="340.5" y2="340.5"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="484" x="213" y="347.5669">Adds scatter file or linker script, describing the memory layout of the target.</text><polygon fill="#00C1DE" filter="url(#f1f0gza4i4o0zv)" points="225.5,421,225.5,461.2656,725.5,461.2656,725.5,431,715.5,421,225.5,421" style="stroke: #000000; stroke-width: 1.0;"/><polygon fill="#00C1DE" points="225.5,421,225.5,437,191.2773,441,225.5,445,225.5,461.2656,725.5,461.2656,725.5,431,715.5,421,225.5,421" style="stroke: #000000; stroke-width: 1.0;"/><line style="stroke: #000000; stroke-width: 1.0;" x1="715.5" x2="715.5" y1="421" y2="431"/><line style="stroke: #000000; stroke-width: 1.0;" x1="725.5" x2="715.5" y1="431" y2="431"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="479" x="231.5" y="438.0669">All applications should depend on this library. It is used to export definitions</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="217" x="231.5" y="453.1997">from the target to the application.</text><!--link ethosu_target_init to ethosu_target_startup--><path d="M98.5,44.182 C98.5,72.9303 98.5,128.8824 98.5,160.7609 " fill="none" id="ethosu_target_init-ethosu_target_startup" style="stroke: #000000; stroke-width: 1.0;"/><polygon fill="#000000" points="98.5,166.0419,102.5,157.0419,98.5,161.0419,94.5,157.0419,98.5,166.0419" style="stroke: #000000; stroke-width: 1.0;"/><!--link ethosu_target_startup to ethosu_target_link--><path d="M98.5,202.682 C98.5,231.4303 98.5,287.3824 98.5,319.2609 " fill="none" id="ethosu_target_startup-ethosu_target_link" style="stroke: #000000; stroke-width: 1.0;"/><polygon fill="#000000" points="98.5,324.5419,102.5,315.5419,98.5,319.5419,94.5,315.5419,98.5,324.5419" style="stroke: #000000; stroke-width: 1.0;"/><!--link ethosu_target_link to ethosu_target_common--><path d="M98.5,361.4331 C98.5,377.4118 98.5,400.611 98.5,417.84 " fill="none" id="ethosu_target_link-ethosu_target_common" style="stroke: #000000; stroke-width: 1.0;"/><polygon fill="#000000" points="98.5,422.9807,102.5,413.9807,98.5,417.9807,94.5,413.9807,98.5,422.9807" style="stroke: #000000; stroke-width: 1.0;"/><!--
+@startuml
+
+skinparam {
+ BackgroundColor #EEEBDC
+ DefaultFontColor black
+}
+
+skinparam component {
+ BackgroundColor #0091BD
+ BorderColor black
+ ArrowColor black
+}
+
+skinparam note {
+ BackgroundColor #00C1DE
+ BorderColor black
+}
+
+[ethosu_target_init] - -> [ethosu_target_startup]
+
+[ethosu_target_startup] - -> [ethosu_target_link]
+
+[ethosu_target_link] - -> [ethosu_target_common]
+
+note right of ethosu_target_init
+ Links drivers and calls targetSetup() to initialize the target.
+end note
+
+note right of ethosu_target_startup
+ Links CMSIS Device and Core libraries.
+
+ CMSIS Device provides startup and system files that are used to initialize
+ the CPU, configure CPU extensions and setup the interrupt vector table.
+
+ CMSIS Core provides an interface to the CPU, for example configuring
+ caches, systick or interrupt handling.
+
+ Some RTOSes provide their own startup files. Those applications should
+ link ethosu_target_link instead.
+end note
+
+note right of ethosu_target_link
+ Adds scatter file or linker script, describing the memory layout of the target.
+end note
+
+note right of ethosu_target_common
+ All applications should depend on this library. It is used to export definitions
+ from the target to the application.
+end note
+
+@enduml
+
+PlantUML version 1.2017.15(Mon Jul 03 18:45:34 CEST 2017)
+(GPL source distribution)
+Java Runtime: OpenJDK Runtime Environment
+JVM: OpenJDK 64-Bit Server VM
+Java Version: 11.0.15+10-Ubuntu-0ubuntu0.18.04.1
+Operating System: Linux
+OS Version: 5.4.0-113-generic
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg> \ No newline at end of file
diff --git a/targets/demo/CMakeLists.txt b/targets/demo/CMakeLists.txt
new file mode 100644
index 0000000..a1ba620
--- /dev/null
+++ b/targets/demo/CMakeLists.txt
@@ -0,0 +1,143 @@
+#
+# Copyright (c) 2022 Arm Limited.
+#
+# 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.
+#
+
+#############################################################################
+# Paths
+#############################################################################
+
+set(CORE_PLATFORM_PATH "${CMAKE_CURRENT_SOURCE_DIR}/<TODO>/core_platform" CACHE PATH "Path to Core Platform")
+
+#############################################################################
+# Default toolchain
+#############################################################################
+
+set(TARGET_CPU "<TODO e.g. cortex-m55>" CACHE STRING "Target CPU")
+
+if (NOT CMAKE_TOOLCHAIN_FILE)
+ # TODO Select default toolchain
+ # - Arm Clang: ${CORE_PLATFORM_PATH}/cmake/toolchain/armclang.cmake
+ # - GCC : ${CORE_PLATFORM_PATH}/cmake/toolchain/arm-none-eabi-gcc.cmake
+ # - Else : Implement your own toolchain file
+ set(CMAKE_TOOLCHAIN_FILE "${CORE_PLATFORM_PATH}/cmake/toolchain/armclang.cmake")
+endif()
+
+#############################################################################
+# Default configuration
+#############################################################################
+
+get_filename_component(ETHOSU_TARGET ${CMAKE_CURRENT_SOURCE_DIR} NAME)
+message("Configuring target ${ETHOSU_TARGET}")
+
+set(ETHOSU_TARGET_NPU_CONFIG "<TODO> e.g. ethos-u65-256" CACHE STRING "NPU configuration")
+set(ETHOSU_TARGET_NPU_COUNT 1 CACHE INTERNAL "Number of NPUs")
+set(ETHOSU_TARGET_NPU_TA_COUNT 0 CACHE INTERNAL "Number of timing adapters per NPU")
+
+# Fast memory size
+# If the TFLM model and arena are placed in Flash/DRAM, and if the NPU is Ethos-U65,
+# then a smaller fast memory buffer can be placed in SRAM. This is called 'spilling'.
+set(FAST_MEMORY_SIZE 0 CACHE STRING "Size of relocated fast memory scratch tensor")
+set(MEMORY_MODEL "sram" CACHE STRING "Memory config for model")
+set(MEMORY_ARENA "sram" CACHE STRING "Memory config for arena")
+
+# UART settings
+set(UART0_BASE "<TODO>" CACHE INTERNAL "UART base address")
+set(UART0_BAUDRATE "<TODO e.g. 115200>" CACHE INTERNAL "UART baudrate, N/A for model and juno")
+set(SYSTEM_CORE_CLOCK "<TODO e.g. 25000000>" CACHE INTERNAL "System core clock (Hz)")
+
+#############################################################################
+# Project
+#############################################################################
+
+cmake_minimum_required(VERSION 3.21)
+
+project(ethos-u-demo VERSION 0.0.1)
+
+include(${CORE_PLATFORM_PATH}/cmake/helpers.cmake)
+
+#############################################################################
+# Target
+#############################################################################
+
+# Include common target
+add_subdirectory(${CORE_PLATFORM_PATH}/targets/common core_platform/target/common)
+
+# Include drivers
+add_subdirectory(../../drivers drivers)
+
+# Common defines
+target_compile_definitions(ethosu_target_common INTERFACE
+ # Configure NPU architecture and number of timing adapters
+ ETHOSU_NPU_COUNT=${ETHOSU_TARGET_NPU_COUNT}
+ ETHOSU_NPU_TA_COUNT=${ETHOSU_TARGET_NPU_TA_COUNT}
+
+ # Placement or TLFu model and area. 0 = SRAM, 1 = DRAM
+ # The scatter file and linker script must be designed to switch on these defines
+ ETHOSU_FAST_MEMORY_SIZE=${FAST_MEMORY_SIZE}
+ ETHOSU_MODEL=$<STREQUAL:${MEMORY_MODEL},dram>
+ ETHOSU_ARENA=$<STREQUAL:${MEMORY_ARENA},dram>)
+
+# Linker script
+set(LINK_FILE platform CACHE STRING "Link file")
+
+ethosu_target_link_options(ethosu_target_link INTERFACE
+ LINK_FILE ${LINK_FILE}
+ ENTRY Reset_Handler)
+
+target_sources(ethosu_target_startup INTERFACE
+ retarget.c
+ target.cpp)
+
+target_link_libraries(ethosu_target_startup INTERFACE
+ $<$<TARGET_EXISTS:ethosu_core_driver>:ethosu_core_driver>
+ # TODO customize which libraries to include
+ mpu
+ ethosu_mhu_dummy
+ ethosu_uart_cmsdk_apb)
+
+if (TARGET ethosu_core_driver)
+ target_compile_definitions(ethosu_core_driver PUBLIC
+ ETHOSU
+
+ # The TFLM arena is accessed over base address 1. The region config
+ # controls if the memory transactions are routed over AXI 0 (region config
+ # 0 or 1) or AXI 1 (region config 2 or 3).
+ NPU_REGIONCFG_1=$<if:$<STREQUAL:${MEMORY_ARENA},dram>,0,2>)
+endif()
+
+###############################################################################
+# CTest
+###############################################################################
+
+# TODO Uncomment to enable ctest
+# include(CTest)
+
+# Uncomment if Python interpreter is needed
+#set(Python3_FIND_STRATEGY LOCATION)
+#find_package(Python3 COMPONENTS Interpreter)
+
+# TODO Uncomment if ETHOSU_ARCH and ETHOSU_NUM_MACS are needed
+# ethosu_get_architecture(${ETHOSU_TARGET_NPU_CONFIG})
+
+set(ETHOSU_COMMAND_DEFAULT <TODO test command> CACHE INTERNAL "Default test command")
+
+###############################################################################
+# Applications
+###############################################################################
+
+add_subdirectory(${CORE_PLATFORM_PATH}/applications core_platform/applications)
+add_subdirectory(../../applications applications)
diff --git a/targets/demo/retarget.c b/targets/demo/retarget.c
new file mode 100644
index 0000000..3355e2e
--- /dev/null
+++ b/targets/demo/retarget.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2019-2022 Arm Limited.
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "uart_stdout.h"
+
+// armclang retargeting
+#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100)
+#include <rt_misc.h>
+#include <rt_sys.h>
+
+/* Standard IO device handles. */
+#define STDIN 0x8001
+#define STDOUT 0x8002
+#define STDERR 0x8003
+
+#define RETARGET(fun) _sys##fun
+#define IO_OUTPUT(len) 0
+
+#else
+/*
+ * This type is used by the _ I/O functions to denote an open
+ * file.
+ */
+typedef int FILEHANDLE;
+
+/*
+ * Open a file. May return -1 if the file failed to open.
+ */
+extern FILEHANDLE _open(const char * /*name*/, int /*openmode*/);
+
+/* Standard IO device handles. */
+#define STDIN 0x00
+#define STDOUT 0x01
+#define STDERR 0x02
+
+#define RETARGET(fun) fun
+#define IO_OUTPUT(len) len
+
+#endif
+
+/* Standard IO device name defines. */
+const char __stdin_name[] __attribute__((aligned(4))) = "STDIN";
+const char __stdout_name[] __attribute__((aligned(4))) = "STDOUT";
+const char __stderr_name[] __attribute__((aligned(4))) = "STDERR";
+
+void _ttywrch(int ch) {
+ (void)fputc(ch, stdout);
+}
+
+FILEHANDLE RETARGET(_open)(const char *name, int openmode) {
+ (void)openmode;
+
+ if (strcmp(name, __stdin_name) == 0) {
+ return (STDIN);
+ }
+
+ if (strcmp(name, __stdout_name) == 0) {
+ return (STDOUT);
+ }
+
+ if (strcmp(name, __stderr_name) == 0) {
+ return (STDERR);
+ }
+
+ return -1;
+}
+
+int RETARGET(_write)(FILEHANDLE fh, const unsigned char *buf, unsigned int len, int mode) {
+ (void)mode;
+
+ switch (fh) {
+ case STDOUT:
+ case STDERR: {
+ int c;
+ unsigned int i;
+
+ for (i = 0; i < len; i++) {
+ c = fputc(buf[i], stdout);
+ if (c == EOF) {
+ return EOF;
+ }
+ }
+
+ return IO_OUTPUT(len);
+ }
+ default:
+ return EOF;
+ }
+}
+
+int RETARGET(_read)(FILEHANDLE fh, unsigned char *buf, unsigned int len, int mode) {
+ (void)mode;
+
+ switch (fh) {
+ case STDIN: {
+ int c;
+ unsigned int i;
+
+ for (i = 0; i < len; i++) {
+ c = fgetc(stdin);
+ if (c == EOF) {
+ return EOF;
+ }
+
+ buf[i] = (unsigned char)c;
+ }
+
+ return IO_OUTPUT(len);
+ }
+ default:
+ return EOF;
+ }
+}
+
+int RETARGET(_istty)(FILEHANDLE fh) {
+ switch (fh) {
+ case STDIN:
+ case STDOUT:
+ case STDERR:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int RETARGET(_close)(FILEHANDLE fh) {
+ if (RETARGET(_istty(fh))) {
+ return 0;
+ }
+
+ return -1;
+}
+
+int RETARGET(_seek)(FILEHANDLE fh, long pos) {
+ (void)fh;
+ (void)pos;
+
+ return -1;
+}
+
+int RETARGET(_ensure)(FILEHANDLE fh) {
+ (void)fh;
+
+ return -1;
+}
+
+long RETARGET(_flen)(FILEHANDLE fh) {
+ if (RETARGET(_istty)(fh)) {
+ return 0;
+ }
+
+ return -1;
+}
+
+int RETARGET(_tmpnam)(char *name, int sig, unsigned maxlen) {
+ (void)name;
+ (void)sig;
+ (void)maxlen;
+
+ return 1;
+}
+
+char *RETARGET(_command_string)(char *cmd, int len) {
+ (void)len;
+
+ return cmd;
+}
+
+void RETARGET(_exit)(int return_code) {
+ char exit_code_buffer[64] = {0};
+ const char *p = exit_code_buffer;
+
+ /* Print out the exit code on the uart so any reader know how we exit. */
+ /* By appending 0x04, ASCII for end-of-transmission the FVP model exits,
+ * if the configuration parameter shutdown_on_eot on the uart is enabled.
+ * For some versions of FVP, the shutdown_on_eot is broken, but the same
+ * behaviour can be created by passing specifying a shutdown_tag= for the
+ * uart when starting the model so that is added last as well.
+ */
+
+ snprintf(exit_code_buffer,
+ sizeof(exit_code_buffer),
+ "Application exit code: %d.\n" // Let the readers know how we exit
+ "\04\n" // end-of-transmission
+ "EXITTHESIM\n", // shutdown_tag
+ return_code);
+
+ while (*p != '\0') {
+ UartPutc(*p++);
+ }
+
+ while (1) {}
+}
+
+int system(const char *cmd) {
+ (void)cmd;
+
+ return 0;
+}
+
+time_t time(time_t *timer) {
+ time_t current;
+
+ current = 0; // To Do !! No RTC implemented
+
+ if (timer != NULL) {
+ *timer = current;
+ }
+
+ return current;
+}
+
+void _clock_init(void) {
+#if 0
+ // Example implementation based on SysTick
+ // For instance, use a counting var in a SysTick interrupt handler
+ // for clock() to use
+ SysTick->LOAD = (uint32_t) ((SystemCoreClock/100)-1UL);
+ NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
+ SysTick->VAL = 0UL;
+ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
+#endif
+}
+
+clock_t clock(void) {
+ return (clock_t)-1;
+}
+
+int remove(const char *arg) {
+ (void)arg;
+ return 0;
+}
+
+int rename(const char *oldn, const char *newn) {
+ (void)oldn;
+ (void)newn;
+ return 0;
+}
+
+int fputc(int ch, FILE *f) {
+ (void)(f);
+ return UartPutc(ch);
+}
+
+int fgetc(FILE *f) {
+ (void)f;
+ return UartPutc(UartGetc());
+}
+
+#ifndef ferror
+/* arm-none-eabi-gcc with newlib uses a define for ferror */
+int ferror(FILE *f) {
+ (void)f;
+ return EOF;
+}
+#endif
diff --git a/targets/demo/target.cpp b/targets/demo/target.cpp
new file mode 100644
index 0000000..6fac5b0
--- /dev/null
+++ b/targets/demo/target.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2022 Arm Limited.
+ *
+ * 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.
+ */
+
+/****************************************************************************
+ * Includes
+ ****************************************************************************/
+
+#include "target.hpp"
+
+#ifdef ETHOSU
+#include <ethosu_driver.h>
+#endif
+
+#include "mpu.hpp"
+#include "uart_stdout.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <vector>
+
+using namespace EthosU;
+
+/****************************************************************************
+ * Defines
+ ****************************************************************************/
+
+#ifdef ETHOSU
+#define ETHOSU_BASE_ADDRESS <TODO>
+#define ETHOSU_IRQ <TODO>
+#endif
+
+/****************************************************************************
+ * Variables
+ ****************************************************************************/
+
+#ifdef ETHOSU
+#if defined(ETHOSU_FAST_MEMORY_SIZE) && ETHOSU_FAST_MEMORY_SIZE > 0
+__attribute__((aligned(16), section(".bss.ethosu_scratch"))) uint8_t ethosu_scratch[ETHOSU_FAST_MEMORY_SIZE];
+#else
+#define ethosu_scratch 0
+#define ETHOSU_FAST_MEMORY_SIZE 0
+#endif
+
+struct ethosu_driver ethosu0_driver;
+#endif
+
+/****************************************************************************
+ * Cache maintenance
+ ****************************************************************************/
+
+#if defined(CPU_CACHE_ENABLE) && defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
+extern "C" {
+void ethosu_flush_dcache(uint32_t *p, size_t bytes) {
+ if (p)
+ SCB_CleanDCache_by_Addr(p, bytes);
+ else
+ SCB_CleanDCache();
+}
+
+void ethosu_invalidate_dcache(uint32_t *p, size_t bytes) {
+ if (p)
+ SCB_InvalidateDCache_by_Addr(p, bytes);
+ else
+ SCB_InvalidateDCache();
+}
+}
+#endif
+
+/****************************************************************************
+ * Init
+ ****************************************************************************/
+
+namespace {
+
+#ifdef ETHOSU
+void ethosuIrqHandler() {
+ ethosu_irq_handler(&ethosu0_driver);
+}
+#endif
+
+} // namespace
+
+namespace EthosU {
+
+void targetSetup() {
+ // Initialize UART driver
+ UartStdOutInit();
+
+#ifdef ETHOSU
+ // Initialize Ethos-U NPU driver
+ if (ethosu_init(&ethosu0_driver,
+ reinterpret_cast<void *>(ETHOSU_BASE_ADDRESS),
+ ethosu_scratch,
+ ETHOSU_FAST_MEMORY_SIZE,
+ 1,
+ 1)) {
+ printf("Failed to initialize NPU.\n");
+ return;
+ }
+
+ // Assumes SCB->VTOR point to RW memory
+ NVIC_SetVector(static_cast<IRQn_Type>(ETHOSU_IRQ), (uint32_t)&ethosuIrqHandler);
+ NVIC_EnableIRQ(static_cast<IRQn_Type>(ETHOSU_IRQ));
+#endif
+
+ // MPU setup
+ // TODO Add memory protection unit configuration
+ const std::vector<ARM_MPU_Region_t> mpuConfig = {};
+
+ // Setup MPU configuration
+ Mpu::loadAndEnableConfig(&mpuConfig[0], mpuConfig.size());
+
+#if defined(CPU_CACHE_ENABLE) && defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
+ SCB_EnableICache();
+ SCB_EnableDCache();
+#endif
+}
+
+} // namespace EthosU