From ae50647fcbf172a07e165f7cc24ec13cb28d9330 Mon Sep 17 00:00:00 2001 From: Andrew Reusch Date: Tue, 5 Jul 2022 16:05:37 -0700 Subject: [PATCH] add corstone300 fvp to the microTVM platforms supported via Zephyr. --- .../template_project/CMakeLists.txt.template | 2 +- .../fvp-hack/FVP_Corstone_SSE-300_Ethos-U55 | 44 +++ .../template_project/microtvm_api_server.py | 303 ++++++++++++++++-- .../src/host_driven/fvp/semihost.c | 89 +++++ .../src/host_driven/fvp/semihost.h | 42 +++ .../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, 593 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 7f37efc599c29..16d46e50bcec0 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 0000000000000..0779f49f432e0 --- /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 81394f31ab18b..9ac81b95d515a 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 @@ -330,6 +333,18 @@ def _get_nrf_device_args(options): type="str", help="Path to the CMSIS directory.", ), + server.ProjectOption( + "arm_fvp_path", + optional=["generate_project"], + 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.", + ), ] @@ -422,6 +437,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", @@ -469,10 +485,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 += f"set(EMU_PLATFORM armfvp)\n" + cmake_args += f"set(ARMFVP_FLAGS -I)\n" + cmake_args += f"set(BOARD {options['zephyr_board']})\n" enable_cmsis = self._cmsis_required(mlf_extracted_path) @@ -511,8 +531,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" @@ -536,6 +558,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"): @@ -543,6 +569,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 @@ -554,7 +583,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"): @@ -564,21 +599,49 @@ 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 = self._find_board_from_cmake_file() + emu_platform = self._find_platform_from_cmake_file() + + env = dict(os.environ) + if self._is_fvp(zephyr_board, emu_platform == "armfvp"): + env["ARMFVP_BIN_PATH"] = str(API_SERVER_DIR / "fvp-hack") + env["ARMFVP_BIN_PATH"] = os.path.realpath(env["ARMFVP_BIN_PATH"]) + 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, + ) + + print("ENV", env) + 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): + assert not ( + (use_fvp is not None) and use_fvp and (board not in cls._KNOWN_FVP_ZEPHYR_BOARDS) + ), "fvp doesn't support this board." + + return board in cls._KNOWN_FVP_ZEPHYR_BOARDS and use_fvp + + @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): @@ -598,10 +661,18 @@ def _find_board_from_cmake_file(cls) -> str: raise RuntimeError(f"No Zephyr board set in the {API_SERVER_DIR / CMAKELIST_FILENAME}.") return zephyr_board - def flash(self, options): - zephyr_board = self._find_board_from_cmake_file() + @classmethod + def _find_platform_from_cmake_file(cls) -> str: + emu_platform = None + with open(API_SERVER_DIR / CMAKELIST_FILENAME) as cmake_f: + for line in cmake_f: + if line.startswith("set(EMU_PLATFORM"): + emu_platform = line.strip("\n").strip("set(EMU_PLATFORM ").strip(")") + break + return emu_platform - if self._is_qemu(zephyr_board): + def flash(self, options): + if self._find_platform_from_cmake_file(): return # NOTE: qemu requires no flash step--it is launched from open_transport. # The nRF5340DK requires an additional `nrfjprog --recover` before each flash cycle. @@ -609,17 +680,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 = self._find_board_from_cmake_file() 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 = self._find_board_from_cmake_file() - - if self._is_qemu(zephyr_board): + emu_platform = self._find_platform_from_cmake_file() + 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) @@ -794,8 +868,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) @@ -807,7 +885,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, @@ -903,5 +981,192 @@ 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): + # 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["FVP_BIN_PATH"] = str(pathlib.Path(self.options["arm_fvp_path"]).parent) + 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.release() + 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 0000000000000..b16020f3dd252 --- /dev/null +++ b/apps/microtvm/zephyr/template_project/src/host_driven/fvp/semihost.c @@ -0,0 +1,89 @@ +/* + * 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; + +static 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; +} + +int32_t get_sim_clk() { return semihost_cmd(0x10, NULL); } 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 0000000000000..a58c24cedc22d --- /dev/null +++ b/apps/microtvm/zephyr/template_project/src/host_driven/fvp/semihost.h @@ -0,0 +1,42 @@ +/* + * 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 + +static uint32_t semihost_cmd(uint32_t opcode, void* arg); + +void init_semihosting(); + +ssize_t read_semihost(uint8_t* data, size_t size); + +ssize_t write_semihost(void* unused_context, const uint8_t* data, size_t size); + +int32_t get_sim_clk(); + +#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 ff02b3cb1d444..c0286dc0c74f3 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 b88d6c63bd68e..be4f85dac33d6 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 099ba3c3fa5b2..7e09c3c7cfa6c 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 9f3b567690752..52e89481b7bb2 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 1f53e4baa8c3f..9c0c3fefb4881 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 054a06aa020ba..2f00d855a46db 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 da9d63216f150..2941bb1befc42 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 a9dcd9bab071b..e65f2253bb287 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