[opentitantool] Print the verilator stdout for easier debug

1. Spawn a thread to consume and log the verilator stdout.

Signed-off-by: Chris Frantz <cfrantz@google.com>
diff --git a/sw/host/opentitanlib/BUILD b/sw/host/opentitanlib/BUILD
index 99f2f93..086d5e8 100644
--- a/sw/host/opentitanlib/BUILD
+++ b/sw/host/opentitanlib/BUILD
@@ -80,6 +80,7 @@
         "src/transport/ultradebug/spi.rs",
         "src/transport/ultradebug/uart.rs",
         "src/transport/verilator/mod.rs",
+        "src/transport/verilator/stdout.rs",
         "src/transport/verilator/subprocess.rs",
         "src/transport/verilator/transport.rs",
         "src/transport/verilator/uart.rs",
diff --git a/sw/host/opentitanlib/src/transport/verilator/mod.rs b/sw/host/opentitanlib/src/transport/verilator/mod.rs
index 8da586f..90f9297 100644
--- a/sw/host/opentitanlib/src/transport/verilator/mod.rs
+++ b/sw/host/opentitanlib/src/transport/verilator/mod.rs
@@ -2,6 +2,7 @@
 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
 // SPDX-License-Identifier: Apache-2.0
 
+mod stdout;
 pub mod subprocess;
 pub mod transport;
 pub mod uart;
diff --git a/sw/host/opentitanlib/src/transport/verilator/stdout.rs b/sw/host/opentitanlib/src/transport/verilator/stdout.rs
new file mode 100644
index 0000000..2223574
--- /dev/null
+++ b/sw/host/opentitanlib/src/transport/verilator/stdout.rs
@@ -0,0 +1,45 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+use anyhow::Result;
+use std::io::Read;
+use std::process::ChildStdout;
+use std::sync::{Arc, Mutex};
+
+// The whole point of this module being named `stdout.rs` is so that the log message
+// looks like `[<timestamp> INFO ...verilator::stdout] <message>`.
+
+// Accumulates output from verilator's `stdout`.
+pub fn accumulate(stdout: ChildStdout, accumulator: Arc<Mutex<String>>) {
+    if let Err(e) = worker(stdout, accumulator) {
+        log::error!("accumulate error: {:?}", e);
+    }
+}
+
+fn worker(mut stdout: ChildStdout, accumulator: Arc<Mutex<String>>) -> Result<()> {
+    let mut s = String::default();
+    loop {
+        read(&mut stdout, &mut s)?;
+        let mut lines = s.split('\n').collect::<Vec<&str>>();
+        let next = if !s.ends_with('\n') {
+            // If we didn't read a complete line at the end, save it for the
+            // next read.
+            lines.pop()
+        } else {
+            None
+        };
+        for line in lines {
+            log::info!("{}", line);
+        }
+        accumulator.lock().unwrap().push_str(&s);
+        s = next.unwrap_or("").to_string();
+    }
+}
+
+fn read(stdout: &mut ChildStdout, s: &mut String) -> Result<()> {
+    let mut buf = [0u8; 256];
+    let n = stdout.read(&mut buf)?;
+    s.push_str(&String::from_utf8_lossy(&buf[..n]));
+    Ok(())
+}
diff --git a/sw/host/opentitanlib/src/transport/verilator/subprocess.rs b/sw/host/opentitanlib/src/transport/verilator/subprocess.rs
index fad3a7e..ae5ddfa 100644
--- a/sw/host/opentitanlib/src/transport/verilator/subprocess.rs
+++ b/sw/host/opentitanlib/src/transport/verilator/subprocess.rs
@@ -2,14 +2,15 @@
 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
 // SPDX-License-Identifier: Apache-2.0
 
-use crate::util::file;
-use anyhow::Result;
-use log::info;
+use anyhow::{anyhow, Result};
 use regex::Regex;
-use std::io::{ErrorKind, Read};
-use std::process::{Child, ChildStdout, Command, Stdio};
+use std::io::ErrorKind;
+use std::process::{Child, Command, Stdio};
+use std::sync::{Arc, Mutex};
 use std::time::{Duration, Instant};
 
+use crate::transport::verilator::stdout;
+
 /// Verilator startup options.
 pub struct Options {
     /// The verilator executable.
@@ -26,8 +27,7 @@
 
 pub struct Subprocess {
     child: Child,
-    stdout: ChildStdout,
-    accumulated_output: String,
+    accumulated_output: Arc<Mutex<String>>,
 }
 
 impl Subprocess {
@@ -48,31 +48,24 @@
         args.extend_from_slice(&options.extra_args);
         command.args(&args[..]);
 
-        info!("Spawning verilator: {:?} {:?}", options.executable, args);
+        log::info!("Spawning verilator: {:?} {:?}", options.executable, args);
 
         let mut child = command
             .stdin(Stdio::null())
             .stdout(Stdio::piped())
             .stderr(Stdio::inherit())
             .spawn()?;
+        let accumulator: Arc<Mutex<String>> = Default::default();
         let stdout = child.stdout.take().unwrap();
+        let a = Arc::clone(&accumulator);
+        std::thread::spawn(move || stdout::accumulate(stdout, a));
+
         Ok(Subprocess {
             child,
-            stdout,
-            accumulated_output: String::default(),
+            accumulated_output: accumulator,
         })
     }
 
-    /// Accumulates output from verilator's `stdout`.
-    pub fn accumulate(&mut self, timeout: Duration) -> Result<()> {
-        let mut buf = [0u8; 256];
-        file::wait_read_timeout(&self.stdout, timeout)?;
-        let n = self.stdout.read(&mut buf)?;
-        let s = String::from_utf8_lossy(&buf[..n]);
-        self.accumulated_output.push_str(&s);
-        Ok(())
-    }
-
     /// Finds a string within the verilator output.
     /// It is assumed that the [`Regex`] `re` has exactly one capture group.
     pub fn find(&mut self, re: &Regex, timeout: Duration) -> Result<String> {
@@ -82,28 +75,24 @@
         // and thus expect a capture length of two.
         assert_eq!(re.captures_len(), 2);
         let deadline = Instant::now() + timeout;
-        loop {
-            if let Some(captures) = re.captures(&self.accumulated_output) {
-                let val = captures.get(1).expect("expected a capture");
-                return Ok(val.as_str().to_owned());
-            } else {
-                self.accumulate(deadline.saturating_duration_since(Instant::now()))?;
+        while deadline > Instant::now() {
+            {
+                let a = self.accumulated_output.lock().unwrap();
+                if let Some(captures) = re.captures(&a.as_str()) {
+                    let val = captures.get(1).expect("expected a capture");
+                    return Ok(val.as_str().to_owned());
+                }
             }
+            std::thread::sleep(Duration::from_millis(50));
         }
+        Err(anyhow!("Timed out"))
     }
 
     /// Kill the verilator subprocess.
     pub fn kill(&mut self) -> Result<()> {
         match self.child.kill() {
-            Ok(_) => Ok(()),
-            Err(error) => {
-                if error.kind() == ErrorKind::InvalidInput {
-                    // Don't care if the child has already exited.
-                    Ok(())
-                } else {
-                    Err(error.into())
-                }
-            }
+            Err(error) if error.kind() != ErrorKind::InvalidInput => Err(error.into()),
+            _ => Ok(()),
         }
     }
 }