Add an interactive verilator test for hello_world

Add a run script to test the verilator testbench of hello_world, and
check the input/output result between UART and GPIO.

The test is included in //sw/device/tests:verilator_test_suite

Change-Id: Ia62d5a7e34a21586d8f042c93b2e8a78c229dcbe
diff --git a/hw/BUILD b/hw/BUILD
index ef96f16..ff9c76c 100644
--- a/hw/BUILD
+++ b/hw/BUILD
@@ -8,7 +8,6 @@
 
 package(default_visibility = ["//visibility:public"])
 
-
 # This configuration exposes fusesoc's "make_options" to enable parallel
 # compilation of the verilated model.
 string_list_flag(
@@ -41,6 +40,12 @@
     target = "sim",
 )
 
+filegroup(
+    name = "verilator_bin",
+    srcs = [":verilator_real"],
+    output_group = "binary",
+)
+
 # This is used in CI steps that do not want to run Verilator tests, and thus
 # do not want to accidentally build the Verilator model. This causes the
 # //hw:verilator target to not emit any files, which will break any tests that
@@ -67,7 +72,7 @@
     name = "verilator",
     actual = select({
         ":disable_verilator_build": ":verilator_stub",
-        "//conditions:default": ":verilator_real",
+        "//conditions:default": ":verilator_bin",
     }),
     tags = ["verilator"],
     visibility = ["//visibility:public"],
diff --git a/rules/matcha_test.bzl b/rules/matcha_test.bzl
index 5d791bf..da5e54d 100644
--- a/rules/matcha_test.bzl
+++ b/rules/matcha_test.bzl
@@ -56,7 +56,7 @@
     sh_test_tags = ["verilator"] + tags
     sh_test_runner = "@//util:run_chip_verilator_sim.sh"
     sh_test_args = [
-        "$(locations %s)" % (verilator_testbench),
+        "$(location %s)" % (verilator_testbench),
         "$(location %s)" % (rom_img),
         "$(location %s)" % (sec_verilator_binary),
         "$(location %s)" % (otp_img),
diff --git a/sw/device/examples/hello_world/BUILD b/sw/device/examples/hello_world/BUILD
index 00ddb67..fa9fce8 100644
--- a/sw/device/examples/hello_world/BUILD
+++ b/sw/device/examples/hello_world/BUILD
@@ -42,3 +42,26 @@
         "@lowrisc_opentitan//sw/device/silicon_creator/lib:manifest_def",
     ],
 )
+
+# Use shell test to run the interactive verilator test on UART and GPIO
+sh_test(
+    name = "verilator_hello_world_test",
+    timeout = "long",
+    srcs = [":run_verilator_hello_world.sh"],
+    args = [
+        "$(location //hw:verilator)",
+        "$(location //sw/device/lib/testing/test_rom:test_rom_sim_verilator_scr_vmem)",
+        "$(location :hello_world_sim_verilator_vmem)",
+        "$(location //hw/top_matcha/data:otp_img_rma)",
+    ],
+    data = [
+        ":hello_world_sim_verilator_vmem",
+        ":hello_world_test_expected_gpio.txt",
+        "//hw:verilator",
+        "//hw/top_matcha/data:otp_img_rma",
+        "//sw/device/lib/testing/test_rom:test_rom_sim_verilator_scr_vmem",
+    ],
+    tags = [
+        "verilator",
+    ],
+)
diff --git a/sw/device/examples/hello_world/hello_world_test_expected_gpio.txt b/sw/device/examples/hello_world/hello_world_test_expected_gpio.txt
new file mode 100644
index 0000000..4617c93
--- /dev/null
+++ b/sw/device/examples/hello_world/hello_world_test_expected_gpio.txt
@@ -0,0 +1,16 @@
+XXXXXXXXXXXXXXXX1111111111111111
+XXXXXXXXXXXXXXXX0000000000000000
+XXXXXXXXXXXXXXXX0110110001101100
+XXXXXXXXXXXXXXXX0110010101100101
+XXXXXXXXXXXXXXXX0110010001100100
+XXXXXXXXXXXXXXXX0010000000100000
+XXXXXXXXXXXXXXXX0110011101100111
+XXXXXXXXXXXXXXXX0111000001110000
+XXXXXXXXXXXXXXXX0110100101101001
+XXXXXXXXXXXXXXXX0110111101101111
+XXXXXXXXXXXXXXXX0010000000100000
+XXXXXXXXXXXXXXXX0111010001110100
+XXXXXXXXXXXXXXXX0110010101100101
+XXXXXXXXXXXXXXXX0111001101110011
+XXXXXXXXXXXXXXXX0111010001110100
+XXXXXXXXXXXXXXXX0000101000001010
diff --git a/sw/device/examples/hello_world/run_verilator_hello_world.sh b/sw/device/examples/hello_world/run_verilator_hello_world.sh
new file mode 100755
index 0000000..932dbdd
--- /dev/null
+++ b/sw/device/examples/hello_world/run_verilator_hello_world.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+#
+# Copyright 2023 Google LLC
+#
+# Licensed 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
+#
+#     https://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.
+
+# Run verilator interactive simulation on sw/device/examples/hello_world.
+
+function print_usage(
+  echo "Usage: run_verilator_hello_world.sh <verilator testbench> <rom binary> <flash binary> <otp binary>"
+)
+
+if [[ $1 == "--help" ]]; then
+  print_usage
+  exit 0
+fi
+
+if [[ $# -ne 4 ]]; then
+  print_usage
+  exit 1
+fi
+
+if [[ -z ${TEST_UNDECLARED_OUTPUTS_DIR} ]]; then
+  echo "The script only works under bazel test"
+  exit 1
+fi
+
+
+TEST_CYCLES=650000
+
+VCHIP_TB=$1
+ROM_BIN=$2
+FLASH_BIN=$3
+OTP_BIN=$4
+
+if [[ ! -f $(realpath ${VCHIP_TB}) ]]; then
+  echo "Verilator testbench not found. Please make sure //hw:verilator is in data."
+  exit 1
+fi
+
+if [[ ! -f $(realpath ${ROM_BIN}) ]] || [[ ! -f $(realpath ${FLASH_BIN}) ]] ||
+  [[ ! -f $(realpath ${OTP_BIN}) ]]; then
+  echo "Software binaries not found. Please make sure the targets are in data and args."
+  exit 1
+fi
+
+# Run verilator testbench in the background
+${VCHIP_TB} \
+  "--meminit=rom,${ROM_BIN}" \
+  "--meminit=flash,${FLASH_BIN}" \
+  "--meminit=otp,${OTP_BIN}" -c "${TEST_CYCLES}" &
+
+VERILATOR_PID=$!
+
+# Pipe GPIO output to a log file
+sleep 5
+cat gpio0-read | tee "${TEST_UNDECLARED_OUTPUTS_DIR}/gpio0_read.log" &
+
+# Wait for 300s to reach the end of the hello_world initialization.
+sleep 300
+echo 'led gpio test' > "${TEST_UNDECLARED_OUTPUTS_DIR}/uart0_device"
+
+# Wait up to another 350s to complete the verilator simulation.
+timeout 350 tail --pid=${VERILATOR_PID} -f /dev/null
+
+# Check results in GPIO and UART logs.
+cat "${TEST_UNDECLARED_OUTPUTS_DIR}/uart0.log" | grep -q "led gpio test" || exit 1
+
+diff -q "${TEST_UNDECLARED_OUTPUTS_DIR}/gpio0_read.log" \
+  "sw/device/examples/hello_world/hello_world_test_expected_gpio.txt" || exit 1
diff --git a/sw/device/tests/BUILD b/sw/device/tests/BUILD
index b096765..c7df613 100644
--- a/sw/device/tests/BUILD
+++ b/sw/device/tests/BUILD
@@ -577,6 +577,7 @@
         "verilator_supervisor_mode_test",
         "verilator_tlul_mailbox_test",
         "verilator_virtual_memory_test",
+        "//sw/device/examples/hello_world:verilator_hello_world_test",
         "//sw/device/tests/smc:verilator_kelvin_checksum_test",
         "//sw/device/tests/smc:verilator_kelvin_hello_test",
         "//sw/device/tests/smc:verilator_ml_top_irq_test",
diff --git a/util/run_chip_verilator_sim.sh b/util/run_chip_verilator_sim.sh
index 6358763..7819142 100755
--- a/util/run_chip_verilator_sim.sh
+++ b/util/run_chip_verilator_sim.sh
@@ -21,12 +21,6 @@
   exit 0
 fi
 
-# In bazel build the verilator target has multiple outputs, so we need to trim
-# the non-executable one.
-while [[ $1 != *"Vchip_sim_tb" ]]; do
-  shift 1
-done
-
 VCHIP_TB=$1
 ROM_BIN=$2
 FLASH_BIN=$3