This is an automated email from the ASF dual-hosted git repository.
mehrdadh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/main by this push:
new a1dc4b91a4 [microTVM] Refactor required external functions in CRT to
platform-template.c (#13885)
a1dc4b91a4 is described below
commit a1dc4b91a4752a0566ae349b5c68af277767b897
Author: Mehrdad Hessar <[email protected]>
AuthorDate: Mon Feb 13 12:56:07 2023 -0800
[microTVM] Refactor required external functions in CRT to
platform-template.c (#13885)
This PR refactors all the necessary functions for a CRT project into
platform-template.c file
In addition, these templates files are also added along with
crt_config-template.h (which was accidentally removed in #13812) to generated
model library format (MLF). Here is the updated structure of a MLF file:
.
├── codegen
│ └── host
├── metadata.json
├── parameters
│ └── default.params
├── runtime
│ ├── include
│ ├── Makefile
│ └── src
├── src
│ └── default.relay
└── templates
├── crt_config-template.h
├── platform-template.c
---
.../template_project/microtvm_api_server.py | 10 +-
.../src/example_project/{model.c => platform.c} | 25 ++-
.../src/example_project/{model.h => platform.h} | 4 -
.../src/example_project/project.ino | 4 +-
.../host_driven/{model_support.c => platform.c} | 12 +-
.../template_project/CMakeLists.txt.template | 2 +-
.../zephyr/template_project/microtvm_api_server.py | 67 +++++--
.../src/aot_standalone_demo/main.c | 193 ++++++++-------------
.../src/aot_standalone_demo/{main.c => platform.c} | 165 +++---------------
.../src/aot_standalone_demo/zephyr_uart.c | 87 ----------
.../src/aot_standalone_demo/zephyr_uart.h | 50 ------
.../src/host_driven/fvp/semihost.c | 2 +-
.../zephyr/template_project/src/host_driven/main.c | 154 +---------------
.../template_project/src/host_driven/platform.c | 155 +++++++++++++++++
.../template_project/src/mlperftiny/platform.cc | 68 ++++++++
.../src/mlperftiny/submitter_implemented.cc | 174 +++++++++++++++++--
.../template_project/src/mlperftiny/tvmruntime.cc | 164 -----------------
.../template_project/src/mlperftiny/tvmruntime.h | 62 -------
.../template_project/src/mlperftiny/zephyr_uart.cc | 89 ----------
.../template_project/src/mlperftiny/zephyr_uart.h | 51 ------
cmake/modules/CRT.cmake | 7 +-
cmake/modules/Zephyr.cmake | 2 -
.../how_to/work_with_microtvm/micro_mlperftiny.py | 2 +-
gallery/how_to/work_with_microtvm/micro_pytorch.py | 2 +-
include/tvm/runtime/crt/platform.h | 9 +
python/tvm/micro/model_library_format.py | 14 +-
python/tvm/testing/aot.py | 4 +-
src/runtime/crt/host/Makefile.template | 4 +-
src/runtime/crt/host/main.cc | 78 +--------
src/runtime/crt/host/microtvm_api_server.py | 31 ++--
src/runtime/crt/host/{main.cc => platform.cc} | 124 ++++---------
src/runtime/crt/platform-template.c | 80 +++++++++
tests/micro/arduino/test_arduino_workflow.py | 14 +-
tests/micro/arduino/testdata/project.ino | 5 +-
tests/micro/zephyr/test_zephyr.py | 36 ++++
.../zephyr/test_zephyr_aot_exec_standalone.py | 4 +-
tests/micro/zephyr/utils.py | 8 +-
.../unittest/test_micro_model_library_format.py | 25 +++
38 files changed, 818 insertions(+), 1169 deletions(-)
diff --git a/apps/microtvm/arduino/template_project/microtvm_api_server.py
b/apps/microtvm/arduino/template_project/microtvm_api_server.py
index 05c17ee194..f121238a67 100644
--- a/apps/microtvm/arduino/template_project/microtvm_api_server.py
+++ b/apps/microtvm/arduino/template_project/microtvm_api_server.py
@@ -197,8 +197,8 @@ class Handler(server.ProjectAPIHandler):
metadata = json.load(f)
return metadata
- def _template_model_header(self, source_dir, metadata):
- with open(source_dir / "model.h", "r") as f:
+ def _template_model(self, source_dir, metadata):
+ with open(source_dir / "platform.c", "r") as f:
model_h_template = Template(f.read())
all_module_names = []
@@ -218,7 +218,7 @@ class Handler(server.ProjectAPIHandler):
"workspace_size_bytes": workspace_size_bytes,
}
- with open(source_dir / "model.h", "w") as f:
+ with open(source_dir / "platform.c", "w") as f:
f.write(model_h_template.substitute(template_values))
# Arduino ONLY recognizes .ino, .ccp, .c, .h
@@ -415,9 +415,9 @@ class Handler(server.ProjectAPIHandler):
metadata = self._disassemble_mlf(model_library_format_path, source_dir)
shutil.copy2(model_library_format_path, project_dir /
MODEL_LIBRARY_FORMAT_RELPATH)
- # For AOT, template model.h with metadata to minimize space usage
+ # For AOT, template platform.c with metadata to minimize space usage
if project_type == "example_project":
- self._template_model_header(source_dir, metadata)
+ self._template_model(source_dir, metadata)
self._change_cpp_file_extensions(source_dir)
diff --git a/apps/microtvm/arduino/template_project/src/example_project/model.c
b/apps/microtvm/arduino/template_project/src/example_project/platform.c
similarity index 80%
rename from apps/microtvm/arduino/template_project/src/example_project/model.c
rename to apps/microtvm/arduino/template_project/src/example_project/platform.c
index 46f43752ef..973b8aa18c 100644
--- a/apps/microtvm/arduino/template_project/src/example_project/model.c
+++ b/apps/microtvm/arduino/template_project/src/example_project/platform.c
@@ -17,17 +17,22 @@
* under the License.
*/
-#include "model.h"
+/*!
+ * \brief Implementation of TVMPlatform functions in tvm/runtime/crt/platform.h
+ */
#include "Arduino.h"
#include "standalone_crt/include/dlpack/dlpack.h"
#include "standalone_crt/include/tvm/runtime/crt/stack_allocator.h"
+#define TVM_WORKSPACE_SIZE_BYTES $workspace_size_bytes
+
// AOT memory array, stack allocator wants it aligned
-static uint8_t g_aot_memory[WORKSPACE_SIZE]
+static uint8_t g_aot_memory[TVM_WORKSPACE_SIZE_BYTES]
__attribute__((aligned(TVM_RUNTIME_ALLOC_ALIGNMENT_BYTES)));
tvm_workspace_t app_workspace;
+// Called when an internal error occurs and execution cannot continue.
// Blink code for debugging purposes
void TVMPlatformAbort(tvm_crt_error_t error) {
TVMLogf("TVMPlatformAbort: 0x%08x\n", error);
@@ -45,19 +50,23 @@ void TVMPlatformAbort(tvm_crt_error_t error) {
}
}
-void TVMLogf(const char* msg, ...) {}
-
+// Allocate memory for use by TVM.
tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLDevice dev,
void** out_ptr) {
return StackMemoryManager_Allocate(&app_workspace, num_bytes, out_ptr);
}
+// Free memory used by TVM.
tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice dev) {
return StackMemoryManager_Free(&app_workspace, ptr);
}
+// Internal logging API call implementation.
+void TVMLogf(const char* msg, ...) {}
+
unsigned long g_utvm_start_time_micros;
int g_utvm_timer_running = 0;
+// Start a device timer.
tvm_crt_error_t TVMPlatformTimerStart() {
if (g_utvm_timer_running) {
return kTvmErrorPlatformTimerBadState;
@@ -67,6 +76,7 @@ tvm_crt_error_t TVMPlatformTimerStart() {
return kTvmErrorNoError;
}
+// Stop the running device timer and get the elapsed time (in microseconds).
tvm_crt_error_t TVMPlatformTimerStop(double* elapsed_time_seconds) {
if (!g_utvm_timer_running) {
return kTvmErrorPlatformTimerBadState;
@@ -77,6 +87,7 @@ tvm_crt_error_t TVMPlatformTimerStop(double*
elapsed_time_seconds) {
return kTvmErrorNoError;
}
+// Fill a buffer with random data.
tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer, size_t num_bytes) {
for (size_t i = 0; i < num_bytes; i++) {
buffer[i] = rand();
@@ -84,7 +95,11 @@ tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer,
size_t num_bytes) {
return kTvmErrorNoError;
}
-void TVMInitialize() { StackMemoryManager_Init(&app_workspace, g_aot_memory,
WORKSPACE_SIZE); }
+// Initialize TVM inference.
+tvm_crt_error_t TVMPlatformInitialize() {
+ StackMemoryManager_Init(&app_workspace, g_aot_memory, sizeof(g_aot_memory));
+ return kTvmErrorNoError;
+}
void TVMExecute(void* input_data, void* output_data) {
int ret_val = tvmgen_default___tvm_main__(input_data, output_data);
diff --git a/apps/microtvm/arduino/template_project/src/example_project/model.h
b/apps/microtvm/arduino/template_project/src/example_project/platform.h
similarity index 94%
rename from apps/microtvm/arduino/template_project/src/example_project/model.h
rename to apps/microtvm/arduino/template_project/src/example_project/platform.h
index 7381c97e9b..d6f10e13e9 100644
--- a/apps/microtvm/arduino/template_project/src/example_project/model.h
+++ b/apps/microtvm/arduino/template_project/src/example_project/platform.h
@@ -17,14 +17,10 @@
* under the License.
*/
-#define WORKSPACE_SIZE $workspace_size_bytes
-
#ifdef __cplusplus
extern "C" {
#endif
-void TVMInitialize();
-
/* TODO template this function signature with the input and output
* data types and sizes. For example:
*
diff --git
a/apps/microtvm/arduino/template_project/src/example_project/project.ino
b/apps/microtvm/arduino/template_project/src/example_project/project.ino
index 5f5683161e..666396b407 100644
--- a/apps/microtvm/arduino/template_project/src/example_project/project.ino
+++ b/apps/microtvm/arduino/template_project/src/example_project/project.ino
@@ -17,10 +17,10 @@
* under the License.
*/
-#include "src/model.h"
+#include "src/standalone_crt/include/tvm/runtime/crt/platform.h"
void setup() {
- TVMInitialize();
+ TVMPlatformInitialize();
// If desired, initialize the RNG with random noise
// randomSeed(analogRead(0));
}
diff --git
a/apps/microtvm/arduino/template_project/src/host_driven/model_support.c
b/apps/microtvm/arduino/template_project/src/host_driven/platform.c
similarity index 85%
rename from
apps/microtvm/arduino/template_project/src/host_driven/model_support.c
rename to apps/microtvm/arduino/template_project/src/host_driven/platform.c
index bcc9a109ca..0a276134d4 100644
--- a/apps/microtvm/arduino/template_project/src/host_driven/model_support.c
+++ b/apps/microtvm/arduino/template_project/src/host_driven/platform.c
@@ -17,22 +17,28 @@
* under the License.
*/
+/*!
+ * \brief Implementation of TVMPlatform functions in tvm/runtime/crt/platform.h
+ */
+
#include "standalone_crt/include/dlpack/dlpack.h"
#include "standalone_crt/include/tvm/runtime/crt/error_codes.h"
#include "stdarg.h"
-// Blink code for debugging purposes
+// Called when an internal error occurs and execution cannot continue.
void TVMPlatformAbort(tvm_crt_error_t error) {
TVMLogf("TVMPlatformAbort: 0x%08x\n", error);
for (;;)
;
}
+// Called by the microTVM RPC server to implement TVMLogf.
size_t TVMPlatformFormatMessage(char* out_buf, size_t out_buf_size_bytes,
const char* fmt,
va_list args) {
return vsnprintf(out_buf, out_buf_size_bytes, fmt, args);
}
+// Allocate memory for use by TVM.
tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLDevice dev,
void** out_ptr) {
if (num_bytes == 0) {
num_bytes = sizeof(int);
@@ -41,6 +47,7 @@ tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes,
DLDevice dev, void**
return (*out_ptr == NULL) ? kTvmErrorPlatformNoMemory : kTvmErrorNoError;
}
+// Free memory used by TVM.
tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice dev) {
free(ptr);
return kTvmErrorNoError;
@@ -49,6 +56,7 @@ tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice
dev) {
unsigned long g_utvm_start_time_micros;
int g_utvm_timer_running = 0;
+// Start a device timer.
tvm_crt_error_t TVMPlatformTimerStart() {
if (g_utvm_timer_running) {
return kTvmErrorPlatformTimerBadState;
@@ -58,6 +66,7 @@ tvm_crt_error_t TVMPlatformTimerStart() {
return kTvmErrorNoError;
}
+// Stop the running device timer and get the elapsed time (in microseconds).
tvm_crt_error_t TVMPlatformTimerStop(double* elapsed_time_seconds) {
if (!g_utvm_timer_running) {
return kTvmErrorPlatformTimerBadState;
@@ -68,6 +77,7 @@ tvm_crt_error_t TVMPlatformTimerStop(double*
elapsed_time_seconds) {
return kTvmErrorNoError;
}
+// Fill a buffer with random data.
tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer, size_t num_bytes) {
for (size_t i = 0; i < num_bytes; i++) {
buffer[i] = rand();
diff --git a/apps/microtvm/zephyr/template_project/CMakeLists.txt.template
b/apps/microtvm/zephyr/template_project/CMakeLists.txt.template
index 1aff9ece6b..cec29e7248 100644
--- a/apps/microtvm/zephyr/template_project/CMakeLists.txt.template
+++ b/apps/microtvm/zephyr/template_project/CMakeLists.txt.template
@@ -83,4 +83,4 @@ endif()
file(GLOB_RECURSE app_srcs src/**.c src/**.cc)
target_sources(app PRIVATE ${app_srcs} ${cmsis_lib_srcs})
-target_include_directories(app PRIVATE crt_config ${CMAKE_SOURCE_DIR}/include
crt/include ${cmsis_includes})
+target_include_directories(app PRIVATE crt_config include
${CMAKE_SOURCE_DIR}/include crt/include ${cmsis_includes})
diff --git a/apps/microtvm/zephyr/template_project/microtvm_api_server.py
b/apps/microtvm/zephyr/template_project/microtvm_api_server.py
index 17dd991229..227b038944 100644
--- a/apps/microtvm/zephyr/template_project/microtvm_api_server.py
+++ b/apps/microtvm/zephyr/template_project/microtvm_api_server.py
@@ -210,14 +210,14 @@ def _get_board_mem_size_bytes(zephyr_base: str, board:
str):
return None
-DEFAULT_HEAP_SIZE_BYTES = 216 * 1024
+DEFAULT_WORKSPACE_SIZE_BYTES = 216 * 1024
def _get_recommended_heap_size_bytes(board: str):
prop = BOARD_PROPERTIES[board]
if "recommended_heap_size_bytes" in prop:
return prop["recommended_heap_size_bytes"]
- return DEFAULT_HEAP_SIZE_BYTES
+ return DEFAULT_WORKSPACE_SIZE_BYTES
def generic_find_serial_port(serial_number: str = None):
@@ -358,11 +358,11 @@ PROJECT_OPTIONS = server.default_project_options(
help="Run on the FVP emulator instead of hardware.",
),
server.ProjectOption(
- "heap_size_bytes",
+ "workspace_size_bytes",
optional=["generate_project"],
type="int",
default=None,
- help="Sets the value for HEAP_SIZE_BYTES passed to K_HEAP_DEFINE() to
service TVM memory allocation requests.",
+ help="Sets the value for TVM_WORKSPACE_SIZE_BYTES passed to
K_HEAP_DEFINE() to service TVM memory allocation requests.",
),
]
@@ -403,7 +403,13 @@ class Handler(server.ProjectAPIHandler):
}
def _create_prj_conf(
- self, project_dir: pathlib.Path, board: str, project_type: str,
config_main_stack_size
+ self,
+ project_dir: pathlib.Path,
+ board: str,
+ project_type: str,
+ config_main_stack_size: int,
+ config_led: bool,
+ use_fvp: bool,
):
with open(project_dir / "prj.conf", "w") as f:
f.write(
@@ -413,6 +419,13 @@ class Handler(server.ProjectAPIHandler):
"CONFIG_UART_INTERRUPT_DRIVEN=y\n"
"\n"
)
+ if (
+ config_led
+ and not self._is_qemu(board, use_fvp)
+ and not self._is_fvp(board, use_fvp)
+ ):
+ f.write("# For debugging.\n" "CONFIG_LED=y\n" "\n")
+
f.write("# For TVMPlatformAbort().\n" "CONFIG_REBOOT=y\n" "\n")
if project_type == "host_driven":
@@ -522,6 +535,18 @@ class Handler(server.ProjectAPIHandler):
return cmake_args
+ def _copy_src_and_header_files(self, src_dir: pathlib.Path, dst_dir:
pathlib.Path):
+ """Copy content of src_dir from template project to dst_dir in separate
+ source and header sub-directories.
+ """
+ for file in os.listdir(src_dir):
+ file = src_dir / file
+ if file.is_file():
+ if file.suffix in [".cc", ".c"]:
+ shutil.copy2(file, dst_dir / "src")
+ elif file.suffix in [".h"]:
+ shutil.copy2(file, dst_dir / "include" / "tvm")
+
def generate_project(self, model_library_format_path, standalone_crt_dir,
project_dir, options):
zephyr_board = options["board"]
project_type = options["project_type"]
@@ -533,7 +558,7 @@ class Handler(server.ProjectAPIHandler):
verbose = options.get("verbose")
recommended_heap_size = _get_recommended_heap_size_bytes(zephyr_board)
- heap_size_bytes = options.get("heap_size_bytes") or
recommended_heap_size
+ workspace_size_bytes = options.get("workspace_size_bytes") or
recommended_heap_size
board_mem_size = _get_board_mem_size_bytes(zephyr_base, zephyr_board)
compile_definitions = options.get("compile_definitions")
@@ -602,7 +627,7 @@ class Handler(server.ProjectAPIHandler):
else:
shutil.copy2(src_path, dst_path)
- # Populate Makefile.
+ # Populate CMakeLists.
with open(project_dir / CMAKELIST_FILENAME, "w") as cmake_f:
with open(API_SERVER_DIR / f"{CMAKELIST_FILENAME}.template", "r")
as cmake_template_f:
for line in cmake_template_f:
@@ -629,10 +654,10 @@ class Handler(server.ProjectAPIHandler):
if board_mem_size is not None:
assert (
- heap_size_bytes < board_mem_size
- ), f"Heap size {heap_size_bytes} is larger than memory
size {board_mem_size} on this board."
+ workspace_size_bytes < board_mem_size
+ ), f"Workspace size {workspace_size_bytes} is larger than
memory size {board_mem_size} on this board."
cmake_f.write(
- f"target_compile_definitions(app PUBLIC
-DHEAP_SIZE_BYTES={heap_size_bytes})\n"
+ f"target_compile_definitions(app PUBLIC
-DTVM_WORKSPACE_SIZE_BYTES={workspace_size_bytes})\n"
)
if compile_definitions:
@@ -649,7 +674,9 @@ class Handler(server.ProjectAPIHandler):
if self._is_fvp(zephyr_board, use_fvp):
cmake_f.write(f"target_compile_definitions(app PUBLIC
-DFVP=1)\n")
- self._create_prj_conf(project_dir, zephyr_board, project_type,
config_main_stack_size)
+ self._create_prj_conf(
+ project_dir, zephyr_board, project_type, config_main_stack_size,
verbose, use_fvp
+ )
# Populate crt-config.h
crt_config_dir = project_dir / "crt_config"
@@ -658,13 +685,19 @@ class Handler(server.ProjectAPIHandler):
API_SERVER_DIR / "crt_config" / "crt_config.h", crt_config_dir /
"crt_config.h"
)
- # Populate src/
+ # Populate `src` and `include`
src_dir = project_dir / "src"
- if project_type != "host_driven" or self._is_fvp(zephyr_board,
use_fvp):
- shutil.copytree(API_SERVER_DIR / "src" / project_type, src_dir)
- else:
- src_dir.mkdir()
- shutil.copy2(API_SERVER_DIR / "src" / project_type / "main.c",
src_dir)
+ src_dir.mkdir()
+ include_dir = project_dir / "include" / "tvm"
+ include_dir.mkdir(parents=True)
+ src_project_type_dir = API_SERVER_DIR / "src" / project_type
+ self._copy_src_and_header_files(src_project_type_dir, project_dir)
+
+ if self._is_fvp(zephyr_board, use_fvp):
+ self._copy_src_and_header_files(src_project_type_dir / "fvp",
project_dir)
+
+ if project_type == "mlperftiny":
+ shutil.copytree(src_project_type_dir / "api", src_dir / "api")
# Populate extra_files
if extra_files_tar:
diff --git
a/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/main.c
b/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/main.c
index 9ba521ae17..fff8f57875 100644
--- a/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/main.c
+++ b/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/main.c
@@ -25,23 +25,18 @@
#include <tvm/runtime/crt/logging.h>
#include <tvm/runtime/crt/stack_allocator.h>
#include <unistd.h>
+#include <zephyr/drivers/uart.h>
#include <zephyr/kernel.h>
-#include <zephyr/sys/reboot.h>
+#include <zephyr/sys/ring_buffer.h>
-#include "input_data.h"
-#include "output_data.h"
+#include "tvm/input_data.h"
+#include "tvm/output_data.h"
#include "tvmgen_default.h"
-#include "zephyr_uart.h"
#ifdef CONFIG_ARCH_POSIX
#include "posix_board_if.h"
#endif
-// WORKSPACE_SIZE defined in Project API Makefile
-
-static uint8_t g_aot_memory[WORKSPACE_SIZE];
-tvm_workspace_t app_workspace;
-
// Transport Commands.
// Commands on host end with `\n`
// Commands on microTVM device end with `%`
@@ -53,126 +48,84 @@ const unsigned char CMD_INFER[] = "infer";
#define CMD_SIZE 80u
#define CMD_TERMINATOR '%'
-size_t TVMPlatformFormatMessage(char* out_buf, size_t out_buf_size_bytes,
const char* fmt,
- va_list args) {
- return vsnprintk(out_buf, out_buf_size_bytes, fmt, args);
-}
+static uint8_t main_rx_buf[128];
+static uint8_t g_cmd_buf[128];
+static size_t g_cmd_buf_ind;
-void TVMLogf(const char* msg, ...) {
- char buffer[256];
- int size;
- va_list args;
- va_start(args, msg);
- size = vsprintf(buffer, msg, args);
- va_end(args);
- TVMPlatformWriteSerial(buffer, (uint32_t)size);
-}
+static const struct device* g_microtvm_uart;
+#define RING_BUF_SIZE_BYTES (TVM_CRT_MAX_PACKET_SIZE_BYTES + 100)
-void TVMPlatformAbort(tvm_crt_error_t error) {
- TVMLogf("TVMPlatformAbort: %08x\n", error);
- sys_reboot(SYS_REBOOT_COLD);
- for (;;)
- ;
-}
+// Ring buffer used to store data read from the UART on rx interrupt.
+RING_BUF_DECLARE(uart_rx_rbuf, RING_BUF_SIZE_BYTES);
-tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLDevice dev,
void** out_ptr) {
- return StackMemoryManager_Allocate(&app_workspace, num_bytes, out_ptr);
+uint32_t UartTxWrite(const char* data, uint32_t size) {
+ for (uint32_t i = 0; i < size; i++) {
+ uart_poll_out(g_microtvm_uart, data[i]);
+ }
+ return size;
}
-tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice dev) {
- return StackMemoryManager_Free(&app_workspace, ptr);
+uint32_t UartRxRead(uint8_t* data, uint32_t data_size_bytes) {
+ unsigned int key = irq_lock();
+ uint32_t bytes_read = ring_buf_get(&uart_rx_rbuf, data, data_size_bytes);
+ irq_unlock(key);
+ return bytes_read;
}
-void timer_expiry_function(struct k_timer* timer_id) { return; }
-
-#define MILLIS_TIL_EXPIRY 200
-#define TIME_TIL_EXPIRY (K_MSEC(MILLIS_TIL_EXPIRY))
-struct k_timer g_microtvm_timer;
-uint32_t g_microtvm_start_time;
-int g_microtvm_timer_running = 0;
-
-// Called to start system timer.
-tvm_crt_error_t TVMPlatformTimerStart() {
- if (g_microtvm_timer_running) {
- TVMLogf("timer already running");
- return kTvmErrorPlatformTimerBadState;
- }
-
- k_timer_start(&g_microtvm_timer, TIME_TIL_EXPIRY, TIME_TIL_EXPIRY);
- g_microtvm_start_time = k_cycle_get_32();
- g_microtvm_timer_running = 1;
- return kTvmErrorNoError;
+// Initialize UART
+void UartInit() {
+ // Claim console device.
+ g_microtvm_uart = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
+ const struct uart_config config = {.baudrate = 115200,
+ .parity = UART_CFG_PARITY_NONE,
+ .stop_bits = UART_CFG_STOP_BITS_1,
+ .data_bits = UART_CFG_DATA_BITS_8,
+ .flow_ctrl = UART_CFG_FLOW_CTRL_NONE};
+ uart_configure(g_microtvm_uart, &config);
+ uart_rx_init(&uart_rx_rbuf, g_microtvm_uart);
}
-// Called to stop system timer.
-tvm_crt_error_t TVMPlatformTimerStop(double* elapsed_time_seconds) {
- if (!g_microtvm_timer_running) {
- TVMLogf("timer not running");
- return kTvmErrorSystemErrorMask | 2;
- }
-
- uint32_t stop_time = k_cycle_get_32();
-
- // compute how long the work took
- uint32_t cycles_spent = stop_time - g_microtvm_start_time;
- if (stop_time < g_microtvm_start_time) {
- // we rolled over *at least* once, so correct the rollover it was *only*
- // once, because we might still use this result
- cycles_spent = ~((uint32_t)0) - (g_microtvm_start_time - stop_time);
- }
-
- uint32_t ns_spent = (uint32_t)k_cyc_to_ns_floor64(cycles_spent);
- double hw_clock_res_us = ns_spent / 1000.0;
-
- // need to grab time remaining *before* stopping. when stopped, this function
- // always returns 0.
- int32_t time_remaining_ms = k_timer_remaining_get(&g_microtvm_timer);
- k_timer_stop(&g_microtvm_timer);
- // check *after* stopping to prevent extra expiries on the happy path
- if (time_remaining_ms < 0) {
- return kTvmErrorSystemErrorMask | 3;
- }
- uint32_t num_expiries = k_timer_status_get(&g_microtvm_timer);
- uint32_t timer_res_ms = ((num_expiries * MILLIS_TIL_EXPIRY) +
time_remaining_ms);
- double approx_num_cycles =
- (double)k_ticks_to_cyc_floor32(1) *
(double)k_ms_to_ticks_ceil32(timer_res_ms);
- // if we approach the limits of the HW clock datatype (uint32_t), use the
- // coarse-grained timer result instead
- if (approx_num_cycles > (0.5 * (~((uint32_t)0)))) {
- *elapsed_time_seconds = timer_res_ms / 1000.0;
- } else {
- *elapsed_time_seconds = hw_clock_res_us / 1e6;
+static uint8_t uart_data[8];
+// UART interrupt callback.
+void uart_irq_cb(const struct device* dev, void* user_data) {
+ while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
+ struct ring_buf* rbuf = (struct ring_buf*)user_data;
+ if (uart_irq_rx_ready(dev) != 0) {
+ for (;;) {
+ // Read a small chunk of data from the UART.
+ int bytes_read = uart_fifo_read(dev, uart_data, sizeof(uart_data));
+ if (bytes_read < 0) {
+ TVMPlatformAbort((tvm_crt_error_t)(0xbeef1));
+ } else if (bytes_read == 0) {
+ break;
+ }
+ // Write it into the ring buffer.
+ int bytes_written = ring_buf_put(rbuf, uart_data, bytes_read);
+ if (bytes_read != bytes_written) {
+ TVMPlatformAbort((tvm_crt_error_t)(0xbeef2));
+ }
+ }
+ }
}
-
- g_microtvm_timer_running = 0;
- return kTvmErrorNoError;
}
-void* TVMBackendAllocWorkspace(int device_type, int device_id, uint64_t
nbytes, int dtype_code_hint,
- int dtype_bits_hint) {
- tvm_crt_error_t err = kTvmErrorNoError;
- void* ptr = 0;
- DLDevice dev = {device_type, device_id};
- assert(nbytes > 0);
- err = TVMPlatformMemoryAllocate(nbytes, dev, &ptr);
- CHECK_EQ(err, kTvmErrorNoError,
- "TVMBackendAllocWorkspace(%d, %d, %" PRIu64 ", %d, %d) -> %"
PRId32, device_type,
- device_id, nbytes, dtype_code_hint, dtype_bits_hint, err);
- return ptr;
+// Used to initialize the UART receiver.
+void uart_rx_init(struct ring_buf* rbuf, const struct device* dev) {
+ uart_irq_callback_user_data_set(dev, uart_irq_cb, (void*)rbuf);
+ uart_irq_rx_enable(dev);
}
-int TVMBackendFreeWorkspace(int device_type, int device_id, void* ptr) {
- tvm_crt_error_t err = kTvmErrorNoError;
- DLDevice dev = {device_type, device_id};
- err = TVMPlatformMemoryFree(ptr, dev);
- return err;
+void TVMLogf(const char* msg, ...) {
+ char buffer[256];
+ int size;
+ va_list args;
+ va_start(args, msg);
+ size = vsprintf(buffer, msg, args);
+ va_end(args);
+ UartTxWrite(buffer, (uint32_t)size);
}
-static uint8_t main_rx_buf[128];
-static uint8_t g_cmd_buf[128];
-static size_t g_cmd_buf_ind;
-
-void TVMInfer() {
+void Infer() {
struct tvmgen_default_inputs inputs = {
.input_1 = input_data,
};
@@ -180,8 +133,6 @@ void TVMInfer() {
.Identity = output_data,
};
- StackMemoryManager_Init(&app_workspace, g_aot_memory, WORKSPACE_SIZE);
-
double elapsed_time = 0;
TVMPlatformTimerStart();
int ret_val = tvmgen_default_run(&inputs, &outputs);
@@ -206,11 +157,11 @@ void TVMInfer() {
// Execute functions based on received command
void command_ready(char* command) {
if (strncmp(command, CMD_INIT, CMD_SIZE) == 0) {
- TVMPlatformWriteSerial(CMD_WAKEUP, sizeof(CMD_WAKEUP));
+ UartTxWrite(CMD_WAKEUP, sizeof(CMD_WAKEUP));
} else if (strncmp(command, CMD_INFER, CMD_SIZE) == 0) {
- TVMInfer();
+ Infer();
} else {
- TVMPlatformWriteSerial(CMD_READY, sizeof(CMD_READY));
+ UartTxWrite(CMD_READY, sizeof(CMD_READY));
}
}
@@ -229,13 +180,13 @@ void serial_callback(char* message, int len_bytes) {
}
void main(void) {
+ TVMPlatformInitialize();
+ UartInit();
g_cmd_buf_ind = 0;
memset((char*)g_cmd_buf, 0, sizeof(g_cmd_buf));
- TVMPlatformUARTInit();
- k_timer_init(&g_microtvm_timer, NULL, NULL);
while (true) {
- int bytes_read = TVMPlatformUartRxRead(main_rx_buf, sizeof(main_rx_buf));
+ int bytes_read = UartRxRead(main_rx_buf, sizeof(main_rx_buf));
if (bytes_read > 0) {
serial_callback(main_rx_buf, bytes_read);
}
diff --git
a/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/main.c
b/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/platform.c
similarity index 50%
copy from apps/microtvm/zephyr/template_project/src/aot_standalone_demo/main.c
copy to apps/microtvm/zephyr/template_project/src/aot_standalone_demo/platform.c
index 9ba521ae17..c66dad5711 100644
--- a/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/main.c
+++ b/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/platform.c
@@ -17,57 +17,38 @@
* under the License.
*/
-#include <assert.h>
-#include <float.h>
+/*!
+ * \brief Implementation of TVMPlatform functions in tvm/runtime/crt/platform.h
+ */
+
+#include <stdarg.h>
+#include <stdint.h>
#include <stdio.h>
-#include <string.h>
-#include <tvm/runtime/c_runtime_api.h>
-#include <tvm/runtime/crt/logging.h>
+#include <stdlib.h>
+#include <tvm/runtime/crt/error_codes.h>
#include <tvm/runtime/crt/stack_allocator.h>
-#include <unistd.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/reboot.h>
-#include "input_data.h"
-#include "output_data.h"
+#include "crt_config.h"
+#include "dlpack/dlpack.h"
#include "tvmgen_default.h"
-#include "zephyr_uart.h"
-
-#ifdef CONFIG_ARCH_POSIX
-#include "posix_board_if.h"
-#endif
-// WORKSPACE_SIZE defined in Project API Makefile
-
-static uint8_t g_aot_memory[WORKSPACE_SIZE];
+// TVM_WORKSPACE_SIZE_BYTES defined in Project API Makefile
+static uint8_t g_aot_memory[TVM_WORKSPACE_SIZE_BYTES];
tvm_workspace_t app_workspace;
-// Transport Commands.
-// Commands on host end with `\n`
-// Commands on microTVM device end with `%`
-const unsigned char CMD_WAKEUP[] = "wakeup\n";
-const unsigned char CMD_READY[] = "ready\n";
-const unsigned char CMD_INIT[] = "init";
-const unsigned char CMD_INFER[] = "infer";
-
-#define CMD_SIZE 80u
-#define CMD_TERMINATOR '%'
+#define MILLIS_TIL_EXPIRY 200
+#define TIME_TIL_EXPIRY (K_MSEC(MILLIS_TIL_EXPIRY))
+struct k_timer g_microtvm_timer;
+uint32_t g_microtvm_start_time;
+int g_microtvm_timer_running = 0;
size_t TVMPlatformFormatMessage(char* out_buf, size_t out_buf_size_bytes,
const char* fmt,
va_list args) {
return vsnprintk(out_buf, out_buf_size_bytes, fmt, args);
}
-void TVMLogf(const char* msg, ...) {
- char buffer[256];
- int size;
- va_list args;
- va_start(args, msg);
- size = vsprintf(buffer, msg, args);
- va_end(args);
- TVMPlatformWriteSerial(buffer, (uint32_t)size);
-}
-
void TVMPlatformAbort(tvm_crt_error_t error) {
TVMLogf("TVMPlatformAbort: %08x\n", error);
sys_reboot(SYS_REBOOT_COLD);
@@ -83,15 +64,12 @@ tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice
dev) {
return StackMemoryManager_Free(&app_workspace, ptr);
}
-void timer_expiry_function(struct k_timer* timer_id) { return; }
-
-#define MILLIS_TIL_EXPIRY 200
-#define TIME_TIL_EXPIRY (K_MSEC(MILLIS_TIL_EXPIRY))
-struct k_timer g_microtvm_timer;
-uint32_t g_microtvm_start_time;
-int g_microtvm_timer_running = 0;
+tvm_crt_error_t TVMPlatformInitialize() {
+ k_timer_init(&g_microtvm_timer, NULL, NULL);
+ StackMemoryManager_Init(&app_workspace, g_aot_memory, sizeof(g_aot_memory));
+ return kTvmErrorNoError;
+}
-// Called to start system timer.
tvm_crt_error_t TVMPlatformTimerStart() {
if (g_microtvm_timer_running) {
TVMLogf("timer already running");
@@ -104,7 +82,6 @@ tvm_crt_error_t TVMPlatformTimerStart() {
return kTvmErrorNoError;
}
-// Called to stop system timer.
tvm_crt_error_t TVMPlatformTimerStop(double* elapsed_time_seconds) {
if (!g_microtvm_timer_running) {
TVMLogf("timer not running");
@@ -147,101 +124,3 @@ tvm_crt_error_t TVMPlatformTimerStop(double*
elapsed_time_seconds) {
g_microtvm_timer_running = 0;
return kTvmErrorNoError;
}
-
-void* TVMBackendAllocWorkspace(int device_type, int device_id, uint64_t
nbytes, int dtype_code_hint,
- int dtype_bits_hint) {
- tvm_crt_error_t err = kTvmErrorNoError;
- void* ptr = 0;
- DLDevice dev = {device_type, device_id};
- assert(nbytes > 0);
- err = TVMPlatformMemoryAllocate(nbytes, dev, &ptr);
- CHECK_EQ(err, kTvmErrorNoError,
- "TVMBackendAllocWorkspace(%d, %d, %" PRIu64 ", %d, %d) -> %"
PRId32, device_type,
- device_id, nbytes, dtype_code_hint, dtype_bits_hint, err);
- return ptr;
-}
-
-int TVMBackendFreeWorkspace(int device_type, int device_id, void* ptr) {
- tvm_crt_error_t err = kTvmErrorNoError;
- DLDevice dev = {device_type, device_id};
- err = TVMPlatformMemoryFree(ptr, dev);
- return err;
-}
-
-static uint8_t main_rx_buf[128];
-static uint8_t g_cmd_buf[128];
-static size_t g_cmd_buf_ind;
-
-void TVMInfer() {
- struct tvmgen_default_inputs inputs = {
- .input_1 = input_data,
- };
- struct tvmgen_default_outputs outputs = {
- .Identity = output_data,
- };
-
- StackMemoryManager_Init(&app_workspace, g_aot_memory, WORKSPACE_SIZE);
-
- double elapsed_time = 0;
- TVMPlatformTimerStart();
- int ret_val = tvmgen_default_run(&inputs, &outputs);
- TVMPlatformTimerStop(&elapsed_time);
-
- if (ret_val != 0) {
- TVMLogf("Error: %d\n", ret_val);
- TVMPlatformAbort(kTvmErrorPlatformCheckFailure);
- }
-
- size_t max_ind = -1;
- float max_val = -FLT_MAX;
- for (size_t i = 0; i < output_data_len; i++) {
- if (output_data[i] >= max_val) {
- max_ind = i;
- max_val = output_data[i];
- }
- }
- TVMLogf("result:%d:%d\n", max_ind, (uint32_t)(elapsed_time * 1000));
-}
-
-// Execute functions based on received command
-void command_ready(char* command) {
- if (strncmp(command, CMD_INIT, CMD_SIZE) == 0) {
- TVMPlatformWriteSerial(CMD_WAKEUP, sizeof(CMD_WAKEUP));
- } else if (strncmp(command, CMD_INFER, CMD_SIZE) == 0) {
- TVMInfer();
- } else {
- TVMPlatformWriteSerial(CMD_READY, sizeof(CMD_READY));
- }
-}
-
-// Append received characters to buffer and check for termination character.
-void serial_callback(char* message, int len_bytes) {
- for (int i = 0; i < len_bytes; i++) {
- if (message[i] == CMD_TERMINATOR) {
- g_cmd_buf[g_cmd_buf_ind] = (char)0;
- command_ready(g_cmd_buf);
- g_cmd_buf_ind = 0;
- } else {
- g_cmd_buf[g_cmd_buf_ind] = message[i];
- g_cmd_buf_ind += 1;
- }
- }
-}
-
-void main(void) {
- g_cmd_buf_ind = 0;
- memset((char*)g_cmd_buf, 0, sizeof(g_cmd_buf));
- TVMPlatformUARTInit();
- k_timer_init(&g_microtvm_timer, NULL, NULL);
-
- while (true) {
- int bytes_read = TVMPlatformUartRxRead(main_rx_buf, sizeof(main_rx_buf));
- if (bytes_read > 0) {
- serial_callback(main_rx_buf, bytes_read);
- }
- }
-
-#ifdef CONFIG_ARCH_POSIX
- posix_exit(0);
-#endif
-}
diff --git
a/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/zephyr_uart.c
b/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/zephyr_uart.c
deleted file mode 100644
index 8d5f912081..0000000000
---
a/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/zephyr_uart.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-#include "zephyr_uart.h"
-
-#include <zephyr/drivers/uart.h>
-#include <zephyr/sys/ring_buffer.h>
-
-#include "crt_config.h"
-
-static const struct device* g_microtvm_uart;
-#define RING_BUF_SIZE_BYTES (TVM_CRT_MAX_PACKET_SIZE_BYTES + 100)
-
-// Ring buffer used to store data read from the UART on rx interrupt.
-RING_BUF_DECLARE(uart_rx_rbuf, RING_BUF_SIZE_BYTES);
-
-static uint8_t uart_data[8];
-// UART interrupt callback.
-void uart_irq_cb(const struct device* dev, void* user_data) {
- while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
- struct ring_buf* rbuf = (struct ring_buf*)user_data;
- if (uart_irq_rx_ready(dev) != 0) {
- for (;;) {
- // Read a small chunk of data from the UART.
- int bytes_read = uart_fifo_read(dev, uart_data, sizeof(uart_data));
- if (bytes_read < 0) {
- TVMPlatformAbort((tvm_crt_error_t)(0xbeef1));
- } else if (bytes_read == 0) {
- break;
- }
- // Write it into the ring buffer.
- int bytes_written = ring_buf_put(rbuf, uart_data, bytes_read);
- if (bytes_read != bytes_written) {
- TVMPlatformAbort((tvm_crt_error_t)(0xbeef2));
- }
- }
- }
- }
-}
-
-// Used to initialize the UART receiver.
-void uart_rx_init(struct ring_buf* rbuf, const struct device* dev) {
- uart_irq_callback_user_data_set(dev, uart_irq_cb, (void*)rbuf);
- uart_irq_rx_enable(dev);
-}
-
-uint32_t TVMPlatformUartRxRead(uint8_t* data, uint32_t data_size_bytes) {
- unsigned int key = irq_lock();
- uint32_t bytes_read = ring_buf_get(&uart_rx_rbuf, data, data_size_bytes);
- irq_unlock(key);
- return bytes_read;
-}
-
-uint32_t TVMPlatformWriteSerial(const char* data, uint32_t size) {
- for (uint32_t i = 0; i < size; i++) {
- uart_poll_out(g_microtvm_uart, data[i]);
- }
- return size;
-}
-
-// Initialize UART
-void TVMPlatformUARTInit() {
- // Claim console device.
- g_microtvm_uart = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
- const struct uart_config config = {.baudrate = 115200,
- .parity = UART_CFG_PARITY_NONE,
- .stop_bits = UART_CFG_STOP_BITS_1,
- .data_bits = UART_CFG_DATA_BITS_8,
- .flow_ctrl = UART_CFG_FLOW_CTRL_NONE};
- uart_configure(g_microtvm_uart, &config);
- uart_rx_init(&uart_rx_rbuf, g_microtvm_uart);
-}
diff --git
a/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/zephyr_uart.h
b/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/zephyr_uart.h
deleted file mode 100644
index 771cb490d0..0000000000
---
a/apps/microtvm/zephyr/template_project/src/aot_standalone_demo/zephyr_uart.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef TVM_APPS_MICROTVM_ZEPHYR_AOT_STANDALONE_DEMO_ZEPHYR_UART_H_
-#define TVM_APPS_MICROTVM_ZEPHYR_AOT_STANDALONE_DEMO_ZEPHYR_UART_H_
-
-#include <stdint.h>
-
-// Used to read data from the UART.
-
-/*!
- * \brief Read Uart Rx buffer.
- * \param data Pointer to read data.
- * \param data_size_bytes Read request size in bytes.
- *
- * \return Number of data read in bytes.
- */
-uint32_t TVMPlatformUartRxRead(uint8_t* data, uint32_t data_size_bytes);
-
-/*!
- * \brief Write data in serial.
- * \param data Pointer to data to write.
- * \param size Size of data in bytes.
- *
- * \return Number of write in bytes.
- */
-uint32_t TVMPlatformWriteSerial(const char* data, uint32_t size);
-
-/*!
- * \brief Initialize Uart.
- */
-void TVMPlatformUARTInit();
-
-#endif /* TVM_APPS_MICROTVM_ZEPHYR_AOT_STANDALONE_DEMO_ZEPHYR_UART_H_ */
diff --git
a/apps/microtvm/zephyr/template_project/src/host_driven/fvp/semihost.c
b/apps/microtvm/zephyr/template_project/src/host_driven/fvp/semihost.c
index 2e03df0963..f51aa47c9f 100644
--- a/apps/microtvm/zephyr/template_project/src/host_driven/fvp/semihost.c
+++ b/apps/microtvm/zephyr/template_project/src/host_driven/fvp/semihost.c
@@ -22,7 +22,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
-#include "semihost.h"
+#include "tvm/semihost.h"
int32_t stdout_fd;
int32_t stdin_fd;
diff --git a/apps/microtvm/zephyr/template_project/src/host_driven/main.c
b/apps/microtvm/zephyr/template_project/src/host_driven/main.c
index c01daab6d0..1c63474817 100644
--- a/apps/microtvm/zephyr/template_project/src/host_driven/main.c
+++ b/apps/microtvm/zephyr/template_project/src/host_driven/main.c
@@ -29,7 +29,6 @@
* this logic into your own application.
*/
#include <stdio.h>
-#include <string.h>
#include <tvm/runtime/crt/logging.h>
#include <tvm/runtime/crt/microtvm_rpc_server.h>
#include <unistd.h>
@@ -37,15 +36,7 @@
#include <zephyr/drivers/uart.h>
#include <zephyr/fatal.h>
#include <zephyr/kernel.h>
-#include <zephyr/random/rand32.h>
-#include <zephyr/sys/printk.h>
-#include <zephyr/sys/reboot.h>
#include <zephyr/sys/ring_buffer.h>
-#include <zephyr/timing/timing.h>
-
-#ifdef FVP
-#include "fvp/semihost.h"
-#endif
#ifdef CONFIG_ARCH_POSIX
#include "posix_board_if.h"
@@ -53,15 +44,11 @@
#include "crt_config.h"
-static const struct device* tvm_uart;
+#ifdef FVP
+#include "tvm/semihost.h"
+#endif
-#ifdef CONFIG_LED
-#define LED0_NODE DT_ALIAS(led0)
-#define LED0 DT_GPIO_LABEL(LED0_NODE, gpios)
-#define LED0_PIN DT_GPIO_PIN(LED0_NODE, gpios)
-#define LED0_FLAGS DT_GPIO_FLAGS(LED0_NODE, gpios)
-static const struct device* led0_pin;
-#endif // CONFIG_LED
+static const struct device* tvm_uart;
static size_t g_num_bytes_requested = 0;
static size_t g_num_bytes_written = 0;
@@ -69,20 +56,11 @@ static size_t g_num_bytes_in_rx_buffer = 0;
// Called by TVM to write serial data to the UART.
ssize_t uart_write(void* unused_context, const uint8_t* data, size_t size) {
-#ifdef CONFIG_LED
- gpio_pin_set(led0_pin, LED0_PIN, 1);
-#endif
g_num_bytes_requested += size;
-
for (size_t i = 0; i < size; i++) {
uart_poll_out(tvm_uart, data[i]);
g_num_bytes_written++;
}
-
-#ifdef CONFIG_LED
- gpio_pin_set(led0_pin, LED0_PIN, 0);
-#endif
-
return size;
}
@@ -94,105 +72,6 @@ ssize_t serial_write(void* unused_context, const uint8_t*
data, size_t size) {
#endif
}
-// This is invoked by Zephyr from an exception handler, which will be invoked
-// if the device crashes. Here, we turn on the LED and spin.
-void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t* esf) {
-#ifdef CONFIG_LED
- gpio_pin_set(led0_pin, LED0_PIN, 1);
-#endif
- for (;;)
- ;
-}
-
-// Called by TVM when a message needs to be formatted.
-size_t TVMPlatformFormatMessage(char* out_buf, size_t out_buf_size_bytes,
const char* fmt,
- va_list args) {
- return vsnprintk(out_buf, out_buf_size_bytes, fmt, args);
-}
-
-// Called by TVM when an internal invariant is violated, and execution cannot
continue.
-void TVMPlatformAbort(tvm_crt_error_t error) {
- TVMLogf("TVMError: 0x%x", error);
- sys_reboot(SYS_REBOOT_COLD);
-#ifdef CONFIG_LED
- gpio_pin_set(led0_pin, LED0_PIN, 1);
-#endif
- for (;;)
- ;
-}
-
-// Called by TVM to generate random data.
-tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer, size_t num_bytes) {
- uint32_t random; // one unit of random data.
-
- // Fill parts of `buffer` which are as large as `random`.
- size_t num_full_blocks = num_bytes / sizeof(random);
- for (int i = 0; i < num_full_blocks; ++i) {
- random = sys_rand32_get();
- memcpy(&buffer[i * sizeof(random)], &random, sizeof(random));
- }
-
- // Fill any leftover tail which is smaller than `random`.
- size_t num_tail_bytes = num_bytes % sizeof(random);
- if (num_tail_bytes > 0) {
- random = sys_rand32_get();
- memcpy(&buffer[num_bytes - num_tail_bytes], &random, num_tail_bytes);
- }
- return kTvmErrorNoError;
-}
-
-// Heap for use by TVMPlatformMemoryAllocate.
-K_HEAP_DEFINE(tvm_heap, HEAP_SIZE_BYTES);
-
-// Called by TVM to allocate memory.
-tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLDevice dev,
void** out_ptr) {
- *out_ptr = k_heap_alloc(&tvm_heap, num_bytes, K_NO_WAIT);
- return (*out_ptr == NULL) ? kTvmErrorPlatformNoMemory : kTvmErrorNoError;
-}
-
-// Called by TVM to deallocate memory.
-tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice dev) {
- k_heap_free(&tvm_heap, ptr);
- return kTvmErrorNoError;
-}
-
-volatile timing_t g_microtvm_start_time, g_microtvm_end_time;
-int g_microtvm_timer_running = 0;
-
-// Called to start system timer.
-tvm_crt_error_t TVMPlatformTimerStart() {
- if (g_microtvm_timer_running) {
- TVMLogf("timer already running");
- return kTvmErrorPlatformTimerBadState;
- }
-
-#ifdef CONFIG_LED
- gpio_pin_set(led0_pin, LED0_PIN, 1);
-#endif
- g_microtvm_start_time = timing_counter_get();
- g_microtvm_timer_running = 1;
- return kTvmErrorNoError;
-}
-
-// Called to stop system timer.
-tvm_crt_error_t TVMPlatformTimerStop(double* elapsed_time_seconds) {
- if (!g_microtvm_timer_running) {
- TVMLogf("timer not running");
- return kTvmErrorSystemErrorMask | 2;
- }
-
-#ifdef CONFIG_LED
- gpio_pin_set(led0_pin, LED0_PIN, 0);
-#endif
-
- g_microtvm_end_time = timing_counter_get();
- uint64_t cycles = timing_cycles_get(&g_microtvm_start_time,
&g_microtvm_end_time);
- uint64_t ns_spent = timing_cycles_to_ns(cycles);
- *elapsed_time_seconds = ns_spent / (double)1e9;
- g_microtvm_timer_running = 0;
- return kTvmErrorNoError;
-}
-
// Ring buffer used to store data read from the UART on rx interrupt.
// This ring buffer size is only required for testing with QEMU and not for
physical hardware.
#define RING_BUF_SIZE_BYTES (TVM_CRT_MAX_PACKET_SIZE_BYTES + 100)
@@ -223,8 +102,6 @@ void uart_irq_cb(const struct device* dev, void* user_data)
{
if (err != 0) {
TVMPlatformAbort((tvm_crt_error_t)0xbeef2);
}
- // CHECK_EQ(bytes_read, bytes_written, "bytes_read: %d; bytes_written:
%d", bytes_read,
- // bytes_written);
}
}
}
@@ -238,29 +115,12 @@ void uart_rx_init(struct ring_buf* rbuf, const struct
device* dev) {
// The main function of this application.
extern void __stdout_hook_install(int (*hook)(int));
void main(void) {
-#ifdef CONFIG_LED
- int ret;
- led0_pin = device_get_binding(LED0);
- if (led0_pin == NULL) {
- for (;;)
- ;
- }
- ret = gpio_pin_configure(led0_pin, LED0_PIN, GPIO_OUTPUT_ACTIVE |
LED0_FLAGS);
- if (ret < 0) {
- TVMPlatformAbort((tvm_crt_error_t)0xbeef4);
- }
- gpio_pin_set(led0_pin, LED0_PIN, 1);
-#endif
+ TVMPlatformInitialize();
// Claim console device.
tvm_uart = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
uart_rx_init(&uart_rx_rbuf, tvm_uart);
- // Initialize system timing. We could stop and start it every time, but we'll
- // be using it enough we should just keep it enabled.
- timing_init();
- timing_start();
-
#ifdef FVP
init_semihosting();
// send some dummy log to speed up the initialization
@@ -274,10 +134,6 @@ void main(void) {
microtvm_rpc_server_t server = MicroTVMRpcServerInit(serial_write, NULL);
TVMLogf("microTVM Zephyr runtime - running");
-#ifdef CONFIG_LED
- gpio_pin_set(led0_pin, LED0_PIN, 0);
-#endif
-
// The main application loop. We continuously read commands from the UART
// and dispatch them to MicroTVMRpcServerLoop().
while (true) {
diff --git a/apps/microtvm/zephyr/template_project/src/host_driven/platform.c
b/apps/microtvm/zephyr/template_project/src/host_driven/platform.c
new file mode 100644
index 0000000000..8aa9abf235
--- /dev/null
+++ b/apps/microtvm/zephyr/template_project/src/host_driven/platform.c
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \brief Implementation of TVMPlatform functions in tvm/runtime/crt/platform.h
+ */
+
+#include <dlpack/dlpack.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tvm/runtime/crt/error_codes.h>
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/kernel.h>
+#include <zephyr/random/rand32.h>
+#include <zephyr/sys/printk.h>
+#include <zephyr/sys/reboot.h>
+#include <zephyr/timing/timing.h>
+
+K_HEAP_DEFINE(tvm_heap, TVM_WORKSPACE_SIZE_BYTES);
+
+volatile timing_t g_microtvm_start_time, g_microtvm_end_time;
+int g_microtvm_timer_running = 0;
+
+#ifdef CONFIG_LED
+#define LED0_NODE DT_ALIAS(led0)
+static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
+#endif // CONFIG_LED
+
+// This is invoked by Zephyr from an exception handler, which will be invoked
+// if the device crashes. Here, we turn on the LED and spin.
+void k_sys_fatal_error_handler(unsigned int reason, const z_arch_esf_t* esf) {
+#ifdef CONFIG_LED
+ gpio_pin_set_dt(&led0, 1);
+#endif
+ for (;;)
+ ;
+}
+
+void TVMPlatformAbort(tvm_crt_error_t error) {
+ TVMLogf("TVMError: 0x%x", error);
+ sys_reboot(SYS_REBOOT_COLD);
+#ifdef CONFIG_LED
+ gpio_pin_set_dt(&led0, 1);
+#endif
+ for (;;)
+ ;
+}
+
+size_t TVMPlatformFormatMessage(char* out_buf, size_t out_buf_size_bytes,
const char* fmt,
+ va_list args) {
+ return vsnprintk(out_buf, out_buf_size_bytes, fmt, args);
+}
+
+tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLDevice dev,
void** out_ptr) {
+ *out_ptr = k_heap_alloc(&tvm_heap, num_bytes, K_NO_WAIT);
+ return (*out_ptr == NULL) ? kTvmErrorPlatformNoMemory : kTvmErrorNoError;
+}
+
+tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice dev) {
+ k_heap_free(&tvm_heap, ptr);
+ return kTvmErrorNoError;
+}
+
+// Called to start system timer.
+tvm_crt_error_t TVMPlatformTimerStart() {
+ if (g_microtvm_timer_running) {
+ TVMLogf("timer already running");
+ return kTvmErrorPlatformTimerBadState;
+ }
+
+#ifdef CONFIG_LED
+ gpio_pin_set_dt(&led0, 1);
+#endif
+ g_microtvm_start_time = timing_counter_get();
+ g_microtvm_timer_running = 1;
+ return kTvmErrorNoError;
+}
+
+// Called to stop system timer.
+tvm_crt_error_t TVMPlatformTimerStop(double* elapsed_time_seconds) {
+ if (!g_microtvm_timer_running) {
+ TVMLogf("timer not running");
+ return kTvmErrorSystemErrorMask | 2;
+ }
+
+#ifdef CONFIG_LED
+ gpio_pin_set_dt(&led0, 0);
+#endif
+
+ g_microtvm_end_time = timing_counter_get();
+ uint64_t cycles = timing_cycles_get(&g_microtvm_start_time,
&g_microtvm_end_time);
+ uint64_t ns_spent = timing_cycles_to_ns(cycles);
+ *elapsed_time_seconds = ns_spent / (double)1e9;
+ g_microtvm_timer_running = 0;
+ return kTvmErrorNoError;
+}
+
+tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer, size_t num_bytes) {
+ uint32_t random; // one unit of random data.
+
+ // Fill parts of `buffer` which are as large as `random`.
+ size_t num_full_blocks = num_bytes / sizeof(random);
+ for (int i = 0; i < num_full_blocks; ++i) {
+ random = sys_rand32_get();
+ memcpy(&buffer[i * sizeof(random)], &random, sizeof(random));
+ }
+
+ // Fill any leftover tail which is smaller than `random`.
+ size_t num_tail_bytes = num_bytes % sizeof(random);
+ if (num_tail_bytes > 0) {
+ random = sys_rand32_get();
+ memcpy(&buffer[num_bytes - num_tail_bytes], &random, num_tail_bytes);
+ }
+ return kTvmErrorNoError;
+}
+
+tvm_crt_error_t TVMPlatformInitialize() {
+#ifdef CONFIG_LED
+ if (!device_is_ready(led0.port)) {
+ for (;;)
+ ;
+ }
+ int ret = gpio_pin_configure_dt(&led0, GPIO_OUTPUT_ACTIVE);
+ if (ret < 0) {
+ TVMPlatformAbort((tvm_crt_error_t)0xbeef4);
+ }
+ gpio_pin_set_dt(&led0, 0);
+#endif
+
+ // Initialize system timing. We could stop and start it every time, but we'll
+ // be using it enough we should just keep it enabled.
+ timing_init();
+ timing_start();
+
+ return kTvmErrorNoError;
+}
diff --git a/apps/microtvm/zephyr/template_project/src/mlperftiny/platform.cc
b/apps/microtvm/zephyr/template_project/src/mlperftiny/platform.cc
new file mode 100644
index 0000000000..9dc4516271
--- /dev/null
+++ b/apps/microtvm/zephyr/template_project/src/mlperftiny/platform.cc
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \brief Implementation of TVMPlatform functions in tvm/runtime/crt/platform.h
+ */
+
+#include <dlpack/dlpack.h>
+#include <float.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <tvm/runtime/c_runtime_api.h>
+#include <tvm/runtime/crt/error_codes.h>
+#include <tvm/runtime/crt/logging.h>
+#include <tvm/runtime/crt/platform.h>
+#include <tvm/runtime/crt/stack_allocator.h>
+#include <zephyr/sys/printk.h>
+#include <zephyr/sys/reboot.h>
+
+#include "crt_config.h"
+
+// TVM_WORKSPACE_SIZE_BYTES is defined in python
+static uint8_t g_aot_memory[TVM_WORKSPACE_SIZE_BYTES];
+tvm_workspace_t app_workspace;
+
+size_t TVMPlatformFormatMessage(char* out_buf, size_t out_buf_size_bytes,
const char* fmt,
+ va_list args) {
+ return vsnprintk(out_buf, out_buf_size_bytes, fmt, args);
+}
+
+void TVMPlatformAbort(tvm_crt_error_t error) {
+ TVMLogf("TVMPlatformAbort: %08x\n", error);
+ sys_reboot(SYS_REBOOT_COLD);
+ for (;;)
+ ;
+}
+
+tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLDevice dev,
void** out_ptr) {
+ return StackMemoryManager_Allocate(&app_workspace, num_bytes, out_ptr);
+}
+
+tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice dev) {
+ return StackMemoryManager_Free(&app_workspace, ptr);
+}
+
+tvm_crt_error_t TVMPlatformInitialize() {
+ StackMemoryManager_Init(&app_workspace, g_aot_memory, sizeof(g_aot_memory));
+ return kTvmErrorNoError;
+}
diff --git
a/apps/microtvm/zephyr/template_project/src/mlperftiny/submitter_implemented.cc
b/apps/microtvm/zephyr/template_project/src/mlperftiny/submitter_implemented.cc
index 91ae0c025c..72b679c640 100644
---
a/apps/microtvm/zephyr/template_project/src/mlperftiny/submitter_implemented.cc
+++
b/apps/microtvm/zephyr/template_project/src/mlperftiny/submitter_implemented.cc
@@ -19,20 +19,46 @@
#include "api/submitter_implemented.h"
+#include <string.h>
+#include <tvm/runtime/crt/logging.h>
#include <tvm/runtime/crt/platform.h>
#include <unistd.h>
#include <zephyr/drivers/gpio.h>
+#include <zephyr/drivers/uart.h>
#include <zephyr/kernel.h>
+#include <zephyr/sys/ring_buffer.h>
#include "api/internally_implemented.h"
-#include "tvmruntime.h"
-#include "zephyr_uart.h"
+#include "crt_config.h"
+#include "tvm/output_data.h"
+#include "tvmgen_default.h"
+
+// ###############################################################
+// Model
+// ###############################################################
+#define MODEL_KWS 1
+#define MODEL_VWW 2
+#define MODEL_AD 3
+#define MODEL_IC 4
static void* g_input_data;
-#if TARGET_MODEL == 3 // AD
+#if TARGET_MODEL == MODEL_AD
static uint8_t __aligned(4) g_input_data_buffer_aligned[MAX_DB_INPUT_SIZE];
#endif
+// OUT_QUANT_SCALE and OUT_QUANT_ZERO are set in python.
+#if TARGET_MODEL == MODEL_AD
+float* g_output_data = output_data;
+#else
+int8_t* g_output_data = output_data;
+float g_quant_scale = OUT_QUANT_SCALE;
+int8_t g_quant_zero = OUT_QUANT_ZERO;
+#endif
+size_t g_output_data_len = output_data_len;
+
+// ###############################################################
+// GPIO
+// ###############################################################
#if EE_CFG_ENERGY_MODE == 1 && NRF_BOARD != 1
// use GPIO PC6 which is on connector CN7 pin 1 on the nucleo_l4r5zi
static const char* g_gpio_device_name = "GPIOC";
@@ -40,23 +66,141 @@ static const struct device* g_gpio_dev;
static const gpio_pin_t g_gpio_pin = 6;
#endif
+// ###############################################################
+// UART
+// ###############################################################
+#define TVM_UART_DEFAULT_BAUDRATE 115200
+static const struct device* g_microtvm_uart;
+
+void UartInit(uint32_t baudrate = TVM_UART_DEFAULT_BAUDRATE) {
+ // Claim console device.
+ g_microtvm_uart = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
+ const struct uart_config config = {.baudrate = baudrate,
+ .parity = UART_CFG_PARITY_NONE,
+ .stop_bits = UART_CFG_STOP_BITS_1,
+ .data_bits = UART_CFG_DATA_BITS_8,
+ .flow_ctrl = UART_CFG_FLOW_CTRL_NONE};
+ uart_configure(g_microtvm_uart, &config);
+}
+
+char UartRxRead() {
+ unsigned char c;
+ int ret = -1;
+ while (ret != 0) {
+ ret = uart_poll_in(g_microtvm_uart, &c);
+ }
+ return (char)c;
+}
+
+uint32_t UartTxWrite(const char* data, uint32_t size) {
+ for (uint32_t i = 0; i < size; i++) {
+ uart_poll_out(g_microtvm_uart, data[i]);
+ }
+ return size;
+}
+
+// ###############################################################
+// TVM
+// ###############################################################
+#ifdef __cplusplus
+extern "C" {
+#endif
+// TODO(mehrdadh): remove and reuse the CRT
+// implementation in src/runtime/crt/common/crt_backend_api.c
+void* TVMBackendAllocWorkspace(int device_type, int device_id, uint64_t
nbytes, int dtype_code_hint,
+ int dtype_bits_hint) {
+ tvm_crt_error_t err = kTvmErrorNoError;
+ void* ptr = 0;
+ DLDevice dev = {(DLDeviceType)device_type, device_id};
+ assert(nbytes > 0);
+ err = TVMPlatformMemoryAllocate(nbytes, dev, &ptr);
+ CHECK_EQ(err, kTvmErrorNoError,
+ "TVMBackendAllocWorkspace(%d, %d, %" PRIu64 ", %d, %d) -> %"
PRId32, device_type,
+ device_id, nbytes, dtype_code_hint, dtype_bits_hint, err);
+ return ptr;
+}
+
+// TODO(mehrdadh): remove and reuse the CRT
+// implementation in src/runtime/crt/common/crt_backend_api.c
+int TVMBackendFreeWorkspace(int device_type, int device_id, void* ptr) {
+ tvm_crt_error_t err = kTvmErrorNoError;
+ DLDevice dev = {(DLDeviceType)device_type, device_id};
+ err = TVMPlatformMemoryFree(ptr, dev);
+ CHECK_EQ(err, kTvmErrorNoError, "TVMBackendFreeWorkspace(%d, %d)",
device_type, device_id);
+ return err;
+}
+
+void TVMLogf(const char* msg, ...) {
+ char buffer[128];
+ int size;
+ va_list args;
+ va_start(args, msg);
+ size = TVMPlatformFormatMessage(buffer, 128, msg, args);
+ va_end(args);
+ UartTxWrite(buffer, (size_t)size);
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+void Infer(void* input_ptr) {
+ struct tvmgen_default_inputs inputs = {
+#if TARGET_MODEL == MODEL_KWS
+ .input_1 = input_ptr,
+#elif TARGET_MODEL == MODEL_IC
+ .input_1_int8 = input_ptr,
+#elif TARGET_MODEL == MODEL_VWW
+ .input_1_int8 = input_ptr,
+#elif TARGET_MODEL == MODEL_AD
+ .input_1 = input_ptr,
+#elif
+#error Wrong model.
+#endif
+ };
+
+ struct tvmgen_default_outputs outputs = {
+#if TARGET_MODEL == MODEL_KWS
+#if COMPILE_WITH_CMSISNN
+ .Identity = output_data,
+#else
+ .output = output_data,
+#endif
+#elif TARGET_MODEL == MODEL_IC
+ .Identity_int8 = output_data,
+#elif TARGET_MODEL == MODEL_VWW
+ .Identity_int8 = output_data,
+#elif TARGET_MODEL == MODEL_AD
+ .Identity = output_data,
+#endif
+ };
+
+ int ret_val = tvmgen_default_run(&inputs, &outputs);
+ if (ret_val != 0) {
+ th_printf("Error: %d\n", ret_val);
+ }
+}
+
+// ###############################################################
+// MLPerftiny APIs
+// ###############################################################
// Implement this method to prepare for inference and preprocess inputs.
// Modified from source
void th_load_tensor() {
-#if TARGET_MODEL == 1 // KWS
+#if TARGET_MODEL == MODEL_KWS
g_input_data = static_cast<void*>(ee_get_buffer_pointer());
-#elif TARGET_MODEL == 2 // VWW
+#elif TARGET_MODEL == MODEL_VWW
// Converting uint8 to int8
int8_t* temp_int = reinterpret_cast<int8_t*>(ee_get_buffer_pointer());
for (size_t i = 0; i < MAX_DB_INPUT_SIZE; i++) {
temp_int[i] -= 128;
}
g_input_data = static_cast<void*>(temp_int);
-#elif TARGET_MODEL == 3 // AD
+#elif TARGET_MODEL == MODEL_AD
uint8_t* buffer = ee_get_buffer_pointer();
memcpy(g_input_data_buffer_aligned, buffer,
sizeof(g_input_data_buffer_aligned));
g_input_data = g_input_data_buffer_aligned;
-#elif TARGET_MODEL == 4 // IC
+#elif TARGET_MODEL == MODEL_IC
uint8_t* temp_uint = reinterpret_cast<uint8_t*>(ee_get_buffer_pointer());
int8_t* temp_int = reinterpret_cast<int8_t*>(ee_get_buffer_pointer());
for (size_t i = 0; i < MAX_DB_INPUT_SIZE; i++) {
@@ -71,7 +215,7 @@ void th_load_tensor() {
#endif
}
-#if TARGET_MODEL == 3 // model AD
+#if TARGET_MODEL == MODEL_AD
// calculate |output - input| for AD model
static float calculate_result() {
size_t feature_size = g_output_data_len;
@@ -95,7 +239,7 @@ void th_results() {
* The results need to be printed back in exactly this format; if easier
* to just modify this loop than copy to results[] above, do that.
*/
-#if TARGET_MODEL == 3 // model AD
+#if TARGET_MODEL == MODEL_AD
th_printf("m-results-[%0.3f]\r\n", calculate_result());
#else
size_t kCategoryCount = g_output_data_len;
@@ -114,11 +258,11 @@ void th_results() {
// Implement this method with the logic to perform one inference cycle.
// Modified from source
-void th_infer() { TVMInfer(g_input_data); }
+void th_infer() { Infer(g_input_data); }
/// \brief optional API.
// Modified from source
-void th_final_initialize(void) { TVMRuntimeInit(); }
+void th_final_initialize(void) { TVMPlatformInitialize(); }
void th_pre() {}
void th_post() {}
@@ -156,18 +300,18 @@ void th_printf(const char* p_fmt, ...) {
va_start(args, p_fmt);
size = TVMPlatformFormatMessage(buffer, 128, p_fmt, args);
va_end(args);
- TVMPlatformWriteSerial(buffer, (size_t)size);
+ UartTxWrite(buffer, (size_t)size);
}
// Modified from source
-char th_getchar() { return TVMPlatformUartRxRead(); }
+char th_getchar() { return UartRxRead(); }
// Modified from source
void th_serialport_initialize(void) {
#if EE_CFG_ENERGY_MODE == 1 && NRF_BOARD != 1
- TVMPlatformUARTInit(9600);
+ UartInit(9600);
#else
- TVMPlatformUARTInit();
+ UartInit();
#endif
}
diff --git a/apps/microtvm/zephyr/template_project/src/mlperftiny/tvmruntime.cc
b/apps/microtvm/zephyr/template_project/src/mlperftiny/tvmruntime.cc
deleted file mode 100644
index 3fb7ccf8eb..0000000000
--- a/apps/microtvm/zephyr/template_project/src/mlperftiny/tvmruntime.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include "tvmruntime.h"
-
-#include <assert.h>
-#include <float.h>
-#include <math.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <tvm/runtime/c_runtime_api.h>
-#include <tvm/runtime/crt/logging.h>
-#include <tvm/runtime/crt/platform.h>
-#include <tvm/runtime/crt/stack_allocator.h>
-#include <zephyr/kernel.h>
-#include <zephyr/sys/reboot.h>
-
-#include "output_data.h"
-#include "tvmgen_default.h"
-#include "zephyr_uart.h"
-
-#ifdef CONFIG_ARCH_POSIX
-#include "posix_board_if.h"
-#endif
-
-// OUT_QUANT_SCALE and OUT_QUANT_ZERO are set in python.
-#if TARGET_MODEL == 3
-float* g_output_data = output_data;
-#else
-int8_t* g_output_data = output_data;
-float g_quant_scale = OUT_QUANT_SCALE;
-int8_t g_quant_zero = OUT_QUANT_ZERO;
-#endif
-size_t g_output_data_len = output_data_len;
-
-// WORKSPACE_SIZE is defined in python
-static uint8_t g_aot_memory[WORKSPACE_SIZE];
-tvm_workspace_t app_workspace;
-
-size_t TVMPlatformFormatMessage(char* out_buf, size_t out_buf_size_bytes,
const char* fmt,
- va_list args) {
- return vsnprintk(out_buf, out_buf_size_bytes, fmt, args);
-}
-
-void TVMLogf(const char* msg, ...) {
- char buffer[128];
- int size;
- va_list args;
- va_start(args, msg);
- size = TVMPlatformFormatMessage(buffer, 128, msg, args);
- va_end(args);
- TVMPlatformWriteSerial(buffer, (size_t)size);
-}
-
-void __attribute__((noreturn)) TVMPlatformAbort(tvm_crt_error_t error) {
- TVMLogf("TVMPlatformAbort: %08x\n", error);
- sys_reboot(SYS_REBOOT_COLD);
- for (;;)
- ;
-}
-
-tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLDevice dev,
void** out_ptr) {
- return StackMemoryManager_Allocate(&app_workspace, num_bytes, out_ptr);
-}
-
-tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice dev) {
- return StackMemoryManager_Free(&app_workspace, ptr);
-}
-
-void timer_expiry_function(struct k_timer* timer_id) { return; }
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-void* TVMBackendAllocWorkspace(int device_type, int device_id, uint64_t
nbytes, int dtype_code_hint,
- int dtype_bits_hint) {
- tvm_crt_error_t err = kTvmErrorNoError;
- void* ptr = 0;
- DLDevice dev = {(DLDeviceType)device_type, device_id};
- assert(nbytes > 0);
- err = TVMPlatformMemoryAllocate(nbytes, dev, &ptr);
- CHECK_EQ(err, kTvmErrorNoError,
- "TVMBackendAllocWorkspace(%d, %d, %" PRIu64 ", %d, %d) -> %"
PRId32, device_type,
- device_id, nbytes, dtype_code_hint, dtype_bits_hint, err);
- return ptr;
-}
-
-int TVMBackendFreeWorkspace(int device_type, int device_id, void* ptr) {
- tvm_crt_error_t err = kTvmErrorNoError;
- DLDevice dev = {(DLDeviceType)device_type, device_id};
- err = TVMPlatformMemoryFree(ptr, dev);
- CHECK_EQ(err, kTvmErrorNoError, "TVMBackendFreeWorkspace(%d, %d)",
device_type, device_id);
- return err;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-void TVMRuntimeInit() { StackMemoryManager_Init(&app_workspace, g_aot_memory,
WORKSPACE_SIZE); }
-
-void TVMInfer(void* input_ptr) {
- struct tvmgen_default_inputs inputs = {
-#if TARGET_MODEL == MODEL_KWS
- .input_1 = input_ptr,
-#elif TARGET_MODEL == MODEL_IC
- .input_1_int8 = input_ptr,
-#elif TARGET_MODEL == MODEL_VWW
- .input_1_int8 = input_ptr,
-#elif TARGET_MODEL == MODEL_AD
- .input_1 = input_ptr,
-#elif
-#error Wrong model.
-#endif
- };
-
- struct tvmgen_default_outputs outputs = {
-#if TARGET_MODEL == MODEL_KWS
-#if COMPILE_WITH_CMSISNN
- .Identity = output_data,
-#else
- .output = output_data,
-#endif
-#elif TARGET_MODEL == MODEL_IC
- .Identity_int8 = output_data,
-#elif TARGET_MODEL == MODEL_VWW
- .Identity_int8 = output_data,
-#elif TARGET_MODEL == MODEL_AD
- .Identity = output_data,
-#endif
- };
-
- int ret_val = tvmgen_default_run(&inputs, &outputs);
- if (ret_val != 0) {
- TVMLogf("Error: %d\n", ret_val);
- }
-}
-
-int8_t QuantizeFloatToInt8(float value, float scale, int zero_point) {
- int32_t result = round(value / scale) + zero_point;
- if (result < INT8_MIN) {
- result = INT8_MIN;
- }
- if (result > INT8_MAX) {
- result = INT8_MAX;
- }
- return (int8_t)(result);
-}
diff --git a/apps/microtvm/zephyr/template_project/src/mlperftiny/tvmruntime.h
b/apps/microtvm/zephyr/template_project/src/mlperftiny/tvmruntime.h
deleted file mode 100644
index 940d64634d..0000000000
--- a/apps/microtvm/zephyr/template_project/src/mlperftiny/tvmruntime.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef APPS_MICROTVM_ZEPHYR_TEMPLATE_PROJECT_SRC_MLPERFTINY_TVMRUNTIME_H_
-#define APPS_MICROTVM_ZEPHYR_TEMPLATE_PROJECT_SRC_MLPERFTINY_TVMRUNTIME_H_
-
-#include <stdarg.h>
-#include <tvm/runtime/crt/error_codes.h>
-#include <unistd.h>
-
-#define MODEL_KWS 1
-#define MODEL_VWW 2
-#define MODEL_AD 3
-#define MODEL_IC 4
-
-extern const unsigned char g_wakeup_sequence[];
-extern size_t g_output_data_len;
-
-#if TARGET_MODEL == 3
-extern float* g_output_data;
-#else
-extern int8_t* g_output_data;
-#endif
-
-extern float g_quant_scale;
-extern int8_t g_quant_zero;
-
-/*!
- * \brief Initialize TVM runtime.
- */
-void TVMRuntimeInit();
-
-/*!
- * \brief Run TVM inference.
- */
-void TVMInfer(void* input_ptr);
-
-/*!
- * \brief Quantize float to int8.
- * \param value Input data in float.
- * \param scale Quantization scale factor.
- * \param zero_point Quantization zero point.
- */
-int8_t QuantizeFloatToInt8(float value, float scale, int zero_point);
-
-#endif /* APPS_MICROTVM_ZEPHYR_TEMPLATE_PROJECT_SRC_MLPERFTINY_TVMRUNTIME_H_ */
diff --git
a/apps/microtvm/zephyr/template_project/src/mlperftiny/zephyr_uart.cc
b/apps/microtvm/zephyr/template_project/src/mlperftiny/zephyr_uart.cc
deleted file mode 100644
index 0922c32133..0000000000
--- a/apps/microtvm/zephyr/template_project/src/mlperftiny/zephyr_uart.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#include "zephyr_uart.h"
-
-#include <tvm/runtime/crt/error_codes.h>
-#include <zephyr/drivers/uart.h>
-#include <zephyr/sys/ring_buffer.h>
-
-#include "crt_config.h"
-
-static const struct device* g_microtvm_uart;
-
-static uint8_t uart_data[8];
-
-// UART interrupt callback.
-void uart_irq_cb(const struct device* dev, void* user_data) {
- while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
- struct ring_buf* rbuf = (struct ring_buf*)user_data;
- if (uart_irq_rx_ready(dev) != 0) {
- for (;;) {
- // Read a small chunk of data from the UART.
- int bytes_read = uart_fifo_read(dev, uart_data, sizeof(uart_data));
- if (bytes_read < 0) {
- TVMPlatformAbort((tvm_crt_error_t)(0xbeef1));
- } else if (bytes_read == 0) {
- break;
- }
- // Write it into the ring buffer.
- int bytes_written = ring_buf_put(rbuf, uart_data, bytes_read);
- if (bytes_read != bytes_written) {
- TVMPlatformAbort((tvm_crt_error_t)(0xbeef2));
- }
- }
- }
- }
-}
-
-// Initialize the UART receiver.
-void uart_rx_init(struct ring_buf* rbuf, const struct device* dev) {
- uart_irq_callback_user_data_set(dev, uart_irq_cb, (void*)rbuf);
- uart_irq_rx_enable(dev);
-}
-
-// UART read.
-char TVMPlatformUartRxRead() {
- unsigned char c;
- int ret = -1;
- while (ret != 0) {
- ret = uart_poll_in(g_microtvm_uart, &c);
- }
- return (char)c;
-}
-
-// UART write.
-uint32_t TVMPlatformWriteSerial(const char* data, uint32_t size) {
- for (uint32_t i = 0; i < size; i++) {
- uart_poll_out(g_microtvm_uart, data[i]);
- }
- return size;
-}
-
-// Initialize UART.
-void TVMPlatformUARTInit(uint32_t baudrate /* = TVM_UART_DEFAULT_BAUDRATE */) {
- // Claim console device.
- g_microtvm_uart = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
- const struct uart_config config = {.baudrate = baudrate,
- .parity = UART_CFG_PARITY_NONE,
- .stop_bits = UART_CFG_STOP_BITS_1,
- .data_bits = UART_CFG_DATA_BITS_8,
- .flow_ctrl = UART_CFG_FLOW_CTRL_NONE};
- uart_configure(g_microtvm_uart, &config);
-}
diff --git a/apps/microtvm/zephyr/template_project/src/mlperftiny/zephyr_uart.h
b/apps/microtvm/zephyr/template_project/src/mlperftiny/zephyr_uart.h
deleted file mode 100644
index f10cf02622..0000000000
--- a/apps/microtvm/zephyr/template_project/src/mlperftiny/zephyr_uart.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-#ifndef APPS_MICROTVM_ZEPHYR_TEMPLATE_PROJECT_SRC_MLPERFTINY_ZEPHYR_UART_H_
-#define APPS_MICROTVM_ZEPHYR_TEMPLATE_PROJECT_SRC_MLPERFTINY_ZEPHYR_UART_H_
-
-#include <stdint.h>
-
-#define TVM_UART_DEFAULT_BAUDRATE 115200
-
-/*!
- * \brief Read Uart Rx buffer.
- * \param data Pointer to read data.
- * \param data_size_bytes Read request size in bytes.
- *
- * \return Number of data read in bytes.
- */
-char TVMPlatformUartRxRead();
-
-/*!
- * \brief Write data in serial.
- * \param data Pointer to data to write.
- * \param size Size of data in bytes.
- *
- * \return Number of write in bytes.
- */
-uint32_t TVMPlatformWriteSerial(const char* data, uint32_t size);
-
-/*!
- * \brief Initialize Uart.
- * \param baudrate Desired UART baudrate.
- */
-void TVMPlatformUARTInit(uint32_t baudrate = TVM_UART_DEFAULT_BAUDRATE);
-
-#endif /* APPS_MICROTVM_ZEPHYR_TEMPLATE_PROJECT_SRC_MLPERFTINY_ZEPHYR_UART_H_
*/
diff --git a/cmake/modules/CRT.cmake b/cmake/modules/CRT.cmake
index 518a613dc1..3ddbb5298f 100644
--- a/cmake/modules/CRT.cmake
+++ b/cmake/modules/CRT.cmake
@@ -22,8 +22,9 @@ if(USE_MICRO)
CRT_TEMPLATE_FILE_COPY_JOBS
"src/runtime/crt/host microtvm_api_server.py -> crt"
"src/runtime/crt/host Makefile.template -> crt"
- "src/runtime/crt crt_config-template.h -> crt"
"src/runtime/crt/host main.cc -> crt/src"
+ "src/runtime/crt/host platform.cc -> crt/src"
+ "src/runtime/crt crt_config-template.h -> crt/crt_config"
)
foreach(job_spec IN LISTS CRT_TEMPLATE_FILE_COPY_JOBS)
@@ -66,6 +67,10 @@ if(USE_MICRO)
endforeach()
endforeach()
+ # Add template files for Model Library Format
+ configure_file("src/runtime/crt/crt_config-template.h"
"${MICROTVM_TEMPLATE_PROJECTS}/crt/templates/crt_config.h.template" COPYONLY)
+ configure_file("src/runtime/crt/platform-template.c"
"${MICROTVM_TEMPLATE_PROJECTS}/crt/templates/platform.c.template" COPYONLY)
+
add_custom_target(crt DEPENDS ${crt_template_deps})
endfunction()
diff --git a/cmake/modules/Zephyr.cmake b/cmake/modules/Zephyr.cmake
index a13aef3319..38551f1dd4 100644
--- a/cmake/modules/Zephyr.cmake
+++ b/cmake/modules/Zephyr.cmake
@@ -26,11 +26,9 @@ if(USE_MICRO)
"apps/microtvm/zephyr/template_project boards.json -> zephyr"
"apps/microtvm/zephyr/template_project CMakeLists.txt.template -> zephyr"
"apps/microtvm/zephyr/template_project/src/aot_standalone_demo *.c ->
zephyr/src/aot_standalone_demo"
- "apps/microtvm/zephyr/template_project/src/aot_standalone_demo *.h ->
zephyr/src/aot_standalone_demo"
"apps/microtvm/zephyr/template_project/src/host_driven *.c ->
zephyr/src/host_driven"
"apps/microtvm/zephyr/template_project/src/host_driven *.h ->
zephyr/src/host_driven"
"apps/microtvm/zephyr/template_project/src/mlperftiny *.cc ->
zephyr/src/mlperftiny"
- "apps/microtvm/zephyr/template_project/src/mlperftiny *.h ->
zephyr/src/mlperftiny"
"3rdparty/mlperftiny/api * -> zephyr/src/mlperftiny/api"
"apps/microtvm/zephyr/template_project/fvp-hack * -> zephyr/fvp-hack"
"apps/microtvm/zephyr/template_project/qemu-hack * -> zephyr/qemu-hack"
diff --git a/gallery/how_to/work_with_microtvm/micro_mlperftiny.py
b/gallery/how_to/work_with_microtvm/micro_mlperftiny.py
index e8c6a253ad..bb7abddddc 100644
--- a/gallery/how_to/work_with_microtvm/micro_mlperftiny.py
+++ b/gallery/how_to/work_with_microtvm/micro_mlperftiny.py
@@ -226,7 +226,7 @@ with tarfile.open(extra_tar_file, "w:gz") as tf:
shape=output_shape,
dtype=output_dtype,
),
- "include",
+ "include/tvm",
tf,
)
diff --git a/gallery/how_to/work_with_microtvm/micro_pytorch.py
b/gallery/how_to/work_with_microtvm/micro_pytorch.py
index a7f5f10280..a0f4ebddee 100644
--- a/gallery/how_to/work_with_microtvm/micro_pytorch.py
+++ b/gallery/how_to/work_with_microtvm/micro_pytorch.py
@@ -131,7 +131,7 @@ with tvm.transform.PassContext(
#
template_project_path =
pathlib.Path(tvm.micro.get_microtvm_template_projects("crt"))
-project_options = {"verbose": False, "memory_size_bytes": 6 * 1024 * 1024}
+project_options = {"verbose": False, "workspace_size_bytes": 6 * 1024 * 1024}
temp_dir = tvm.contrib.utils.tempdir() / "project"
project = tvm.micro.generate_project(
diff --git a/include/tvm/runtime/crt/platform.h
b/include/tvm/runtime/crt/platform.h
index 1bc610e6cc..85121fd0f5 100644
--- a/include/tvm/runtime/crt/platform.h
+++ b/include/tvm/runtime/crt/platform.h
@@ -139,6 +139,15 @@ tvm_crt_error_t TVMPlatformAfterMeasurement();
*/
tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer, size_t num_bytes);
+/*! \brief Initialize TVM inference.
+ *
+ * Placeholder function for TVM inference initializations on a specific
platform.
+ * A common use of this function is setting up workspace memory for TVM
inference.
+ *
+ * \return kTvmErrorNoError if successful.
+ */
+tvm_crt_error_t TVMPlatformInitialize();
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/python/tvm/micro/model_library_format.py
b/python/tvm/micro/model_library_format.py
index fc32fe34d6..b16877b256 100644
--- a/python/tvm/micro/model_library_format.py
+++ b/python/tvm/micro/model_library_format.py
@@ -26,7 +26,7 @@ import tarfile
import typing
import tvm
-from tvm.micro import get_standalone_crt_dir
+from tvm.micro import get_standalone_crt_dir, get_microtvm_template_projects
from .._ffi import get_global_func
from ..contrib import utils
@@ -39,6 +39,7 @@ from ..tir import expr
# This should be kept identical to runtime::symbol::tvm_module_main
MAIN_FUNC_NAME_STR = "__tvm_main__"
STANDALONE_CRT_URL = "./runtime"
+CRT_TEMPLATE_FILES_URL = "./templates"
METADATA_FILE = "metadata.json"
@@ -373,7 +374,18 @@ def _make_tar(source_dir, tar_file_path, modules):
for mod in modules:
is_aot = isinstance(mod, executor_factory.AOTExecutorFactoryModule)
if is_aot and str(mod.runtime) == "crt":
+ crt_template_path =
pathlib.Path(get_microtvm_template_projects("crt"))
tar_f.add(get_standalone_crt_dir(), arcname=STANDALONE_CRT_URL)
+
+ # Add template files from CRT template project
+ for file in [
+ "templates/crt_config.h.template",
+ "templates/platform.c.template",
+ ]:
+ tar_f.add(
+ crt_template_path / pathlib.Path(file),
+
arcname=f"{CRT_TEMPLATE_FILES_URL}/{pathlib.Path(file).name}",
+ )
break
diff --git a/python/tvm/testing/aot.py b/python/tvm/testing/aot.py
index 5ddbdcabac..a975eb95bc 100644
--- a/python/tvm/testing/aot.py
+++ b/python/tvm/testing/aot.py
@@ -725,8 +725,8 @@ def run_and_check(
os.mkdir(include_path)
crt_root = tvm.micro.get_microtvm_template_projects("crt")
shutil.copy2(
- os.path.join(crt_root, "crt_config-template.h"),
- os.path.join(include_path, "crt_config.h"),
+ pathlib.Path(crt_root) / "crt_config" / "crt_config-template.h",
+ pathlib.Path(include_path) / "crt_config.h",
)
workspace_bytes = 0
diff --git a/src/runtime/crt/host/Makefile.template
b/src/runtime/crt/host/Makefile.template
index 2caf7ba0bc..526b17deb7 100644
--- a/src/runtime/crt/host/Makefile.template
+++ b/src/runtime/crt/host/Makefile.template
@@ -16,9 +16,9 @@
# under the License.
INCLUDES ?= -isystem crt/include -Icrt_config
-MEMORY_SIZE_BYTES := <MEMORY_SIZE_BYTES>
+TVM_WORKSPACE_SIZE_BYTES := <TVM_WORKSPACE_SIZE_BYTES>
CFLAGS ?= -Werror -Wall
-CXXFLAGS ?= -Werror -Wall -std=c++11 -DTVM_HOST_USE_GRAPH_EXECUTOR_MODULE
-DMEMORY_SIZE_BYTES=$(MEMORY_SIZE_BYTES)
+CXXFLAGS ?= -Werror -Wall -std=c++11 -DTVM_HOST_USE_GRAPH_EXECUTOR_MODULE
-DTVM_WORKSPACE_SIZE_BYTES=$(TVM_WORKSPACE_SIZE_BYTES)
LDFLAGS ?= -Werror -Wall
# Codegen produces spurious lines like: int32_t arg2_code =
((int32_t*)arg_type_ids)[(2)];
diff --git a/src/runtime/crt/host/main.cc b/src/runtime/crt/host/main.cc
index e9f6813f9b..0607d4b287 100644
--- a/src/runtime/crt/host/main.cc
+++ b/src/runtime/crt/host/main.cc
@@ -22,14 +22,12 @@
* \brief main entry point for host subprocess-based CRT
*/
#include <inttypes.h>
-#include <time.h>
#include <tvm/runtime/c_runtime_api.h>
+#include <tvm/runtime/crt/aot_executor_module.h>
#include <tvm/runtime/crt/logging.h>
#include <tvm/runtime/crt/microtvm_rpc_server.h>
-#include <tvm/runtime/crt/page_allocator.h>
#include <unistd.h>
-#include <chrono>
#include <iostream>
#include "crt_config.h"
@@ -38,10 +36,6 @@
#include <tvm/runtime/crt/graph_executor_module.h>
#endif
-#include <tvm/runtime/crt/aot_executor_module.h>
-
-using namespace std::chrono;
-
extern "C" {
ssize_t MicroTVMWriteFunc(void* context, const uint8_t* data, size_t
num_bytes) {
@@ -50,70 +44,8 @@ ssize_t MicroTVMWriteFunc(void* context, const uint8_t*
data, size_t num_bytes)
fsync(STDOUT_FILENO);
return to_return;
}
-
-size_t TVMPlatformFormatMessage(char* out_buf, size_t out_buf_size_bytes,
const char* fmt,
- va_list args) {
- return vsnprintf(out_buf, out_buf_size_bytes, fmt, args);
-}
-
-void TVMPlatformAbort(tvm_crt_error_t error_code) {
- std::cerr << "TVMPlatformAbort: " << error_code << std::endl;
- throw "Aborted";
}
-MemoryManagerInterface* memory_manager;
-
-tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLDevice dev,
void** out_ptr) {
- return memory_manager->Allocate(memory_manager, num_bytes, dev, out_ptr);
-}
-
-tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice dev) {
- return memory_manager->Free(memory_manager, ptr, dev);
-}
-
-steady_clock::time_point g_microtvm_start_time;
-int g_microtvm_timer_running = 0;
-
-tvm_crt_error_t TVMPlatformTimerStart() {
- if (g_microtvm_timer_running) {
- std::cerr << "timer already running" << std::endl;
- return kTvmErrorPlatformTimerBadState;
- }
- g_microtvm_start_time = std::chrono::steady_clock::now();
- g_microtvm_timer_running = 1;
- return kTvmErrorNoError;
-}
-
-tvm_crt_error_t TVMPlatformTimerStop(double* elapsed_time_seconds) {
- if (!g_microtvm_timer_running) {
- std::cerr << "timer not running" << std::endl;
- return kTvmErrorPlatformTimerBadState;
- }
- auto microtvm_stop_time = std::chrono::steady_clock::now();
- std::chrono::microseconds time_span =
std::chrono::duration_cast<std::chrono::microseconds>(
- microtvm_stop_time - g_microtvm_start_time);
- *elapsed_time_seconds = static_cast<double>(time_span.count()) / 1e6;
- g_microtvm_timer_running = 0;
- return kTvmErrorNoError;
-}
-
-static_assert(RAND_MAX >= (1 << 8), "RAND_MAX is smaller than acceptable");
-unsigned int random_seed = 0;
-tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer, size_t num_bytes) {
- if (random_seed == 0) {
- random_seed = (unsigned int)time(NULL);
- }
- for (size_t i = 0; i < num_bytes; ++i) {
- int random = rand_r(&random_seed);
- buffer[i] = (uint8_t)random;
- }
-
- return kTvmErrorNoError;
-}
-}
-
-uint8_t memory[MEMORY_SIZE_BYTES];
-
static char** g_argv = NULL;
int testonly_reset_server(TVMValue* args, int* type_codes, int num_args,
TVMValue* out_ret_value,
@@ -125,13 +57,7 @@ int testonly_reset_server(TVMValue* args, int* type_codes,
int num_args, TVMValu
int main(int argc, char** argv) {
g_argv = argv;
- int status =
- PageMemoryManagerCreate(&memory_manager, memory, sizeof(memory), 8 /*
page_size_log2 */);
- if (status != 0) {
- fprintf(stderr, "error initiailizing memory manager\n");
- return 2;
- }
-
+ TVMPlatformInitialize();
microtvm_rpc_server_t rpc_server = MicroTVMRpcServerInit(&MicroTVMWriteFunc,
nullptr);
#ifdef TVM_HOST_USE_GRAPH_EXECUTOR_MODULE
diff --git a/src/runtime/crt/host/microtvm_api_server.py
b/src/runtime/crt/host/microtvm_api_server.py
index e5b82f96b0..57b7506b87 100644
--- a/src/runtime/crt/host/microtvm_api_server.py
+++ b/src/runtime/crt/host/microtvm_api_server.py
@@ -38,7 +38,7 @@ MODEL_LIBRARY_FORMAT_RELPATH = "model.tar"
IS_TEMPLATE = not os.path.exists(os.path.join(PROJECT_DIR,
MODEL_LIBRARY_FORMAT_RELPATH))
# Used this size to pass most CRT tests in TVM.
-MEMORY_SIZE_BYTES = 2 * 1024 * 1024
+WORKSPACE_SIZE_BYTES = 2 * 1024 * 1024
MAKEFILE_FILENAME = "Makefile"
@@ -67,11 +67,11 @@ class Handler(server.ProjectAPIHandler):
help="Run make with verbose output",
),
server.ProjectOption(
- "memory_size_bytes",
+ "workspace_size_bytes",
optional=["generate_project"],
type="int",
- default=MEMORY_SIZE_BYTES,
- help="Sets the value of MEMORY_SIZE_BYTES.",
+ default=WORKSPACE_SIZE_BYTES,
+ help="Sets the value of TVM_WORKSPACE_SIZE_BYTES.",
),
],
)
@@ -90,7 +90,7 @@ class Handler(server.ProjectAPIHandler):
):
"""Generate Makefile from template."""
flags = {
- "MEMORY_SIZE_BYTES": str(memory_size),
+ "TVM_WORKSPACE_SIZE_BYTES": str(memory_size),
}
regex = re.compile(r"([A-Z_]+) := (<[A-Z_]+>)")
@@ -106,6 +106,7 @@ class Handler(server.ProjectAPIHandler):
def generate_project(self, model_library_format_path, standalone_crt_dir,
project_dir, options):
# Make project directory.
project_dir.mkdir(parents=True)
+ current_dir = pathlib.Path(__file__).parent.absolute()
# Copy ourselves to the generated project. TVM may perform further
build steps on the generated project
# by launching the copy.
@@ -135,25 +136,29 @@ class Handler(server.ProjectAPIHandler):
# Populate Makefile
self._populate_makefile(
- pathlib.Path(__file__).parent / f"{MAKEFILE_FILENAME}.template",
+ current_dir / f"{MAKEFILE_FILENAME}.template",
project_dir / MAKEFILE_FILENAME,
- options.get("memory_size_bytes", MEMORY_SIZE_BYTES),
+ options.get("workspace_size_bytes", WORKSPACE_SIZE_BYTES),
)
# Populate crt-config.h
crt_config_dir = project_dir / "crt_config"
crt_config_dir.mkdir()
shutil.copy2(
- os.path.join(os.path.dirname(__file__), "crt_config-template.h"),
- os.path.join(crt_config_dir, "crt_config.h"),
+ current_dir / "crt_config" / "crt_config-template.h",
+ crt_config_dir / "crt_config.h",
)
# Populate src/
- src_dir = os.path.join(project_dir, "src")
- os.mkdir(src_dir)
+ src_dir = project_dir / "src"
+ src_dir.mkdir()
shutil.copy2(
- os.path.join(os.path.dirname(__file__), "src", "main.cc"),
- os.path.join(src_dir, "main.cc"),
+ current_dir / "src" / "main.cc",
+ src_dir / "main.cc",
+ )
+ shutil.copy2(
+ current_dir / "src" / "platform.cc",
+ src_dir / "platform.cc",
)
def build(self, options):
diff --git a/src/runtime/crt/host/main.cc b/src/runtime/crt/host/platform.cc
similarity index 56%
copy from src/runtime/crt/host/main.cc
copy to src/runtime/crt/host/platform.cc
index e9f6813f9b..f5af08a9be 100644
--- a/src/runtime/crt/host/main.cc
+++ b/src/runtime/crt/host/platform.cc
@@ -18,62 +18,56 @@
*/
/*!
- * \file main.cc
- * \brief main entry point for host subprocess-based CRT
+ * \brief Implementation of TVMPlatform functions in tvm/runtime/crt/platform.h
*/
+
+#include <dlpack/dlpack.h>
#include <inttypes.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <time.h>
-#include <tvm/runtime/c_runtime_api.h>
-#include <tvm/runtime/crt/logging.h>
-#include <tvm/runtime/crt/microtvm_rpc_server.h>
+#include <tvm/runtime/crt/error_codes.h>
#include <tvm/runtime/crt/page_allocator.h>
#include <unistd.h>
#include <chrono>
#include <iostream>
-#include "crt_config.h"
-
-#ifdef TVM_HOST_USE_GRAPH_EXECUTOR_MODULE
-#include <tvm/runtime/crt/graph_executor_module.h>
-#endif
-
-#include <tvm/runtime/crt/aot_executor_module.h>
-
using namespace std::chrono;
extern "C" {
-ssize_t MicroTVMWriteFunc(void* context, const uint8_t* data, size_t
num_bytes) {
- ssize_t to_return = write(STDOUT_FILENO, data, num_bytes);
- fflush(stdout);
- fsync(STDOUT_FILENO);
- return to_return;
-}
+uint8_t memory[TVM_WORKSPACE_SIZE_BYTES];
+MemoryManagerInterface* memory_manager;
-size_t TVMPlatformFormatMessage(char* out_buf, size_t out_buf_size_bytes,
const char* fmt,
- va_list args) {
- return vsnprintf(out_buf, out_buf_size_bytes, fmt, args);
-}
+steady_clock::time_point g_microtvm_start_time;
+int g_microtvm_timer_running = 0;
+// Called when an internal error occurs and execution cannot continue.
void TVMPlatformAbort(tvm_crt_error_t error_code) {
std::cerr << "TVMPlatformAbort: " << error_code << std::endl;
throw "Aborted";
}
-MemoryManagerInterface* memory_manager;
+// Called by the microTVM RPC server to implement TVMLogf.
+size_t TVMPlatformFormatMessage(char* out_buf, size_t out_buf_size_bytes,
const char* fmt,
+ va_list args) {
+ return vsprintf(out_buf, fmt, args);
+}
+// Allocate memory for use by TVM.
tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLDevice dev,
void** out_ptr) {
return memory_manager->Allocate(memory_manager, num_bytes, dev, out_ptr);
}
+// Free memory used by TVM.
tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice dev) {
return memory_manager->Free(memory_manager, ptr, dev);
}
-steady_clock::time_point g_microtvm_start_time;
-int g_microtvm_timer_running = 0;
-
+// Start a device timer.
tvm_crt_error_t TVMPlatformTimerStart() {
if (g_microtvm_timer_running) {
std::cerr << "timer already running" << std::endl;
@@ -84,6 +78,7 @@ tvm_crt_error_t TVMPlatformTimerStart() {
return kTvmErrorNoError;
}
+// Stop the running device timer and get the elapsed time (in microseconds).
tvm_crt_error_t TVMPlatformTimerStop(double* elapsed_time_seconds) {
if (!g_microtvm_timer_running) {
std::cerr << "timer not running" << std::endl;
@@ -97,8 +92,15 @@ tvm_crt_error_t TVMPlatformTimerStop(double*
elapsed_time_seconds) {
return kTvmErrorNoError;
}
+// Platform-specific before measurement call.
+tvm_crt_error_t TVMPlatformBeforeMeasurement() { return kTvmErrorNoError; }
+
+// Platform-specific after measurement call.
+tvm_crt_error_t TVMPlatformAfterMeasurement() { return kTvmErrorNoError; }
+
static_assert(RAND_MAX >= (1 << 8), "RAND_MAX is smaller than acceptable");
unsigned int random_seed = 0;
+// Fill a buffer with random data.
tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer, size_t num_bytes) {
if (random_seed == 0) {
random_seed = (unsigned int)time(NULL);
@@ -107,74 +109,18 @@ tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t*
buffer, size_t num_bytes) {
int random = rand_r(&random_seed);
buffer[i] = (uint8_t)random;
}
-
return kTvmErrorNoError;
}
-}
-
-uint8_t memory[MEMORY_SIZE_BYTES];
-
-static char** g_argv = NULL;
-
-int testonly_reset_server(TVMValue* args, int* type_codes, int num_args,
TVMValue* out_ret_value,
- int* out_ret_tcode, void* resource_handle) {
- execvp(g_argv[0], g_argv);
- perror("microTVM runtime: error restarting");
- return -1;
-}
-int main(int argc, char** argv) {
- g_argv = argv;
+// Initialize TVM inference.
+tvm_crt_error_t TVMPlatformInitialize() {
int status =
PageMemoryManagerCreate(&memory_manager, memory, sizeof(memory), 8 /*
page_size_log2 */);
if (status != 0) {
fprintf(stderr, "error initiailizing memory manager\n");
- return 2;
- }
-
- microtvm_rpc_server_t rpc_server = MicroTVMRpcServerInit(&MicroTVMWriteFunc,
nullptr);
-
-#ifdef TVM_HOST_USE_GRAPH_EXECUTOR_MODULE
- CHECK_EQ(TVMGraphExecutorModule_Register(), kTvmErrorNoError,
- "failed to register GraphExecutor TVMModule");
-#endif
-
- int error = TVMFuncRegisterGlobal("tvm.testing.reset_server",
- (TVMFunctionHandle)&testonly_reset_server,
0);
- if (error) {
- fprintf(
- stderr,
- "microTVM runtime: internal error (error#: %x) registering global
packedfunc; exiting\n",
- error);
- return 2;
+ return kTvmErrorPlatformMemoryManagerInitialized;
}
-
- setbuf(stdin, NULL);
- setbuf(stdout, NULL);
-
- for (;;) {
- uint8_t c;
- int ret_code = read(STDIN_FILENO, &c, 1);
- if (ret_code < 0) {
- perror("microTVM runtime: read failed");
- return 2;
- } else if (ret_code == 0) {
- fprintf(stderr, "microTVM runtime: 0-length read, exiting!\n");
- return 2;
- }
- uint8_t* cursor = &c;
- size_t bytes_to_process = 1;
- while (bytes_to_process > 0) {
- tvm_crt_error_t err = MicroTVMRpcServerLoop(rpc_server, &cursor,
&bytes_to_process);
- if (err == kTvmErrorPlatformShutdown) {
- break;
- } else if (err != kTvmErrorNoError) {
- char buf[1024];
- snprintf(buf, sizeof(buf), "microTVM runtime: MicroTVMRpcServerLoop
error: %08x", err);
- perror(buf);
- return 2;
- }
- }
- }
- return 0;
+ return kTvmErrorNoError;
}
+
+} // extern C
diff --git a/src/runtime/crt/platform-template.c
b/src/runtime/crt/platform-template.c
new file mode 100644
index 0000000000..b93fd1459b
--- /dev/null
+++ b/src/runtime/crt/platform-template.c
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \brief Implementation of TVMPlatform functions in tvm/runtime/crt/platform.h
+ */
+
+#include <dlpack/dlpack.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <tvm/runtime/crt/error_codes.h>
+#include <tvm/runtime/crt/page_allocator.h>
+
+uint8_t memory[TVM_WORKSPACE_SIZE_BYTES];
+MemoryManagerInterface* memory_manager;
+
+// Called when an internal error occurs and execution cannot continue.
+void TVMPlatformAbort(tvm_crt_error_t error_code) { exit(1); }
+
+// Called by the microTVM RPC server to implement TVMLogf.
+size_t TVMPlatformFormatMessage(char* out_buf, size_t out_buf_size_bytes,
const char* fmt,
+ va_list args) {
+ return vsprintf(out_buf, fmt, args);
+}
+
+// Allocate memory for use by TVM.
+tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLDevice dev,
void** out_ptr) {
+ return memory_manager->Allocate(memory_manager, num_bytes, dev, out_ptr);
+}
+
+// Free memory used by TVM.
+tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice dev) {
+ return memory_manager->Free(memory_manager, ptr, dev);
+}
+
+// Start a device timer.
+tvm_crt_error_t TVMPlatformTimerStart() { return kTvmErrorNoError; }
+
+// Stop the running device timer and get the elapsed time (in microseconds).
+tvm_crt_error_t TVMPlatformTimerStop(double* elapsed_time_seconds) { return
kTvmErrorNoError; }
+
+// Platform-specific before measurement call.
+tvm_crt_error_t TVMPlatformBeforeMeasurement() { return kTvmErrorNoError; }
+
+// Platform-specific after measurement call.
+tvm_crt_error_t TVMPlatformAfterMeasurement() { return kTvmErrorNoError; }
+
+// Fill a buffer with random data.
+tvm_crt_error_t TVMPlatformGenerateRandom(uint8_t* buffer, size_t num_bytes) {
+ return kTvmErrorNoError;
+}
+
+// Initialize TVM inference.
+tvm_crt_error_t TVMPlatformInitialize() {
+ int status =
+ PageMemoryManagerCreate(&memory_manager, memory, sizeof(memory), 8 /*
page_size_log2 */);
+ if (status != 0) {
+ fprintf(stderr, "error initiailizing memory manager\n");
+ return kTvmErrorPlatformMemoryManagerInitialized;
+ }
+ return kTvmErrorNoError;
+}
diff --git a/tests/micro/arduino/test_arduino_workflow.py
b/tests/micro/arduino/test_arduino_workflow.py
index 42874ad6c3..73cdd9b85d 100644
--- a/tests/micro/arduino/test_arduino_workflow.py
+++ b/tests/micro/arduino/test_arduino_workflow.py
@@ -71,7 +71,7 @@ def test_project_folder_structure(project_dir, project):
source_dir = project_dir / "src"
assert _get_directory_elements(source_dir) == set(
- ["model", "standalone_crt", "model.c", "model.h"]
+ ["model", "standalone_crt", "platform.c", "platform.h"]
)
@@ -82,15 +82,15 @@ def test_project_model_integrity(project_dir, project):
)
-def test_model_header_templating(project_dir, project):
- # Ensure model.h was templated with correct WORKSPACE_SIZE
- with (project_dir / "src" / "model.h").open() as f:
- model_h = f.read()
- workspace_size_defs = re.findall(r"\#define WORKSPACE_SIZE ([0-9]*)",
model_h)
+def test_model_platform_templating(project_dir, project):
+ # Ensure platform.c was templated with correct TVM_WORKSPACE_SIZE_BYTES
+ with (project_dir / "src" / "platform.c").open() as f:
+ platform_c = f.read()
+ workspace_size_defs = re.findall(r"\#define TVM_WORKSPACE_SIZE_BYTES
([0-9]*)", platform_c)
assert workspace_size_defs
assert len(workspace_size_defs) == 1
- # Make sure the WORKSPACE_SIZE we define is a reasonable size. We
don't want
+ # Make sure the TVM_WORKSPACE_SIZE_BYTES we define is a reasonable
size. We don't want
# to set an exact value, as this test shouldn't break if an
improvement to
# TVM causes the amount of memory needed to decrease.
workspace_size = int(workspace_size_defs[0])
diff --git a/tests/micro/arduino/testdata/project.ino
b/tests/micro/arduino/testdata/project.ino
index ebd1c5e0e6..d7ef155b33 100644
--- a/tests/micro/arduino/testdata/project.ino
+++ b/tests/micro/arduino/testdata/project.ino
@@ -17,11 +17,12 @@
* under the License.
*/
-#include "src/model.h"
+#include "src/platform.h"
#include "src/data/yes.c"
#include "src/data/no.c"
#include "src/data/unknown.c"
#include "src/data/silence.c"
+#include "src/standalone_crt/include/tvm/runtime/crt/platform.h"
void performInference(int8_t input_data[1960], char *data_name) {
int8_t output_data[4];
@@ -41,7 +42,7 @@ void performInference(int8_t input_data[1960], char
*data_name) {
}
void setup() {
- TVMInitialize();
+ TVMPlatformInitialize();
Serial.begin(115200);
}
diff --git a/tests/micro/zephyr/test_zephyr.py
b/tests/micro/zephyr/test_zephyr.py
index 59c4cab881..79e4f46e0f 100644
--- a/tests/micro/zephyr/test_zephyr.py
+++ b/tests/micro/zephyr/test_zephyr.py
@@ -608,5 +608,41 @@ def
test_schedule_build_with_cmsis_dependency(workspace_dir, board, microtvm_deb
assert "CMSIS-NN/Include" in cmake_content
[email protected]_micro
+def test_debugging_enabled(workspace_dir):
+ """Test debugging enabled for LED. `verbose=True` in project option enables
+ debugging. For this test a physical board(nucleo_l4r5zi) is used instead of
+ QEMU since LED config is not available on QEMU.
+ """
+ board = "nucleo_l4r5zi"
+ project_options = {
+ "project_type": "host_driven",
+ "board": board,
+ "verbose": True,
+ }
+ shape = (10,)
+ dtype = "int8"
+ x = relay.var("x", relay.TensorType(shape=shape, dtype=dtype))
+ xx = relay.multiply(x, x)
+ z = relay.add(xx, relay.const(np.ones(shape=shape, dtype=dtype)))
+ func = relay.Function([x], z)
+ ir_mod = tvm.IRModule.from_expr(func)
+
+ runtime = Runtime("crt", {"system-lib": True})
+ executor = Executor("aot")
+ target = tvm.micro.testing.get_target("zephyr", board)
+
+ with tvm.transform.PassContext(opt_level=3,
config={"tir.disable_vectorize": True}):
+ mod = tvm.relay.build(ir_mod, target=target, runtime=runtime,
executor=executor)
+
+ project = tvm.micro.generate_project(
+ str(utils.TEMPLATE_PROJECT_DIR),
+ mod,
+ workspace_dir / "project",
+ project_options,
+ )
+ project.build()
+
+
if __name__ == "__main__":
tvm.testing.main()
diff --git a/tests/micro/zephyr/test_zephyr_aot_exec_standalone.py
b/tests/micro/zephyr/test_zephyr_aot_exec_standalone.py
index 16c1f9e308..8c6bc272f0 100644
--- a/tests/micro/zephyr/test_zephyr_aot_exec_standalone.py
+++ b/tests/micro/zephyr/test_zephyr_aot_exec_standalone.py
@@ -63,7 +63,9 @@ def test_tflite(workspace_dir, board, microtvm_debug,
serial_number):
"aot", {"unpacked-api": True, "interface-api": "c",
"workspace-byte-alignment": 4}
)
runtime = Runtime("crt")
- with tvm.transform.PassContext(opt_level=3,
config={"tir.disable_vectorize": True}):
+ with tvm.transform.PassContext(
+ opt_level=3, config={"tir.disable_vectorize": True, "tir.usmp.enable":
True}
+ ):
lowered = relay.build(relay_mod, target, params=params,
runtime=runtime, executor=executor)
sample_url =
"https://github.com/tlc-pack/web-data/raw/967fc387dadb272c5a7f8c3461d34c060100dbf1/testdata/microTVM/data/keyword_spotting_int8_6.pyc.npy"
diff --git a/tests/micro/zephyr/utils.py b/tests/micro/zephyr/utils.py
index 26f9d6a10e..fdd873c8e8 100644
--- a/tests/micro/zephyr/utils.py
+++ b/tests/micro/zephyr/utils.py
@@ -153,8 +153,8 @@ def generate_project(
with tempfile.NamedTemporaryFile() as tar_temp_file:
with tarfile.open(tar_temp_file.name, "w:gz") as tf:
with tempfile.TemporaryDirectory() as tar_temp_dir:
- model_files_path = os.path.join(tar_temp_dir, "include")
- os.mkdir(model_files_path)
+ model_files_path = pathlib.Path(tar_temp_dir) / "include"
+ model_files_path.mkdir(parents=True)
if load_cmsis:
loadCMSIS(model_files_path)
tf.add(
@@ -174,9 +174,9 @@ def generate_project(
)
tf.add(header_path, arcname=os.path.relpath(header_path,
tar_temp_dir))
- create_header_file("input_data", sample, "include", tf)
+ create_header_file("input_data", sample, "include/tvm", tf)
create_header_file(
- "output_data", np.zeros(shape=output_shape,
dtype=output_type), "include", tf
+ "output_data", np.zeros(shape=output_shape,
dtype=output_type), "include/tvm", tf
)
project, project_dir = build_project(
diff --git a/tests/python/unittest/test_micro_model_library_format.py
b/tests/python/unittest/test_micro_model_library_format.py
index 734404fb34..6f79723de4 100644
--- a/tests/python/unittest/test_micro_model_library_format.py
+++ b/tests/python/unittest/test_micro_model_library_format.py
@@ -715,5 +715,30 @@ def test_output_names_many():
}
[email protected]_micro
+def test_template_files():
+ """Check template files in generated model library format."""
+ mod = get_conv2d_relay_module()
+
+ executor = Executor("aot", {"unpacked-api": True, "interface-api": "c"})
+ runtime = Runtime("crt")
+ target = tvm.target.target.micro("host")
+
+ with tvm.transform.PassContext(opt_level=3,
config={"tir.disable_vectorize": True}):
+ factory = tvm.relay.build(mod, target, runtime=runtime,
executor=executor, mod_name="mod")
+
+ temp_dir = utils.tempdir()
+ mlf_tar_path = temp_dir / "lib.tar"
+ micro.export_model_library_format(factory, mlf_tar_path)
+
+ tf = tarfile.open(mlf_tar_path)
+ extract_dir = temp_dir / "extract"
+ os.mkdir(extract_dir)
+ tf.extractall(extract_dir)
+
+ assert (extract_dir / "templates" / "crt_config.h.template").is_file()
+ assert (extract_dir / "templates" / "platform.c.template").is_file()
+
+
if __name__ == "__main__":
tvm.testing.main()