mkatanbaf commented on code in PR #12125:
URL: https://github.com/apache/tvm/pull/12125#discussion_r929414402


##########
apps/microtvm/zephyr/template_project/microtvm_api_server.py:
##########
@@ -885,5 +945,186 @@ def _wait_for_qemu(self):
             raise ValueError(f"{item} not expected.")
 
 
+class ZephyrFvpMakeResult(enum.Enum):
+    FVP_STARTED = "fvp_started"
+    FVP_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()
+
+        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):
+        for line in self.proc.stdout:
+            line = str(line, "utf-8")
+            m = re.match(r"Iris server started listening to port ([0-9]+)\n", 
line)
+            n = re.match("microTVM Zephyr runtime - running", line)
+            if m:
+                self._queue.put((ZephyrFvpMakeResult.FVP_STARTED, 
int(m.group(1))))
+            elif n:
+                self._queue.put((ZephyrFvpMakeResult.FVP_INIT, None))
+            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):
+        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):
+        while True:
+            try:
+                item = self._queue.get(timeout=120)
+            except Exception:
+                raise TimeoutError("semihost init timeout.")
+
+            if item[0] == ZephyrFvpMakeResult.FVP_INIT:
+                return
+
+            raise ValueError(f"{item} not expected.")

Review Comment:
   The API is waiting for a specific line to appear on the stdout. I added a 
comment to make it more clear.



##########
apps/microtvm/zephyr/template_project/src/host_driven/main.c:
##########
@@ -64,8 +67,89 @@ static size_t g_num_bytes_requested = 0;
 static size_t g_num_bytes_written = 0;
 static size_t g_num_bytes_in_rx_buffer = 0;
 
+#ifdef FVP

Review Comment:
   done



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to