From 9b46fad039070460d1dfdeccb9327389de0bd137 Mon Sep 17 00:00:00 2001 From: Mohamad Katanbaf Date: Mon, 15 Aug 2022 16:01:04 -0700 Subject: [PATCH] Zephyr: Add support for FVP (#12125) adds corstone300 FVP to the platforms supported by the zephyr. We use the Iris debugger to communicate with the emulator via semihosting, due to the FVP serial port's faulty behavior. also changes the generated micro-projects build system from make to ninja. Co-authored-by: Andrew Reusch --- .../template_project/CMakeLists.txt.template | 2 +- .../fvp-hack/FVP_Corstone_SSE-300_Ethos-U55 | 44 +++ .../template_project/microtvm_api_server.py | 306 ++++++++++++++++-- .../src/host_driven/fvp/semihost.c | 87 +++++ .../src/host_driven/fvp/semihost.h | 38 +++ .../template_project/src/host_driven/main.c | 42 ++- cmake/modules/Zephyr.cmake | 2 + tests/lint/check_file_type.py | 3 +- tests/micro/zephyr/conftest.py | 28 ++ tests/micro/zephyr/test_zephyr.py | 77 +++-- tests/micro/zephyr/test_zephyr_aot_exec.py | 14 +- .../zephyr/test_zephyr_aot_exec_standalone.py | 8 +- tests/scripts/task_python_microtvm.sh | 1 + 13 files changed, 590 insertions(+), 62 deletions(-) create mode 100755 apps/microtvm/zephyr/template_project/fvp-hack/FVP_Corstone_SSE-300_Ethos-U55 create mode 100644 apps/microtvm/zephyr/template_project/src/host_driven/fvp/semihost.c create mode 100644 apps/microtvm/zephyr/template_project/src/host_driven/fvp/semihost.h diff --git a/apps/microtvm/zephyr/template_project/CMakeLists.txt.template b/apps/microtvm/zephyr/template_project/CMakeLists.txt.template index 7f37efc599c2..742433e82d0d 100644 --- a/apps/microtvm/zephyr/template_project/CMakeLists.txt.template +++ b/apps/microtvm/zephyr/template_project/CMakeLists.txt.template @@ -21,7 +21,7 @@ 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. +set(QEMU_PIPE CACHE PATH "Path to QEMU pipe") diff --git a/apps/microtvm/zephyr/template_project/fvp-hack/FVP_Corstone_SSE-300_Ethos-U55 b/apps/microtvm/zephyr/template_project/fvp-hack/FVP_Corstone_SSE-300_Ethos-U55 new file mode 100755 index 000000000000..6325fec9b3b1 --- /dev/null +++ b/apps/microtvm/zephyr/template_project/fvp-hack/FVP_Corstone_SSE-300_Ethos-U55 @@ -0,0 +1,44 @@ +#!/bin/bash -e +# 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. + +set -x + +ARGS=( "$(basename $0)" ) + +if [ "${FVP_BIN_PATH}" != "" ]; then + ARGS=( ${FVP_BIN_PATH}/${ARGS[0]} ) +fi + +ARGS=( "${ARGS[@]}" + --iris-server + --print-port-number + -C cpu0.semihosting-enable=1 + -C mps3_board.telnetterminal0.mode=raw + -C mps3_board.telnetterminal1.mode=raw + -C mps3_board.telnetterminal2.mode=raw + -C mps3_board.telnetterminal0.start_telnet=0 + -C mps3_board.telnetterminal1.start_telnet=0 + -C mps3_board.telnetterminal2.start_telnet=0 + ) + +while [ "$#" -gt 0 ]; do + ARGS=( "${ARGS[@]}" "$1" ) + shift +done + +"${ARGS[@]}" diff --git a/apps/microtvm/zephyr/template_project/microtvm_api_server.py b/apps/microtvm/zephyr/template_project/microtvm_api_server.py index b6114f10988c..c55bd63fa4dd 100644 --- a/apps/microtvm/zephyr/template_project/microtvm_api_server.py +++ b/apps/microtvm/zephyr/template_project/microtvm_api_server.py @@ -29,6 +29,7 @@ import re import shlex import shutil +import struct import subprocess import sys import tarfile @@ -36,6 +37,8 @@ import threading from typing import Union import usb +import psutil +import stat import serial import serial.tools.list_ports @@ -166,6 +169,17 @@ def _find_board_from_cmake_file(cmake_file: Union[str, pathlib.Path]) -> str: return zephyr_board +def _find_platform_from_cmake_file(cmake_file: Union[str, pathlib.Path]) -> str: + emu_platform = None + with open(API_SERVER_DIR / CMAKELIST_FILENAME) as cmake_f: + for line in cmake_f: + set_platform = re.match("set\(EMU_PLATFORM (.*)\)", line) + if set_platform: + emu_platform = set_platform.group(1) + break + return emu_platform + + def _get_device_args(options): flash_runner = _get_flash_runner() @@ -344,6 +358,18 @@ def _get_nrf_device_args(options): type="str", help="Path to the CMSIS directory.", ), + server.ProjectOption( + "arm_fvp_path", + optional=["generate_project", "open_transport"], + type="str", + help="Path to the FVP binary to invoke.", + ), + server.ProjectOption( + "use_fvp", + optional=["generate_project"], + type="bool", + help="Run on the FVP emulator instead of hardware.", + ), ] @@ -436,6 +462,7 @@ def _create_prj_conf(self, project_dir, options): API_SERVER_CRT_LIBS_TOKEN = "" CMAKE_ARGS_TOKEN = "" + QEMU_PIPE_TOKEN = "" CRT_LIBS_BY_PROJECT_TYPE = { "host_driven": "microtvm_rpc_server microtvm_rpc_common aot_executor_module aot_executor common", @@ -483,10 +510,14 @@ def _generate_cmake_args(self, mlf_extracted_path, options) -> str: if options.get("west_cmd"): cmake_args += f"set(WEST {options['west_cmd']})\n" - if self._is_qemu(options["zephyr_board"]): + if self._is_qemu(options["zephyr_board"], options.get("use_fvp")): # Some boards support more than one emulator, so ensure QEMU is set. cmake_args += f"set(EMU_PLATFORM qemu)\n" + if self._is_fvp(options["zephyr_board"], options.get("use_fvp")): + cmake_args += "set(EMU_PLATFORM armfvp)\n" + cmake_args += "set(ARMFVP_FLAGS -I)\n" + cmake_args += f"set(BOARD {options['zephyr_board']})\n" enable_cmsis = self._cmsis_required(mlf_extracted_path) @@ -525,8 +556,10 @@ def generate_project(self, model_library_format_path, standalone_crt_dir, projec os.makedirs(extract_path) tf.extractall(path=extract_path) - if self._is_qemu(options["zephyr_board"]): + if self._is_qemu(options["zephyr_board"], options.get("use_fvp")): shutil.copytree(API_SERVER_DIR / "qemu-hack", project_dir / "qemu-hack") + elif self._is_fvp(options["zephyr_board"], options.get("use_fvp")): + shutil.copytree(API_SERVER_DIR / "fvp-hack", project_dir / "fvp-hack") # Populate CRT. crt_path = project_dir / "crt" @@ -550,6 +583,10 @@ def generate_project(self, model_library_format_path, standalone_crt_dir, projec if self.CMAKE_ARGS_TOKEN in line: line = self._generate_cmake_args(extract_path, options) + if self.QEMU_PIPE_TOKEN in line: + self.qemu_pipe_dir = pathlib.Path(tempfile.mkdtemp()) + line = line.replace(self.QEMU_PIPE_TOKEN, str(self.qemu_pipe_dir / "fifo")) + cmake_f.write(line) if options.get("compile_definitions"): @@ -557,6 +594,9 @@ def generate_project(self, model_library_format_path, standalone_crt_dir, projec for item in flags: cmake_f.write(f"target_compile_definitions(app PUBLIC {item})\n") + if self._is_fvp(options["zephyr_board"], options.get("use_fvp")): + cmake_f.write(f"target_compile_definitions(app PUBLIC -DFVP=1)\n") + self._create_prj_conf(project_dir, options) # Populate crt-config.h @@ -568,7 +608,13 @@ def generate_project(self, model_library_format_path, standalone_crt_dir, projec # Populate src/ src_dir = project_dir / "src" - shutil.copytree(API_SERVER_DIR / "src" / options["project_type"], src_dir) + if options["project_type"] != "host_driven" or self._is_fvp( + options["zephyr_board"], options.get("use_fvp") + ): + shutil.copytree(API_SERVER_DIR / "src" / options["project_type"], src_dir) + else: + src_dir.mkdir() + shutil.copy2(API_SERVER_DIR / "src" / options["project_type"] / "main.c", src_dir) # Populate extra_files if options.get("extra_files_tar"): @@ -578,21 +624,50 @@ def generate_project(self, model_library_format_path, standalone_crt_dir, projec def build(self, options): BUILD_DIR.mkdir() - check_call(["cmake", ".."], cwd=BUILD_DIR) + zephyr_board = _find_board_from_cmake_file(API_SERVER_DIR / CMAKELIST_FILENAME) + emu_platform = _find_platform_from_cmake_file(API_SERVER_DIR / CMAKELIST_FILENAME) + + env = os.environ + if self._is_fvp(zephyr_board, emu_platform == "armfvp"): + env["ARMFVP_BIN_PATH"] = str((API_SERVER_DIR / "fvp-hack").resolve()) + # Note: We need to explicitly modify the file permissions and make it an executable to pass CI tests. + # [To Do]: Move permission change to Build.groovy.j2 + st = os.stat(env["ARMFVP_BIN_PATH"] + "/FVP_Corstone_SSE-300_Ethos-U55") + os.chmod( + env["ARMFVP_BIN_PATH"] + "/FVP_Corstone_SSE-300_Ethos-U55", + st.st_mode | stat.S_IEXEC, + ) + + check_call(["cmake", "-GNinja", ".."], cwd=BUILD_DIR, env=env) - args = ["make", "-j2"] + args = ["ninja"] if options.get("verbose"): - args.append("VERBOSE=1") - check_call(args, cwd=BUILD_DIR) + args.append("-v") + check_call(args, cwd=BUILD_DIR, env=env) # A list of all zephyr_board values which are known to launch using QEMU. Many platforms which # launch through QEMU by default include "qemu" in their name. However, not all do. This list # includes those tested platforms which do not include qemu. - _KNOWN_QEMU_ZEPHYR_BOARDS = ("mps2_an521", "mps3_an547") + _KNOWN_QEMU_ZEPHYR_BOARDS = ["mps2_an521", "mps3_an547"] + + # A list of all zephyr_board values which are known to launch using ARM FVP (this script configures + # Zephyr to use that launch method). + _KNOWN_FVP_ZEPHYR_BOARDS = ["mps3_an547"] @classmethod - def _is_qemu(cls, board: str) -> bool: - return "qemu" in board or board in cls._KNOWN_QEMU_ZEPHYR_BOARDS + def _is_fvp(cls, board, use_fvp): + if use_fvp: + assert ( + board in cls._KNOWN_FVP_ZEPHYR_BOARDS + ), "FVP can't be used to emulate this board on Zephyr" + return True + return False + + @classmethod + def _is_qemu(cls, board, use_fvp=False): + return "qemu" in board or ( + board in cls._KNOWN_QEMU_ZEPHYR_BOARDS and not cls._is_fvp(board, use_fvp) + ) @classmethod def _has_fpu(cls, zephyr_board): @@ -600,9 +675,7 @@ def _has_fpu(cls, zephyr_board): return zephyr_board in fpu_boards def flash(self, options): - zephyr_board = _find_board_from_cmake_file(API_SERVER_DIR / CMAKELIST_FILENAME) - - if self._is_qemu(zephyr_board): + if _find_platform_from_cmake_file(API_SERVER_DIR / CMAKELIST_FILENAME): return # NOTE: qemu requires no flash step--it is launched from open_transport. # The nRF5340DK requires an additional `nrfjprog --recover` before each flash cycle. @@ -610,17 +683,20 @@ def flash(self, options): # Otherwise, flashing may fail with an error such as the following: # ERROR: The operation attempted is unavailable due to readback protection in # ERROR: your device. Please use --recover to unlock the device. + zephyr_board = _find_board_from_cmake_file(API_SERVER_DIR / CMAKELIST_FILENAME) if zephyr_board.startswith("nrf5340dk") and _get_flash_runner() == "nrfjprog": recover_args = ["nrfjprog", "--recover"] recover_args.extend(_get_nrf_device_args(options)) check_call(recover_args, cwd=API_SERVER_DIR / "build") - check_call(["make", "flash"], cwd=API_SERVER_DIR / "build") + check_call(["ninja", "flash"], cwd=API_SERVER_DIR / "build") def open_transport(self, options): zephyr_board = _find_board_from_cmake_file(API_SERVER_DIR / CMAKELIST_FILENAME) - - if self._is_qemu(zephyr_board): + emu_platform = _find_platform_from_cmake_file(API_SERVER_DIR / CMAKELIST_FILENAME) + if self._is_fvp(zephyr_board, emu_platform == "armfvp"): + transport = ZephyrFvpTransport(options) + elif self._is_qemu(zephyr_board): transport = ZephyrQemuTransport(options) else: transport = ZephyrSerialTransport(options) @@ -795,8 +871,12 @@ def __init__(self, options): self._queue = queue.Queue() def open(self): - self.pipe_dir = pathlib.Path(tempfile.mkdtemp()) - self.pipe = self.pipe_dir / "fifo" + with open(BUILD_DIR / "CMakeCache.txt", "r") as cmake_cache_f: + for line in cmake_cache_f: + if "QEMU_PIPE:" in line: + self.pipe = pathlib.Path(line[line.find("=") + 1 :]) + break + self.pipe_dir = self.pipe.parents[0] self.write_pipe = self.pipe_dir / "fifo.in" self.read_pipe = self.pipe_dir / "fifo.out" os.mkfifo(self.write_pipe) @@ -808,7 +888,7 @@ def open(self): env["TVM_QEMU_GDBSERVER_PORT"] = self.options["gdbserver_port"] self.proc = subprocess.Popen( - ["make", "run", f"QEMU_PIPE={self.pipe}"], + ["ninja", "run"], cwd=BUILD_DIR, env=env, stdout=subprocess.PIPE, @@ -904,5 +984,193 @@ def _wait_for_qemu(self): raise ValueError(f"{item} not expected.") +class ZephyrFvpMakeResult(enum.Enum): + FVP_STARTED = "fvp_started" + MICROTVM_API_SERVER_INIT = "fvp_initialized" + MAKE_FAILED = "make_failed" + EOF = "eof" + + +class BlockingStream: + """Reimplementation of Stream class from Iris with blocking semantics.""" + + def __init__(self): + self.q = queue.Queue() + self.unread = None + + def read(self, n=-1, timeout_sec=None): + assert ( + n != -1 + ), "expect firmware to open stdin using raw mode, and therefore expect sized read requests" + + data = b"" + if self.unread: + data = data + self.unread + self.unread = None + + while len(data) < n: + try: + # When there is some data to return, fetch as much as possible, then return what we can. + # When there is no data yet to return, block. + data += self.q.get(block=not len(data), timeout=timeout_sec) + except queue.Empty: + break + + if len(data) > n: + self.unread = data[n:] + data = data[:n] + + return data + + readline = read + + def write(self, data): + self.q.put(data) + + +class ZephyrFvpTransport: + """A transport class that communicates with the ARM FVP via Iris server.""" + + def __init__(self, options): + self.options = options + self.proc = None + self._queue = queue.Queue() + self._import_iris() + + def _import_iris(self): + assert "arm_fvp_path" in self.options, "arm_fvp_path is not defined." + # Location as seen in the FVP_Corstone_SSE-300_11.15_24 tar. + iris_lib_path = ( + pathlib.Path(self.options["arm_fvp_path"]).parent.parent.parent + / "Iris" + / "Python" + / "iris" + ) + + sys.path.insert(0, str(iris_lib_path.parent)) + try: + import iris.NetworkModelInitializer + finally: + sys.path.pop(0) + + self._iris_lib = iris + + def _convertStringToU64Array(strValue): + numBytes = len(strValue) + if numBytes == 0: + return [] + + numU64 = (numBytes + 7) // 8 + # Extend the string ending with '\0', so that the string length is multiple of 8. + # E.g. 'hello' is extended to: 'hello'+\0\0\0 + strExt = strValue.ljust(8 * numU64, b"\0") + # Convert the string to a list of uint64_t in little endian + return struct.unpack("<{}Q".format(numU64), strExt) + + iris.iris.convertStringToU64Array = _convertStringToU64Array + + def open(self): + args = ["ninja"] + if self.options.get("verbose"): + args.append("-v") + args.append("run") + env = dict(os.environ) + env["ARMFVP_BIN_PATH"] = str(API_SERVER_DIR / "fvp-hack") + self.proc = subprocess.Popen( + args, + cwd=BUILD_DIR, + env=env, + stdout=subprocess.PIPE, + ) + threading.Thread(target=self._fvp_check_stdout, daemon=True).start() + + self.iris_port = self._wait_for_fvp() + _LOG.info("IRIS started on port %d", self.iris_port) + NetworkModelInitializer = self._iris_lib.NetworkModelInitializer.NetworkModelInitializer + self._model_init = NetworkModelInitializer( + host="localhost", port=self.iris_port, timeout_in_ms=1000 + ) + self._model = self._model_init.start() + self._target = self._model.get_target("component.FVP_MPS3_Corstone_SSE_300.cpu0") + + self._target.handle_semihost_io() + self._target._stdout = BlockingStream() + self._target._stdin = BlockingStream() + self._model.run(blocking=False, timeout=100) + self._wait_for_semihost_init() + _LOG.info("IRIS semihosting initialized.") + + return server.TransportTimeouts( + session_start_retry_timeout_sec=2.0, + session_start_timeout_sec=10.0, + session_established_timeout_sec=10.0, + ) + + def _fvp_check_stdout(self): + START_MSG = "Iris server started listening to port" + INIT_MSG = "microTVM Zephyr runtime - running" + for line in self.proc.stdout: + line = str(line, "utf-8") + _LOG.info("%s", line) + start_msg = re.match(START_MSG + r" ([0-9]+)\n", line) + init_msg = re.match(INIT_MSG, line) + if start_msg: + self._queue.put((ZephyrFvpMakeResult.FVP_STARTED, int(start_msg.group(1)))) + elif init_msg: + self._queue.put((ZephyrFvpMakeResult.MICROTVM_API_SERVER_INIT, None)) + break + else: + line = re.sub("[^a-zA-Z0-9 \n]", "", line) + pattern = r"recipe for target (\w*) failed" + if re.search(pattern, line, re.IGNORECASE): + self._queue.put((ZephyrFvpMakeResult.MAKE_FAILED, None)) + + self._queue.put((ZephyrFvpMakeResult.EOF, None)) + + def _wait_for_fvp(self): + """waiting for the START_MSG to appear on the stdout""" + while True: + try: + item = self._queue.get(timeout=120) + except Exception: + raise TimeoutError("FVP setup timeout.") + + if item[0] == ZephyrFvpMakeResult.FVP_STARTED: + return item[1] + + if item[0] in [ZephyrFvpMakeResult.MAKE_FAILED, ZephyrFvpMakeResult.EOF]: + raise RuntimeError("FVP setup failed.") + + raise ValueError(f"{item} not expected.") + + def _wait_for_semihost_init(self): + """waiting for the INIT_MSG to appear on the stdout""" + while True: + try: + item = self._queue.get(timeout=240) + except Exception: + raise TimeoutError("semihost init timeout.") + + if item[0] == ZephyrFvpMakeResult.MICROTVM_API_SERVER_INIT: + return + + raise ValueError(f"{item} not expected.") + + def close(self): + self._model._shutdown_model() + self._model.client.disconnect(force=True) + parent = psutil.Process(self.proc.pid) + if parent: + for child in parent.children(recursive=True): + child.terminate() + parent.terminate() + + def read(self, n, timeout_sec): + return self._target.stdout.read(n, timeout_sec) + + def write(self, data, timeout_sec): + self._target.stdin.write(data) + + if __name__ == "__main__": server.main(Handler()) 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 new file mode 100644 index 000000000000..64a43b02d933 --- /dev/null +++ b/apps/microtvm/zephyr/template_project/src/host_driven/fvp/semihost.c @@ -0,0 +1,87 @@ +/* + * 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. + */ + +/* + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "semihost.h" + +int32_t stdout_fd; +int32_t stdin_fd; + +uint32_t semihost_cmd(uint32_t opcode, void* arg) { + uint32_t ret_val; + __asm__ volatile( + "mov r0, %[opcode]\n\t" + "mov r1, %[arg]\n\t" + "bkpt #0xab\n\r" + "mov %[ret_val], r0" + : [ ret_val ] "=r"(ret_val) + : [ opcode ] "r"(opcode), [ arg ] "r"(arg) + : "r1", "memory"); + + return ret_val; +} + +int32_t stdout_fd; +int32_t stdin_fd; + +void init_semihosting() { + // https://github.com/ARM-software/abi-aa/blob/main/semihosting/semihosting.rst#sys-open-0x01 + struct { + const char* file_name; + uint32_t mode; + uint32_t file_name_len; + } params; + params.file_name = ":tt"; + params.mode = 5; // "wb" + params.file_name_len = 3; + stdout_fd = semihost_cmd(0x01, ¶ms); + + params.mode = 0; + stdin_fd = semihost_cmd(0x01, ¶ms); +} + +ssize_t semihost_read(uint8_t* data, size_t size) { + struct { + uint32_t file_handle; + const uint8_t* data; + uint32_t size; + } read_req; + read_req.file_handle = stdin_fd; + read_req.data = data; + read_req.size = size; + uint32_t ret_val = semihost_cmd(0x06, &read_req); + return size - ret_val; +} + +ssize_t semihost_write(void* unused_context, const uint8_t* data, size_t size) { + struct { + uint32_t file_handle; + const uint8_t* data; + uint32_t size; + } write_req; + write_req.file_handle = stdout_fd; + write_req.data = data; + write_req.size = size; + uint32_t ret_val = semihost_cmd(0x05, &write_req); + return size - ret_val; +} \ No newline at end of file diff --git a/apps/microtvm/zephyr/template_project/src/host_driven/fvp/semihost.h b/apps/microtvm/zephyr/template_project/src/host_driven/fvp/semihost.h new file mode 100644 index 000000000000..06b42ae3f95b --- /dev/null +++ b/apps/microtvm/zephyr/template_project/src/host_driven/fvp/semihost.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +/* + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef TVM_APPS_MICROTVM_ZEPHYR_HOST_DRIVEN_SEMIHOST_H_ +#define TVM_APPS_MICROTVM_ZEPHYR_HOST_DRIVEN_SEMIHOST_H_ + +#include +#include +#include + +void init_semihosting(); + +ssize_t semihost_read(uint8_t* data, size_t size); + +ssize_t semihost_write(void* unused_context, const uint8_t* data, size_t size); + +#endif /* TVM_APPS_MICROTVM_ZEPHYR_HOST_DRIVEN_SEMIHOST_H_ */ 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 ff02b3cb1d44..c0286dc0c74f 100644 --- a/apps/microtvm/zephyr/template_project/src/host_driven/main.c +++ b/apps/microtvm/zephyr/template_project/src/host_driven/main.c @@ -28,7 +28,6 @@ * intended to be a demonstration, since typically you will want to incorporate * this logic into your own application. */ - #include #include #include @@ -44,6 +43,10 @@ #include #include +#ifdef FVP +#include "fvp/semihost.h" +#endif + #ifdef CONFIG_ARCH_POSIX #include "posix_board_if.h" #endif @@ -65,7 +68,7 @@ static size_t g_num_bytes_written = 0; static size_t g_num_bytes_in_rx_buffer = 0; // Called by TVM to write serial data to the UART. -ssize_t write_serial(void* unused_context, const uint8_t* data, size_t size) { +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 @@ -83,6 +86,14 @@ ssize_t write_serial(void* unused_context, const uint8_t* data, size_t size) { return size; } +ssize_t serial_write(void* unused_context, const uint8_t* data, size_t size) { +#ifdef FVP + return semihost_write(unused_context, data, size); +#else + return uart_write(unused_context, data, 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) { @@ -250,9 +261,19 @@ void main(void) { timing_init(); timing_start(); +#ifdef FVP + init_semihosting(); + // send some dummy log to speed up the initialization + for (int i = 0; i < 100; ++i) { + uart_write(NULL, "dummy log...\n", 13); + } + uart_write(NULL, "microTVM Zephyr runtime - running\n", 34); +#endif + // Initialize microTVM RPC server, which will receive commands from the UART and execute them. - microtvm_rpc_server_t server = MicroTVMRpcServerInit(write_serial, NULL); + 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 @@ -260,18 +281,28 @@ void main(void) { // The main application loop. We continuously read commands from the UART // and dispatch them to MicroTVMRpcServerLoop(). while (true) { +#ifdef FVP + uint8_t data[128]; + uint32_t bytes_read = semihost_read(data, 128); +#else uint8_t* data; unsigned int key = irq_lock(); uint32_t bytes_read = ring_buf_get_claim(&uart_rx_rbuf, &data, RING_BUF_SIZE_BYTES); +#endif if (bytes_read > 0) { - g_num_bytes_in_rx_buffer -= bytes_read; + uint8_t* ptr = data; size_t bytes_remaining = bytes_read; while (bytes_remaining > 0) { // Pass the received bytes to the RPC server. - tvm_crt_error_t err = MicroTVMRpcServerLoop(server, &data, &bytes_remaining); + tvm_crt_error_t err = MicroTVMRpcServerLoop(server, &ptr, &bytes_remaining); if (err != kTvmErrorNoError && err != kTvmErrorFramingShortPacket) { TVMPlatformAbort(err); } +#ifdef FVP + } + } +#else + g_num_bytes_in_rx_buffer -= bytes_read; if (g_num_bytes_written != 0 || g_num_bytes_requested != 0) { if (g_num_bytes_written != g_num_bytes_requested) { TVMPlatformAbort((tvm_crt_error_t)0xbeef5); @@ -286,6 +317,7 @@ void main(void) { } } irq_unlock(key); +#endif } #ifdef CONFIG_ARCH_POSIX diff --git a/cmake/modules/Zephyr.cmake b/cmake/modules/Zephyr.cmake index b88d6c63bd68..be4f85dac33d 100644 --- a/cmake/modules/Zephyr.cmake +++ b/cmake/modules/Zephyr.cmake @@ -26,6 +26,8 @@ if(USE_MICRO) "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/fvp-hack * -> zephyr/fvp-hack" "apps/microtvm/zephyr/template_project/qemu-hack * -> zephyr/qemu-hack" "apps/microtvm/zephyr/template_project/crt_config *.h -> zephyr/crt_config" ) diff --git a/tests/lint/check_file_type.py b/tests/lint/check_file_type.py index 099ba3c3fa5b..7e09c3c7cfa6 100644 --- a/tests/lint/check_file_type.py +++ b/tests/lint/check_file_type.py @@ -147,6 +147,7 @@ "apps/microtvm/zephyr/template_project/qemu-hack/qemu-system-i386", "apps/microtvm/zephyr/template_project/qemu-hack/qemu-system-riscv32", "apps/microtvm/zephyr/template_project/qemu-hack/qemu-system-riscv64", + "apps/microtvm/zephyr/template_project/fvp-hack/FVP_Corstone_SSE-300_Ethos-U55", # microTVM Virtual Machines "apps/microtvm/poetry.lock", "apps/microtvm/reference-vm/Vagrantfile", @@ -236,7 +237,7 @@ def main(): if error_list: report = "------File type check report----\n" report += "\n".join(error_list) - report += "\nFound %d files that are now allowed\n" % len(error_list) + report += "\nFound %d files that are not allowed\n" % len(error_list) report += ( "We do not check in binary files into the repo.\n" "If necessary, please discuss with committers and" diff --git a/tests/micro/zephyr/conftest.py b/tests/micro/zephyr/conftest.py index 9f3b56769075..52e89481b7bb 100644 --- a/tests/micro/zephyr/conftest.py +++ b/tests/micro/zephyr/conftest.py @@ -26,8 +26,36 @@ def pytest_addoption(parser): parser.addoption( "--west-cmd", default="west", help="Path to `west` command for flashing device." ) + parser.addoption( + "--use-fvp", + action="store_true", + default=False, + help="If set true, use the FVP emulator to run the test", + ) @pytest.fixture(scope="session") def west_cmd(request): return request.config.getoption("--west-cmd") + + +@pytest.fixture +def use_fvp(request): + return request.config.getoption("--use-fvp") + + +@pytest.fixture(autouse=True) +def xfail_on_fvp(request, use_fvp): + """mark the tests as xfail if running on fvp.""" + if request.node.get_closest_marker("xfail_on_fvp"): + if use_fvp: + request.node.add_marker( + pytest.mark.xfail(reason="checking corstone300 reliability on CI") + ) + + +def pytest_configure(config): + config.addinivalue_line( + "markers", + "xfail_on_fvp(): mark test as xfail on fvp", + ) diff --git a/tests/micro/zephyr/test_zephyr.py b/tests/micro/zephyr/test_zephyr.py index 1f53e4baa8c3..9c0c3fefb488 100644 --- a/tests/micro/zephyr/test_zephyr.py +++ b/tests/micro/zephyr/test_zephyr.py @@ -40,7 +40,7 @@ def _make_sess_from_op( - temp_dir, model, zephyr_board, west_cmd, op_name, sched, arg_bufs, build_config + temp_dir, model, zephyr_board, west_cmd, op_name, sched, arg_bufs, build_config, use_fvp ): runtime = Runtime("crt", {"system-lib": True}) target = tvm.target.target.micro(model) @@ -48,10 +48,10 @@ def _make_sess_from_op( with tvm.transform.PassContext(opt_level=3, config={"tir.disable_vectorize": True}): mod = tvm.build(sched, arg_bufs, target=target, runtime=runtime, name=op_name) - return _make_session(temp_dir, zephyr_board, west_cmd, mod, build_config) + return _make_session(temp_dir, zephyr_board, west_cmd, mod, build_config, use_fvp) -def _make_session(temp_dir, zephyr_board, west_cmd, mod, build_config): +def _make_session(temp_dir, zephyr_board, west_cmd, mod, build_config, use_fvp): config_main_stack_size = None if test_utils.qemu_boards(zephyr_board): config_main_stack_size = 1536 @@ -61,6 +61,8 @@ def _make_session(temp_dir, zephyr_board, west_cmd, mod, build_config): "west_cmd": west_cmd, "verbose": bool(build_config.get("debug")), "zephyr_board": zephyr_board, + "arm_fvp_path": "/opt/arm/FVP_Corstone_SSE-300/models/Linux64_GCC-6.4/FVP_Corstone_SSE-300_Ethos-U55", + "use_fvp": bool(use_fvp), } if config_main_stack_size is not None: project_options["config_main_stack_size"] = config_main_stack_size @@ -76,20 +78,21 @@ def _make_session(temp_dir, zephyr_board, west_cmd, mod, build_config): return tvm.micro.Session(project.transport()) -def _make_add_sess(temp_dir, model, zephyr_board, west_cmd, build_config, dtype="int8"): +def _make_add_sess(temp_dir, model, zephyr_board, west_cmd, build_config, use_fvp, dtype="int8"): A = tvm.te.placeholder((2,), dtype=dtype) B = tvm.te.placeholder((1,), dtype=dtype) C = tvm.te.compute(A.shape, lambda i: A[i] + B[0], name="C") sched = tvm.te.create_schedule(C.op) return _make_sess_from_op( - temp_dir, model, zephyr_board, west_cmd, "add", sched, [A, B, C], build_config + temp_dir, model, zephyr_board, west_cmd, "add", sched, [A, B, C], build_config, use_fvp ) # The same test code can be executed on both the QEMU simulation and on real hardware. @tvm.testing.requires_micro @pytest.mark.skip_boards(["mps2_an521"]) -def test_add_uint(workspace_dir, board, west_cmd, microtvm_debug): +@pytest.mark.xfail_on_fvp() +def test_add_uint(workspace_dir, board, west_cmd, microtvm_debug, use_fvp): """Test compiling the on-device runtime.""" model = test_utils.ZEPHYR_BOARDS[board] @@ -108,14 +111,15 @@ def test_basic_add(sess): system_lib.get_function("add")(A_data, B_data, C_data) assert (C_data.numpy() == np.array([6, 7])).all() - with _make_add_sess(workspace_dir, model, board, west_cmd, build_config) as sess: + with _make_add_sess(workspace_dir, model, board, west_cmd, build_config, use_fvp) as sess: test_basic_add(sess) # The same test code can be executed on both the QEMU simulation and on real hardware. @tvm.testing.requires_micro @pytest.mark.skip_boards(["mps2_an521"]) -def test_add_float(workspace_dir, board, west_cmd, microtvm_debug): +@pytest.mark.xfail_on_fvp() +def test_add_float(workspace_dir, board, west_cmd, microtvm_debug, use_fvp): """Test compiling the on-device runtime.""" model = test_utils.ZEPHYR_BOARDS[board] if not test_utils.has_fpu(board): @@ -137,14 +141,15 @@ def test_basic_add(sess): assert (C_data.numpy() == np.array([7, 8])).all() with _make_add_sess( - workspace_dir, model, board, west_cmd, build_config, dtype="float32" + workspace_dir, model, board, west_cmd, build_config, use_fvp, dtype="float32" ) as sess: test_basic_add(sess) @tvm.testing.requires_micro @pytest.mark.skip_boards(["mps2_an521"]) -def test_platform_timer(workspace_dir, board, west_cmd, microtvm_debug): +@pytest.mark.xfail_on_fvp() +def test_platform_timer(workspace_dir, board, west_cmd, microtvm_debug, use_fvp): """Test compiling the on-device runtime.""" model = test_utils.ZEPHYR_BOARDS[board] @@ -168,13 +173,14 @@ def test_basic_add(sess): assert result.mean > 0 assert len(result.results) == 3 - with _make_add_sess(workspace_dir, model, board, west_cmd, build_config) as sess: + with _make_add_sess(workspace_dir, model, board, west_cmd, build_config, use_fvp) as sess: test_basic_add(sess) @tvm.testing.requires_micro @pytest.mark.skip_boards(["mps2_an521"]) -def test_relay(workspace_dir, board, west_cmd, microtvm_debug): +@pytest.mark.xfail_on_fvp() +def test_relay(workspace_dir, board, west_cmd, microtvm_debug, use_fvp): """Testing a simple relay graph""" model = test_utils.ZEPHYR_BOARDS[board] build_config = {"debug": microtvm_debug} @@ -193,7 +199,7 @@ def test_relay(workspace_dir, board, west_cmd, microtvm_debug): with tvm.transform.PassContext(opt_level=3, config={"tir.disable_vectorize": True}): mod = tvm.relay.build(ir_mod, target=target, runtime=runtime) - with _make_session(workspace_dir, board, west_cmd, mod, build_config) as session: + with _make_session(workspace_dir, board, west_cmd, mod, build_config, use_fvp) as session: graph_mod = tvm.micro.create_local_graph_executor( mod.get_graph_json(), session.get_system_lib(), session.device ) @@ -207,7 +213,8 @@ def test_relay(workspace_dir, board, west_cmd, microtvm_debug): @tvm.testing.requires_micro @pytest.mark.skip_boards(["mps2_an521"]) -def test_onnx(workspace_dir, board, west_cmd, microtvm_debug): +@pytest.mark.xfail_on_fvp() +def test_onnx(workspace_dir, board, west_cmd, microtvm_debug, use_fvp): """Testing a simple ONNX model.""" model = test_utils.ZEPHYR_BOARDS[board] build_config = {"debug": microtvm_debug} @@ -239,7 +246,7 @@ def test_onnx(workspace_dir, board, west_cmd, microtvm_debug): lowered = relay.build(relay_mod, target, params=params, executor=executor, runtime=runtime) graph = lowered.get_graph_json() - with _make_session(workspace_dir, board, west_cmd, lowered, build_config) as session: + with _make_session(workspace_dir, board, west_cmd, lowered, build_config, use_fvp) as session: graph_mod = tvm.micro.create_local_graph_executor( graph, session.get_system_lib(), session.device ) @@ -258,7 +265,16 @@ def test_onnx(workspace_dir, board, west_cmd, microtvm_debug): def check_result( - temp_dir, relay_mod, model, zephyr_board, west_cmd, map_inputs, out_shape, result, build_config + temp_dir, + relay_mod, + model, + zephyr_board, + west_cmd, + map_inputs, + out_shape, + result, + build_config, + use_fvp, ): """Helper function to verify results""" TOL = 1e-5 @@ -267,7 +283,7 @@ def check_result( with tvm.transform.PassContext(opt_level=3, config={"tir.disable_vectorize": True}): mod = tvm.relay.build(relay_mod, target=target, runtime=runtime) - with _make_session(temp_dir, zephyr_board, west_cmd, mod, build_config) as session: + with _make_session(temp_dir, zephyr_board, west_cmd, mod, build_config, use_fvp) as session: rt_mod = tvm.micro.create_local_graph_executor( mod.get_graph_json(), session.get_system_lib(), session.device ) @@ -288,7 +304,8 @@ def check_result( @tvm.testing.requires_micro @pytest.mark.skip_boards(["mps2_an521"]) -def test_byoc_microtvm(workspace_dir, board, west_cmd, microtvm_debug): +@pytest.mark.xfail_on_fvp() +def test_byoc_microtvm(workspace_dir, board, west_cmd, microtvm_debug, use_fvp): """This is a simple test case to check BYOC capabilities of microTVM""" model = test_utils.ZEPHYR_BOARDS[board] build_config = {"debug": microtvm_debug} @@ -347,15 +364,18 @@ def test_byoc_microtvm(workspace_dir, board, west_cmd, microtvm_debug): zephyr_board=board, west_cmd=west_cmd, build_config=build_config, + use_fvp=use_fvp, ) -def _make_add_sess_with_shape(temp_dir, model, zephyr_board, west_cmd, shape, build_config): +def _make_add_sess_with_shape( + temp_dir, model, zephyr_board, west_cmd, shape, build_config, use_fvp +): A = tvm.te.placeholder(shape, dtype="int8") C = tvm.te.compute(A.shape, lambda i: A[i] + A[i], name="C") sched = tvm.te.create_schedule(C.op) return _make_sess_from_op( - temp_dir, model, zephyr_board, west_cmd, "add", sched, [A, C], build_config + temp_dir, model, zephyr_board, west_cmd, "add", sched, [A, C], build_config, use_fvp ) @@ -369,7 +389,8 @@ def _make_add_sess_with_shape(temp_dir, model, zephyr_board, west_cmd, shape, bu ) @tvm.testing.requires_micro @pytest.mark.skip_boards(["mps2_an521"]) -def test_rpc_large_array(workspace_dir, board, west_cmd, microtvm_debug, shape): +@pytest.mark.xfail_on_fvp() +def test_rpc_large_array(workspace_dir, board, west_cmd, microtvm_debug, shape, use_fvp): """Test large RPC array transfer.""" model = test_utils.ZEPHYR_BOARDS[board] build_config = {"debug": microtvm_debug} @@ -384,14 +405,14 @@ def test_tensors(sess): assert (C_data.numpy() == np.zeros(shape)).all() with _make_add_sess_with_shape( - workspace_dir, model, board, west_cmd, shape, build_config + workspace_dir, model, board, west_cmd, shape, build_config, use_fvp ) as sess: test_tensors(sess) @pytest.mark.xfail(strict=False, reason="See https://github.com/apache/tvm/issues/10297") @tvm.testing.requires_micro -def test_autotune_conv2d(workspace_dir, board, west_cmd, microtvm_debug): +def test_autotune_conv2d(workspace_dir, board, west_cmd, microtvm_debug, use_fvp): """Test AutoTune for microTVM Zephyr""" if board != "qemu_x86": pytest.xfail(f"Autotune fails on {board}.") @@ -440,6 +461,7 @@ def test_autotune_conv2d(workspace_dir, board, west_cmd, microtvm_debug): "west_cmd": west_cmd, "verbose": 1, "project_type": "host_driven", + "use_fvp": bool(use_fvp), } if config_main_stack_size is not None: project_options["config_main_stack_size"] = config_main_stack_size @@ -489,7 +511,7 @@ def test_autotune_conv2d(workspace_dir, board, west_cmd, microtvm_debug): lowered = tvm.relay.build(mod, target=target, runtime=runtime, params=params) temp_dir = utils.tempdir() - with _make_session(temp_dir, board, west_cmd, lowered, build_config) as session: + with _make_session(temp_dir, board, west_cmd, lowered, build_config, use_fvp) as session: graph_mod = tvm.micro.create_local_graph_executor( lowered.get_graph_json(), session.get_system_lib(), session.device ) @@ -504,7 +526,7 @@ def test_autotune_conv2d(workspace_dir, board, west_cmd, microtvm_debug): lowered_tuned = tvm.relay.build(mod, target=target, runtime=runtime, params=params) temp_dir = utils.tempdir() - with _make_session(temp_dir, board, west_cmd, lowered_tuned, build_config) as session: + with _make_session(temp_dir, board, west_cmd, lowered_tuned, build_config, use_fvp) as session: graph_mod = tvm.micro.create_local_graph_executor( lowered_tuned.get_graph_json(), session.get_system_lib(), session.device ) @@ -517,7 +539,9 @@ def test_autotune_conv2d(workspace_dir, board, west_cmd, microtvm_debug): @tvm.testing.requires_micro -def test_schedule_build_with_cmsis_dependency(workspace_dir, board, west_cmd, microtvm_debug): +def test_schedule_build_with_cmsis_dependency( + workspace_dir, board, west_cmd, microtvm_debug, use_fvp +): """Test Relay schedule with CMSIS dependency. This test shows if microTVM Auto tuning with Zephyr breaks if CMSIS dependency was required for a schedule. """ @@ -557,6 +581,7 @@ def test_schedule_build_with_cmsis_dependency(workspace_dir, board, west_cmd, mi "verbose": bool(build_config.get("debug")), "zephyr_board": board, "cmsis_path": os.getenv("CMSIS_PATH"), + "use_fvp": bool(use_fvp), } project_dir = workspace_dir / "project" diff --git a/tests/micro/zephyr/test_zephyr_aot_exec.py b/tests/micro/zephyr/test_zephyr_aot_exec.py index 054a06aa020b..2f00d855a46d 100644 --- a/tests/micro/zephyr/test_zephyr_aot_exec.py +++ b/tests/micro/zephyr/test_zephyr_aot_exec.py @@ -38,7 +38,7 @@ import test_utils -def _make_session(workspace_dir, zephyr_board, west_cmd, mod, build_config): +def _make_session(workspace_dir, zephyr_board, west_cmd, mod, build_config, use_fvp): config_main_stack_size = None if test_utils.qemu_boards(zephyr_board): # fyi: qemu_riscv64 seems to be the greediest stack user @@ -52,6 +52,8 @@ def _make_session(workspace_dir, zephyr_board, west_cmd, mod, build_config): "west_cmd": west_cmd, "verbose": bool(build_config.get("debug")), "zephyr_board": zephyr_board, + "arm_fvp_path": "/opt/arm/FVP_Corstone_SSE-300/models/Linux64_GCC-6.4/FVP_Corstone_SSE-300_Ethos-U55", + "use_fvp": bool(use_fvp), } if config_main_stack_size is not None: project_options["config_main_stack_size"] = config_main_stack_size @@ -69,7 +71,8 @@ def _make_session(workspace_dir, zephyr_board, west_cmd, mod, build_config): @tvm.testing.requires_micro @pytest.mark.skip_boards(["mps2_an521"]) -def test_relay(workspace_dir, board, west_cmd, microtvm_debug): +@pytest.mark.xfail_on_fvp() +def test_relay(workspace_dir, board, west_cmd, microtvm_debug, use_fvp): """Testing a simple relay graph""" model = test_utils.ZEPHYR_BOARDS[board] @@ -90,7 +93,7 @@ def test_relay(workspace_dir, board, west_cmd, microtvm_debug): with tvm.transform.PassContext(opt_level=3, config={"tir.disable_vectorize": True}): mod = tvm.relay.build(ir_mod, target=target, runtime=runtime, executor=executor) - with _make_session(workspace_dir, board, west_cmd, mod, build_config) as session: + with _make_session(workspace_dir, board, west_cmd, mod, build_config, use_fvp) as session: aot_executor = tvm.runtime.executor.aot_executor.AotModule(session.create_aot_executor()) @@ -103,7 +106,8 @@ def test_relay(workspace_dir, board, west_cmd, microtvm_debug): @tvm.testing.requires_micro @pytest.mark.skip_boards(["mps2_an521"]) -def test_aot_executor(workspace_dir, board, west_cmd, microtvm_debug): +@pytest.mark.xfail_on_fvp() +def test_aot_executor(workspace_dir, board, west_cmd, microtvm_debug, use_fvp): """Test use of the AOT executor with microTVM.""" model = test_utils.ZEPHYR_BOARDS[board] @@ -154,7 +158,7 @@ def do_test(): aot_executor.set_input("b", B_np_new) assert (B_data.numpy() == B_np_new).all() - with _make_session(workspace_dir, board, west_cmd, mod, build_config) as session: + with _make_session(workspace_dir, board, west_cmd, mod, build_config, use_fvp) as session: do_test() diff --git a/tests/micro/zephyr/test_zephyr_aot_exec_standalone.py b/tests/micro/zephyr/test_zephyr_aot_exec_standalone.py index da9d63216f15..2941bb1befc4 100644 --- a/tests/micro/zephyr/test_zephyr_aot_exec_standalone.py +++ b/tests/micro/zephyr/test_zephyr_aot_exec_standalone.py @@ -38,7 +38,7 @@ @tvm.testing.requires_micro -@pytest.mark.skip_boards(["mps2_an521"]) +@pytest.mark.skip_boards(["mps2_an521", "mps3_an547"]) def test_tflite(workspace_dir, board, west_cmd, microtvm_debug): """Testing a TFLite model.""" model = test_utils.ZEPHYR_BOARDS[board] @@ -94,7 +94,7 @@ def test_tflite(workspace_dir, board, west_cmd, microtvm_debug): @tvm.testing.requires_micro -@pytest.mark.skip_boards(["mps2_an521"]) +@pytest.mark.skip_boards(["mps2_an521", "mps3_an547"]) def test_qemu_make_fail(workspace_dir, board, west_cmd, microtvm_debug): """Testing QEMU make fail.""" if board not in ["qemu_x86", "mps2_an521", "mps3_an547"]: @@ -131,9 +131,7 @@ def test_qemu_make_fail(workspace_dir, board, west_cmd, microtvm_debug): load_cmsis=False, ) - file_path = ( - pathlib.Path(project_dir) / "build" / "zephyr" / "CMakeFiles" / "run.dir" / "build.make" - ) + file_path = pathlib.Path(project_dir) / "build" / "build.ninja" assert file_path.is_file(), f"[{file_path}] does not exist." # Remove a file to create make failure. diff --git a/tests/scripts/task_python_microtvm.sh b/tests/scripts/task_python_microtvm.sh index a9dcd9bab071..e65f2253bb28 100755 --- a/tests/scripts/task_python_microtvm.sh +++ b/tests/scripts/task_python_microtvm.sh @@ -28,6 +28,7 @@ run_pytest ctypes python-microtvm-zephyr-qemu_x86 tests/micro/zephyr --board=qem run_pytest ctypes python-microtvm-zephyr-qemu_riscv32 tests/micro/zephyr --board=qemu_riscv32 run_pytest ctypes python-microtvm-zephyr-qemu_riscv64 tests/micro/zephyr --board=qemu_riscv64 run_pytest ctypes python-microtvm-zephyr-mps2_an521 tests/micro/zephyr --board=mps2_an521 +run_pytest ctypes python-microtvm-zephyr-mps3_an547 tests/micro/zephyr --board=mps3_an547 --use-fvp # Arduino run_pytest ctypes python-microtvm-arduino apps/microtvm/arduino/template_project/tests