diff --git a/apps/microtvm/zephyr/demo_runtime/CMakeLists.txt b/apps/microtvm/zephyr/aot_demo/CMakeLists.txt similarity index 88% rename from apps/microtvm/zephyr/demo_runtime/CMakeLists.txt rename to apps/microtvm/zephyr/aot_demo/CMakeLists.txt index a99d5edb07e6..d7ec2a25db14 100644 --- a/apps/microtvm/zephyr/demo_runtime/CMakeLists.txt +++ b/apps/microtvm/zephyr/aot_demo/CMakeLists.txt @@ -10,8 +10,9 @@ find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) project(microtvm_zephyr_runtime) set(CMAKE_VERBOSE_MAKEFILE ON) -file(GLOB TVM_SOURCES ${CMAKE_SOURCE_DIR}/__tvm*.c) -target_sources(app PRIVATE src/main.c ${TVM_SOURCES}) + +target_sources(app PRIVATE src/zephyr_uart.c) +target_sources(app PRIVATE src/main.c) foreach(tvm_lib ${TVM_LIBS}) string(LENGTH ${tvm_lib} tvm_lib_length) diff --git a/apps/microtvm/zephyr/aot_demo/README.md b/apps/microtvm/zephyr/aot_demo/README.md new file mode 100644 index 000000000000..a718da65e2fa --- /dev/null +++ b/apps/microtvm/zephyr/aot_demo/README.md @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + +This directory contains a Zephyr-based ahead of time (AOT) "demo" runtime environment that +pulls together the microTVM runtime dependencies into a single application +that can run TVM on a microTVM device without the need to a host. diff --git a/apps/microtvm/zephyr/demo_runtime/boards/mps2_an521.conf b/apps/microtvm/zephyr/aot_demo/boards/mps2_an521.conf similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/boards/mps2_an521.conf rename to apps/microtvm/zephyr/aot_demo/boards/mps2_an521.conf diff --git a/apps/microtvm/zephyr/aot_demo/boards/nrf5340dk_nrf5340_cpuapp.conf b/apps/microtvm/zephyr/aot_demo/boards/nrf5340dk_nrf5340_cpuapp.conf new file mode 100644 index 000000000000..d298325eb4a4 --- /dev/null +++ b/apps/microtvm/zephyr/aot_demo/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -0,0 +1,31 @@ +# 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. +# +# This file is specific to the nRF5340 DK board. + +# For intrinsics used by generated optimized operators. +CONFIG_CMSIS_DSP=y + +# For AOT runtime which requires lots of function call. +CONFIG_MAIN_STACK_SIZE=2000 + +# For random number generation. +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y + +# For debugging. +CONFIG_LED=y diff --git a/apps/microtvm/zephyr/aot_demo/boards/qemu_x86.conf b/apps/microtvm/zephyr/aot_demo/boards/qemu_x86.conf new file mode 100644 index 000000000000..5f3c4a4bed36 --- /dev/null +++ b/apps/microtvm/zephyr/aot_demo/boards/qemu_x86.conf @@ -0,0 +1,25 @@ +# 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. + +# This file is specific to the QEMU-emulated microTVM board. + +# For TVMPlatformGenerateRandom(). Remember, these values do not need to be truly random. +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_TIMER_RANDOM_GENERATOR=y + +# Default stack size is 1k, this is required for debug mode. +CONFIG_MAIN_STACK_SIZE=2000 diff --git a/apps/microtvm/zephyr/aot_demo/crt/crt_config.h b/apps/microtvm/zephyr/aot_demo/crt/crt_config.h new file mode 100644 index 000000000000..9ee315aa1763 --- /dev/null +++ b/apps/microtvm/zephyr/aot_demo/crt/crt_config.h @@ -0,0 +1,62 @@ +/* + * 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. + */ + +/*! + * \file tvm/runtime/crt_config.h.template + * \brief Template for CRT configuration, to be modified on each target. + */ +#ifndef TVM_RUNTIME_CRT_CONFIG_H_ +#define TVM_RUNTIME_CRT_CONFIG_H_ + +#include + +/*! Log level of the CRT runtime */ +#define TVM_CRT_LOG_LEVEL TVM_CRT_LOG_LEVEL_DEBUG + +/*! Maximum supported dimension in NDArray */ +#define TVM_CRT_MAX_NDIM 6 + +/*! Maximum supported arguments in generated functions */ +#define TVM_CRT_MAX_ARGS 10 + +/*! Size of the global function registry, in bytes. */ +#define TVM_CRT_GLOBAL_FUNC_REGISTRY_SIZE_BYTES 200 + +/*! Maximum number of registered modules. */ +#define TVM_CRT_MAX_REGISTERED_MODULES 2 + +/*! Maximum packet size, in bytes, including the length header. */ +#define TVM_CRT_MAX_PACKET_SIZE_BYTES (1 * 1024) + +/*! Maximum supported string length in dltype, e.g. "int8", "int16", "float32" */ +#define TVM_CRT_MAX_STRLEN_DLTYPE 10 + +/*! Maximum supported string length in function names */ +#define TVM_CRT_MAX_STRLEN_FUNCTION_NAME 80 + +/*! \brief Maximum length of a PackedFunc function name. */ +#define TVM_CRT_MAX_FUNCTION_NAME_LENGTH_BYTES 30 + +/*! \brief Log2 of the page size (bytes) for a virtual memory page. */ +#define TVM_CRT_PAGE_BITS 10 // 1 kB + +/*! \brief Number of pages on device. */ +#define TVM_CRT_MAX_PAGES 300 + +#endif // TVM_RUNTIME_CRT_CONFIG_H_ diff --git a/apps/microtvm/zephyr/aot_demo/include/zephyr_uart.h b/apps/microtvm/zephyr/aot_demo/include/zephyr_uart.h new file mode 100644 index 000000000000..f24ade734c4f --- /dev/null +++ b/apps/microtvm/zephyr/aot_demo/include/zephyr_uart.h @@ -0,0 +1,50 @@ +/* + * 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_DEMO_INCLUDE_ZEPHYR_UART_H_ +#define TVM_APPS_MICROTVM_ZEPHYR_AOT_DEMO_INCLUDE_ZEPHYR_UART_H_ + +#include + +// 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_DEMO_INCLUDE_ZEPHYR_UART_H_ */ diff --git a/apps/microtvm/zephyr/demo_runtime/prj.conf b/apps/microtvm/zephyr/aot_demo/prj.conf similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/prj.conf rename to apps/microtvm/zephyr/aot_demo/prj.conf diff --git a/apps/microtvm/zephyr/aot_demo/qemu-hack b/apps/microtvm/zephyr/aot_demo/qemu-hack new file mode 120000 index 000000000000..b4810f2aab6e --- /dev/null +++ b/apps/microtvm/zephyr/aot_demo/qemu-hack @@ -0,0 +1 @@ +../qemu-hack \ No newline at end of file diff --git a/apps/microtvm/zephyr/aot_demo/src/main.c b/apps/microtvm/zephyr/aot_demo/src/main.c new file mode 100644 index 000000000000..b92366a7098b --- /dev/null +++ b/apps/microtvm/zephyr/aot_demo/src/main.c @@ -0,0 +1,228 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "input_data.h" +#include "output_data.h" +#include "zephyr_uart.h" + +#ifdef CONFIG_ARCH_POSIX +#include "posix_board_if.h" +#endif + +#define WORKSPACE_SIZE (270 * 1024) + +static uint8_t g_aot_memory[WORKSPACE_SIZE]; +extern tvm_model_t network; +tvm_workspace_t app_workspace; + +// Wakeup sequence used to wake up QEMU on the host. +const unsigned char g_wakeup_sequence[12] = {0xfe, 0xff, 0xfd, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x66, 0x77}; +const char g_start_cmd[] = "start\n"; + +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); + 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; } + +#define MILLIS_TIL_EXPIRY 200 +#define TIME_TIL_EXPIRY (K_MSEC(MILLIS_TIL_EXPIRY)) +struct k_timer g_utvm_timer; +uint32_t g_utvm_start_time; +int g_utvm_timer_running = 0; + +// Called to start system timer. +tvm_crt_error_t TVMPlatformTimerStart() { + if (g_utvm_timer_running) { + TVMLogf("timer already running"); + return kTvmErrorPlatformTimerBadState; + } + + k_timer_start(&g_utvm_timer, TIME_TIL_EXPIRY, TIME_TIL_EXPIRY); + g_utvm_start_time = k_cycle_get_32(); + g_utvm_timer_running = 1; + return kTvmErrorNoError; +} + +// Called to stop system timer. +tvm_crt_error_t TVMPlatformTimerStop(double* elapsed_time_seconds) { + if (!g_utvm_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_utvm_start_time; + if (stop_time < g_utvm_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_utvm_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_utvm_timer); + k_timer_stop(&g_utvm_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_utvm_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; + } + + g_utvm_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 cmd_buf[128]; +static size_t g_cmd_buf_ind; + +void main(void) { + g_cmd_buf_ind = 0; + memset((char*)cmd_buf, 0, sizeof(cmd_buf)); + TVMPlatformUARTInit(); + k_timer_init(&g_utvm_timer, NULL, NULL); + // Wake up host side. + TVMPlatformWriteSerial(g_wakeup_sequence, sizeof(g_wakeup_sequence)); + + // Wait for start command + while (true) { + int bytes_read = TVMPlatformUartRxRead(main_rx_buf, sizeof(main_rx_buf)); + if (bytes_read > 0) { + memcpy((char*)cmd_buf + g_cmd_buf_ind, main_rx_buf, bytes_read); + g_cmd_buf_ind += bytes_read; + } + if (g_cmd_buf_ind >= 6) { + if (!strcmp((char*)(cmd_buf), g_start_cmd)) { + break; + } else { + memset((char*)cmd_buf, 0, sizeof(cmd_buf)); + g_cmd_buf_ind = 0; + } + } + } + TVMLogf("Zephyr AOT Runtime\n"); + + void* inputs[1] = { + input_data, + }; + void* outputs[1] = { + output_data, + }; + + StackMemoryManager_Init(&app_workspace, g_aot_memory, WORKSPACE_SIZE); + + double elapsed_time = 0; + TVMPlatformTimerStart(); + int ret_val = tvm_runtime_run(&network, 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)); +#ifdef CONFIG_ARCH_POSIX + posix_exit(0); +#endif +} diff --git a/apps/microtvm/zephyr/aot_demo/src/zephyr_uart.c b/apps/microtvm/zephyr/aot_demo/src/zephyr_uart.c new file mode 100644 index 000000000000..1f4dde1de4b9 --- /dev/null +++ b/apps/microtvm/zephyr/aot_demo/src/zephyr_uart.c @@ -0,0 +1,81 @@ +/* + * 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 +#include + +#include "crt_config.h" + +static const struct device* g_utvm_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_utvm_uart, data[i]); + } + return size; +} + +// Initialize UART +void TVMPlatformUARTInit() { + // Claim console device. + g_utvm_uart = device_get_binding(DT_LABEL(DT_CHOSEN(zephyr_console))); + uart_rx_init(&uart_rx_rbuf, g_utvm_uart); +} diff --git a/apps/microtvm/zephyr/host_driven/CMakeLists.txt b/apps/microtvm/zephyr/host_driven/CMakeLists.txt new file mode 100644 index 000000000000..f04a792086cb --- /dev/null +++ b/apps/microtvm/zephyr/host_driven/CMakeLists.txt @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.13.1) + +set(ENV{QEMU_BIN_PATH} "${CMAKE_SOURCE_DIR}/qemu-hack") + +set(QEMU_PIPE "\${QEMU_PIPE}") # QEMU_PIPE is set by the calling TVM instance. + +find_package(Zephyr HINTS $ENV{ZEPHYR_BASE}) +project(microtvm_zephyr_runtime) + +set(CMAKE_VERBOSE_MAKEFILE ON) + +target_sources(app PRIVATE src/main.c) + +foreach(tvm_lib ${TVM_LIBS}) + string(LENGTH ${tvm_lib} tvm_lib_length) + math(EXPR tvm_lib_cut "${tvm_lib_length} - 2") + string(SUBSTRING ${tvm_lib} 3 ${tvm_lib_cut} tvm_lib_name) + add_library(${tvm_lib_name} STATIC IMPORTED) + set_target_properties(${tvm_lib_name} PROPERTIES + IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/${tvm_lib}) + target_link_libraries(app PRIVATE ${tvm_lib_name}) +endforeach(tvm_lib ${TVM_LIBS}) + +target_include_directories(app PRIVATE ${TVM_INCLUDE_DIRS}) diff --git a/apps/microtvm/zephyr/demo_runtime/README.md b/apps/microtvm/zephyr/host_driven/README.md similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/README.md rename to apps/microtvm/zephyr/host_driven/README.md diff --git a/apps/microtvm/zephyr/host_driven/boards/mps2_an521.conf b/apps/microtvm/zephyr/host_driven/boards/mps2_an521.conf new file mode 100644 index 000000000000..3916b17c49cf --- /dev/null +++ b/apps/microtvm/zephyr/host_driven/boards/mps2_an521.conf @@ -0,0 +1,28 @@ +# 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. +# +# This file is specific to the MPS2-AN512 board. + +# For intrinsics used by generated optimized operators. +CONFIG_CMSIS_DSP=y + +# For random number generation. +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y + +# For debugging. +CONFIG_LED=n diff --git a/apps/microtvm/zephyr/demo_runtime/boards/nrf5340dk_nrf5340_cpuapp.conf b/apps/microtvm/zephyr/host_driven/boards/nrf5340dk_nrf5340_cpuapp.conf similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/boards/nrf5340dk_nrf5340_cpuapp.conf rename to apps/microtvm/zephyr/host_driven/boards/nrf5340dk_nrf5340_cpuapp.conf diff --git a/apps/microtvm/zephyr/demo_runtime/boards/nucleo_f746zg.conf b/apps/microtvm/zephyr/host_driven/boards/nucleo_f746zg.conf similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/boards/nucleo_f746zg.conf rename to apps/microtvm/zephyr/host_driven/boards/nucleo_f746zg.conf diff --git a/apps/microtvm/zephyr/demo_runtime/boards/qemu_riscv32.conf b/apps/microtvm/zephyr/host_driven/boards/qemu_riscv32.conf similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/boards/qemu_riscv32.conf rename to apps/microtvm/zephyr/host_driven/boards/qemu_riscv32.conf diff --git a/apps/microtvm/zephyr/demo_runtime/boards/qemu_riscv64.conf b/apps/microtvm/zephyr/host_driven/boards/qemu_riscv64.conf similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/boards/qemu_riscv64.conf rename to apps/microtvm/zephyr/host_driven/boards/qemu_riscv64.conf diff --git a/apps/microtvm/zephyr/demo_runtime/boards/qemu_x86.conf b/apps/microtvm/zephyr/host_driven/boards/qemu_x86.conf similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/boards/qemu_x86.conf rename to apps/microtvm/zephyr/host_driven/boards/qemu_x86.conf diff --git a/apps/microtvm/zephyr/demo_runtime/boards/stm32f746g_disco.conf b/apps/microtvm/zephyr/host_driven/boards/stm32f746g_disco.conf similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/boards/stm32f746g_disco.conf rename to apps/microtvm/zephyr/host_driven/boards/stm32f746g_disco.conf diff --git a/apps/microtvm/zephyr/demo_runtime/crt/crt_config.h b/apps/microtvm/zephyr/host_driven/crt/crt_config.h similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/crt/crt_config.h rename to apps/microtvm/zephyr/host_driven/crt/crt_config.h diff --git a/apps/microtvm/zephyr/host_driven/prj.conf b/apps/microtvm/zephyr/host_driven/prj.conf new file mode 100644 index 000000000000..5f4d7a0689dc --- /dev/null +++ b/apps/microtvm/zephyr/host_driven/prj.conf @@ -0,0 +1,35 @@ +# 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. + +# The settings in this file are generic for all boards, and are merged +# with the settings in the file boards/.conf by the Zephyr build +# process. + +# For UART implementation in main(). +CONFIG_RING_BUFFER=y +CONFIG_UART_CONSOLE=n +CONFIG_UART_INTERRUPT_DRIVEN=y + +# For RPC server C++ bindings. +CONFIG_CPLUSPLUS=y +CONFIG_NEWLIB_LIBC=y + +# For models with floating point. +CONFIG_FPU=y + +# For TVMPlatformAbort(). +CONFIG_REBOOT=y diff --git a/apps/microtvm/zephyr/host_driven/qemu-hack b/apps/microtvm/zephyr/host_driven/qemu-hack new file mode 120000 index 000000000000..b4810f2aab6e --- /dev/null +++ b/apps/microtvm/zephyr/host_driven/qemu-hack @@ -0,0 +1 @@ +../qemu-hack \ No newline at end of file diff --git a/apps/microtvm/zephyr/demo_runtime/src/main.c b/apps/microtvm/zephyr/host_driven/src/main.c similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/src/main.c rename to apps/microtvm/zephyr/host_driven/src/main.c diff --git a/apps/microtvm/zephyr/demo_runtime/qemu-hack/qemu-system-arm b/apps/microtvm/zephyr/qemu-hack/qemu-system-arm similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/qemu-hack/qemu-system-arm rename to apps/microtvm/zephyr/qemu-hack/qemu-system-arm diff --git a/apps/microtvm/zephyr/demo_runtime/qemu-hack/qemu-system-i386 b/apps/microtvm/zephyr/qemu-hack/qemu-system-i386 similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/qemu-hack/qemu-system-i386 rename to apps/microtvm/zephyr/qemu-hack/qemu-system-i386 diff --git a/apps/microtvm/zephyr/demo_runtime/qemu-hack/qemu-system-riscv32 b/apps/microtvm/zephyr/qemu-hack/qemu-system-riscv32 similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/qemu-hack/qemu-system-riscv32 rename to apps/microtvm/zephyr/qemu-hack/qemu-system-riscv32 diff --git a/apps/microtvm/zephyr/demo_runtime/qemu-hack/qemu-system-riscv64 b/apps/microtvm/zephyr/qemu-hack/qemu-system-riscv64 similarity index 100% rename from apps/microtvm/zephyr/demo_runtime/qemu-hack/qemu-system-riscv64 rename to apps/microtvm/zephyr/qemu-hack/qemu-system-riscv64 diff --git a/python/tvm/micro/build.py b/python/tvm/micro/build.py index d95f14f0349e..910b0ce1721f 100644 --- a/python/tvm/micro/build.py +++ b/python/tvm/micro/build.py @@ -53,10 +53,6 @@ def path(self): return self.tempdir.temp_dir -# Required C runtime libraries, in link order. -CRT_RUNTIME_LIB_NAMES = ["utvm_rpc_server", "utvm_rpc_common", "common"] - - STANDALONE_CRT_DIR = None @@ -110,9 +106,17 @@ def get_standalone_crt_lib(name: str) -> str: return os.path.join(get_standalone_crt_dir(), "src", "runtime", "crt", name) -def get_runtime_libs() -> str: - """Return abspath to all CRT directories which contain source (i.e. not header) files.""" - return [get_standalone_crt_lib(n) for n in CRT_RUNTIME_LIB_NAMES] +def get_runtime_libs(executor: str) -> str: + """Return abspath to all CRT directories in link order which contain + source (i.e. not header) files. + """ + if executor == "host-driven": + crt_runtime_lib_names = ["utvm_rpc_server", "utvm_rpc_common", "common"] + elif executor == "aot": + crt_runtime_lib_names = ["aot_executor", "common"] + else: + raise ValueError(f"Incorrect executor: {executor}") + return [get_standalone_crt_lib(n) for n in crt_runtime_lib_names] RUNTIME_SRC_REGEX = re.compile(r"^.*\.cc?$", re.IGNORECASE) @@ -188,6 +192,7 @@ def build_static_runtime( compiler, module, compiler_options, + executor=None, extra_libs=None, ): """Build the on-device runtime, statically linking the given modules. @@ -206,6 +211,10 @@ def build_static_runtime( used. This dict contains the `options` parameter passed to Compiler.library() and Compiler.binary() at various stages in the compilation process. + executor : Optional[str] + Executor used for runtime. Based on this we determine the libraries that need to be + linked with runtime. + extra_libs : Optional[List[MicroLibrary|str]] If specified, extra libraries to be compiled into the binary. If a MicroLibrary, it is included into the binary directly. If a string, the path to a directory; all direct children @@ -221,8 +230,11 @@ def build_static_runtime( os.makedirs(mod_build_dir) mod_src_dir = workspace.relpath(os.path.join("src", "module")) + if not executor: + executor = "host-driven" + libs = [] - for mod_or_src_dir in (extra_libs or []) + get_runtime_libs(): + for mod_or_src_dir in (extra_libs or []) + get_runtime_libs(executor): if isinstance(mod_or_src_dir, MicroLibrary): libs.append(mod_or_src_dir) continue diff --git a/python/tvm/target/target.py b/python/tvm/target/target.py index 748b4e8910c1..be39a6f6bd25 100644 --- a/python/tvm/target/target.py +++ b/python/tvm/target/target.py @@ -296,10 +296,13 @@ def micro(model="unknown", options=None): if model not in MICRO_SUPPORTED_MODELS: raise ValueError(f"Model {model} not supported by tvm.target.micro.") opts = _merge_opts( - MICRO_SUPPORTED_MODELS[model] + ["-runtime=c", "--system-lib", f"-model={model}"], + MICRO_SUPPORTED_MODELS[model] + ["-runtime=c", f"-model={model}"], options, ) + if (not options) or (options and "--executor=aot" not in options): + opts = _merge_opts(opts, "--system-lib") + # NOTE: in the future, the default micro target will be LLVM except when # external dependencies are present. return Target(" ".join(["c"] + opts)) diff --git a/tests/lint/check_file_type.py b/tests/lint/check_file_type.py index 967df8d2b7b4..73d06ccf7c4c 100644 --- a/tests/lint/check_file_type.py +++ b/tests/lint/check_file_type.py @@ -129,19 +129,30 @@ "tests/micro/zephyr/testdata/digit-2.jpg", "tests/micro/zephyr/testdata/digit-9.jpg", "tests/micro/zephyr/testdata/mnist-8.onnx", + "tests/micro/zephyr/testdata/ic_sample_fp32_8.npy", # microTVM Zephyr runtime - "apps/microtvm/zephyr/demo_runtime/prj.conf", - "apps/microtvm/zephyr/demo_runtime/boards/qemu_x86.conf", - "apps/microtvm/zephyr/demo_runtime/boards/qemu_riscv32.conf", - "apps/microtvm/zephyr/demo_runtime/boards/qemu_riscv64.conf", - "apps/microtvm/zephyr/demo_runtime/boards/nrf5340dk_nrf5340_cpuapp.conf", - "apps/microtvm/zephyr/demo_runtime/boards/nucleo_f746zg.conf", - "apps/microtvm/zephyr/demo_runtime/boards/stm32f746g_disco.conf", - "apps/microtvm/zephyr/demo_runtime/boards/mps2_an521.conf", - "apps/microtvm/zephyr/demo_runtime/qemu-hack/qemu-system-i386", - "apps/microtvm/zephyr/demo_runtime/qemu-hack/qemu-system-arm", - "apps/microtvm/zephyr/demo_runtime/qemu-hack/qemu-system-riscv32", - "apps/microtvm/zephyr/demo_runtime/qemu-hack/qemu-system-riscv64", + "apps/microtvm/zephyr/qemu-hack/qemu-system-i386", + "apps/microtvm/zephyr/qemu-hack/qemu-system-arm", + "apps/microtvm/zephyr/qemu-hack/qemu-system-riscv32", + "apps/microtvm/zephyr/qemu-hack/qemu-system-riscv64", + "apps/microtvm/zephyr/host_driven/prj.conf", + "apps/microtvm/zephyr/host_driven/boards/qemu_x86.conf", + "apps/microtvm/zephyr/host_driven/boards/qemu_riscv32.conf", + "apps/microtvm/zephyr/host_driven/boards/qemu_riscv64.conf", + "apps/microtvm/zephyr/host_driven/boards/nrf5340dk_nrf5340_cpuapp.conf", + "apps/microtvm/zephyr/host_driven/boards/nucleo_f746zg.conf", + "apps/microtvm/zephyr/host_driven/boards/stm32f746g_disco.conf", + "apps/microtvm/zephyr/host_driven/boards/mps2_an521.conf", + "apps/microtvm/zephyr/host_driven/qemu-hack", + "apps/microtvm/zephyr/aot_demo/prj.conf", + "apps/microtvm/zephyr/aot_demo/boards/qemu_x86.conf", + "apps/microtvm/zephyr/aot_demo/boards/qemu_riscv32.conf", + "apps/microtvm/zephyr/aot_demo/boards/qemu_riscv64.conf", + "apps/microtvm/zephyr/aot_demo/boards/nrf5340dk_nrf5340_cpuapp.conf", + "apps/microtvm/zephyr/aot_demo/boards/nucleo_f746zg.conf", + "apps/microtvm/zephyr/aot_demo/boards/stm32f746g_disco.conf", + "apps/microtvm/zephyr/aot_demo/boards/mps2_an521.conf", + "apps/microtvm/zephyr/aot_demo/qemu-hack", # microTVM Virtual Machines "apps/microtvm/reference-vm/zephyr/Vagrantfile", "apps/microtvm/reference-vm/zephyr/base-box/Vagrantfile.packer-template", diff --git a/tests/micro/zephyr/test_zephyr.py b/tests/micro/zephyr/test_zephyr.py index e217ec39ed1d..fe1eea1dde29 100644 --- a/tests/micro/zephyr/test_zephyr.py +++ b/tests/micro/zephyr/test_zephyr.py @@ -66,10 +66,12 @@ def _make_sess_from_op(model, zephyr_board, west_cmd, op_name, sched, arg_bufs): def _make_session(model, target, zephyr_board, west_cmd, mod): - test_name = f"{os.path.splitext(os.path.abspath(__file__))[0]}_{zephyr_board}" - prev_build = f"{test_name}-last-build.micro-binary" - workspace_root = ( - f'{test_name}_workspace/{datetime.datetime.now().strftime("%Y-%m-%dT%H-%M-%S")}' + parent_dir = os.path.dirname(__file__) + filename = os.path.splitext(os.path.basename(__file__))[0] + prev_build = f"{os.path.join(parent_dir, 'archive')}_{filename}_{zephyr_board}_last_build.micro" + workspace_root = os.path.join( + f"{os.path.join(parent_dir, 'workspace')}_{filename}_{zephyr_board}", + datetime.datetime.now().strftime("%Y-%m-%dT%H-%M-%S"), ) workspace_parent = os.path.dirname(workspace_root) if not os.path.exists(workspace_parent): @@ -78,7 +80,7 @@ def _make_session(model, target, zephyr_board, west_cmd, mod): test_dir = os.path.dirname(os.path.realpath(os.path.expanduser(__file__))) tvm_source_dir = os.path.join(test_dir, "..", "..", "..") - runtime_path = os.path.join(tvm_source_dir, "apps", "microtvm", "zephyr", "demo_runtime") + runtime_path = os.path.join(tvm_source_dir, "apps", "microtvm", "zephyr", "host_driven") compiler = zephyr.ZephyrCompiler( project_dir=runtime_path, board=zephyr_board, @@ -229,7 +231,7 @@ def test_onnx(platform, west_cmd): relay_mod = relay.transform.DynamicToStatic()(relay_mod) # We add the -link-params=1 option to ensure the model parameters are compiled in. - # There is currently a bug preventing the demo_runtime environment from receiving + # There is currently a bug preventing the host_driven environment from receiving # the model weights when set using graph_mod.set_input(). # See: https://github.com/apache/tvm/issues/7567 target = tvm.target.target.micro(model, options=["-link-params=1"]) @@ -395,4 +397,4 @@ def test_byoc_utvm(platform, west_cmd): if __name__ == "__main__": - sys.exit(pytest.main([os.path.dirname(__file__)] + sys.argv[1:])) + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/tests/micro/zephyr/test_zephyr_aot.py b/tests/micro/zephyr/test_zephyr_aot.py new file mode 100644 index 000000000000..516774a5d83c --- /dev/null +++ b/tests/micro/zephyr/test_zephyr_aot.py @@ -0,0 +1,221 @@ +# 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. + +import datetime +from hashlib import new +import logging +import os +import sys +import logging +import pathlib + +import pytest +import numpy as np + +import tvm +import tvm.rpc +import tvm.micro +import tvm.relay as relay + +from tvm.micro.contrib import zephyr +from tvm.contrib import utils +from tvm.contrib.download import download_testdata + +import conftest + +_LOG = logging.getLogger(__name__) + +PLATFORMS = conftest.PLATFORMS + +# If set, build the uTVM binary from scratch on each test. +# Otherwise, reuses the build from the previous test run. +BUILD = True + +# If set, enable a debug session while the test is running. +# Before running the test, in a separate shell, you should run: +# python -m tvm.exec.microtvm_debug_shell +DEBUG = False + + +def _build_session_kw(model, target, zephyr_board, west_cmd, mod, runtime_path): + parent_dir = os.path.dirname(__file__) + filename = os.path.splitext(os.path.basename(__file__))[0] + prev_build = f"{os.path.join(parent_dir, 'archive')}_{filename}_{zephyr_board}_last_build.micro" + workspace_root = os.path.join( + f"{os.path.join(parent_dir, 'workspace')}_{filename}_{zephyr_board}", + datetime.datetime.now().strftime("%Y-%m-%dT%H-%M-%S"), + ) + workspace_parent = os.path.dirname(workspace_root) + if not os.path.exists(workspace_parent): + os.makedirs(workspace_parent) + workspace = tvm.micro.Workspace(debug=True, root=workspace_root) + + compiler = zephyr.ZephyrCompiler( + project_dir=runtime_path, + board=zephyr_board, + zephyr_toolchain_variant="zephyr", + west_cmd=west_cmd, + env_vars={"ZEPHYR_RUNTIME": "ZEPHYR-AOT"}, + ) + + opts = tvm.micro.default_options(os.path.join(runtime_path, "crt")) + opts["bin_opts"]["include_dirs"].append(os.path.join(runtime_path, "include")) + opts["lib_opts"]["include_dirs"].append(os.path.join(runtime_path, "include")) + + flasher_kw = {} + if DEBUG: + flasher_kw["debug_rpc_session"] = tvm.rpc.connect("127.0.0.1", 9090) + + session_kw = { + "flasher": compiler.flasher(**flasher_kw), + } + + if BUILD: + session_kw["binary"] = tvm.micro.build_static_runtime( + workspace, + compiler, + mod, + opts, + executor="aot", + extra_libs=[tvm.micro.get_standalone_crt_lib("memory")], + ) + if os.path.exists(prev_build): + os.unlink(prev_build) + session_kw["binary"].archive(prev_build, metadata_only=True) + else: + unarchive_dir = utils.tempdir() + session_kw["binary"] = tvm.micro.MicroBinary.unarchive( + prev_build, unarchive_dir.relpath("binary") + ) + + return session_kw + + +def _create_header_file(tensor_name, npy_data, output_path): + """ + This method generates a header file containing the data contained in the numpy array provided. + It is used to capture the tensor data (for both inputs and expected outputs). + """ + file_path = pathlib.Path(f"{output_path}/" + tensor_name).resolve() + # create header file + raw_path = file_path.with_suffix(".h").resolve() + with open(raw_path, "w") as header_file: + header_file.write("#include \n") + header_file.write("#include \n") + header_file.write("#include \n") + header_file.write(f"const size_t {tensor_name}_len = {npy_data.size};\n") + + if npy_data.dtype == "int8": + header_file.write(f"int8_t {tensor_name}[] =") + elif npy_data.dtype == "int32": + header_file.write(f"int32_t {tensor_name}[] = ") + elif npy_data.dtype == "uint8": + header_file.write(f"uint8_t {tensor_name}[] = ") + elif npy_data.dtype == "float32": + header_file.write(f"float {tensor_name}[] = ") + + header_file.write("{") + for i in np.ndindex(npy_data.shape): + header_file.write(f"{npy_data[i]}, ") + header_file.write("};\n\n") + + +def _read_line(fd): + data = "" + new_line = False + while True: + if new_line: + break + new_data = fd.read(1, timeout_sec=10) + logging.debug(f"read data: {new_data}") + for item in new_data: + new_c = chr(item) + data = data + new_c + if new_c == "\n": + new_line = True + break + return data + + +def _get_message(fd, expr: str): + while True: + data = _read_line(fd) + logging.debug(f"new line: {data}") + if expr in data: + return data + + +def test_tflite(platform, west_cmd): + """Testing a TFLite model.""" + model, zephyr_board = PLATFORMS[platform] + input_shape = (1, 32, 32, 3) + output_shape = (1, 10) + + this_dir = os.path.dirname(__file__) + tvm_source_dir = os.path.join(this_dir, "..", "..", "..") + runtime_path = os.path.join(tvm_source_dir, "apps", "microtvm", "zephyr", "aot_demo") + model_url = "https://github.com/eembc/ulpmark-ml/raw/fc1499c7cc83681a02820d5ddf5d97fe75d4f663/base_models/ic01/ic01_fp32.tflite" + model_path = download_testdata(model_url, "ic01_fp32.tflite", module="model") + + # Import TFLite model + tflite_model_buf = open(model_path, "rb").read() + try: + import tflite + + tflite_model = tflite.Model.GetRootAsModel(tflite_model_buf, 0) + except AttributeError: + import tflite.Model + + tflite_model = tflite.Model.Model.GetRootAsModel(tflite_model_buf, 0) + + # Load TFLite model and convert to Relay + relay_mod, params = relay.frontend.from_tflite( + tflite_model, shape_dict={"input_1": input_shape}, dtype_dict={"input_1 ": "float32"} + ) + + target = tvm.target.target.micro(model, options=["-link-params=1", "--executor=aot"]) + with tvm.transform.PassContext(opt_level=3, config={"tir.disable_vectorize": True}): + lowered = relay.build(relay_mod, target, params=params) + + # Load sample and generate input/output header files + sample_url = "https://github.com/tlc-pack/web-data/raw/main/testdata/microTVM/data/testdata_image_classification_fp32_8.npy" + sample_path = download_testdata( + sample_url, "testdata_image_classification_fp32_8.npy", module="data" + ) + sample = np.load(sample_path) + model_files_path = os.path.join(runtime_path, "include") + _create_header_file((f"input_data"), sample, model_files_path) + _create_header_file( + "output_data", np.zeros(shape=output_shape, dtype="float32"), model_files_path + ) + + session_kw = _build_session_kw(model, target, zephyr_board, west_cmd, lowered.lib, runtime_path) + transport = session_kw["flasher"].flash(session_kw["binary"]) + transport.open() + transport.write(b"start\n", timeout_sec=5) + + result_line = _get_message(transport, "#result") + result_line = result_line.strip("\n") + result_line = result_line.split(":") + result = int(result_line[1]) + time = int(result_line[2]) + logging.info(f"Result: {result}\ttime: {time} ms") + assert result == 8 + + +if __name__ == "__main__": + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/tutorials/micro/micro_tflite.py b/tutorials/micro/micro_tflite.py index b2896306b7b2..5e517bf062ef 100644 --- a/tutorials/micro/micro_tflite.py +++ b/tutorials/micro/micro_tflite.py @@ -230,7 +230,7 @@ # from tvm.micro.contrib import zephyr # # repo_root = subprocess.check_output(["git", "rev-parse", "--show-toplevel"], encoding='utf-8').strip() -# project_dir = os.path.join(repo_root, "apps", "microtvm", "zephyr", "demo_runtime") +# project_dir = os.path.join(repo_root, "apps", "microtvm", "zephyr", "host_driven") # compiler = zephyr.ZephyrCompiler( # project_dir=project_dir, # board=BOARD,