[test] Implement rom_e2e_asm_watchdog bark tests

Test that the watchdog bark restarts the ROM when the bite threshold is
artificially inflated to UINT32_MAX.

This commit also modifies rom_start.S:
* it enables NMIs from the watchdog timer,
* it configures the bark and bite thresholds at 1 and 1.1 seconds,
  respectively, and
* it adds a few labels so the GDB tests can make fewer assumptions about
  the code.

Signed-off-by: Dan McArdle <dmcardle@google.com>
diff --git a/sw/device/silicon_creator/rom/e2e/BUILD b/sw/device/silicon_creator/rom/e2e/BUILD
index 70e6c03..a45668a 100644
--- a/sw/device/silicon_creator/rom/e2e/BUILD
+++ b/sw/device/silicon_creator/rom/e2e/BUILD
@@ -1499,6 +1499,7 @@
         rom_kind = "Rom",
         tags = [
             "cw310",
+            "exclusive",
             "vivado",
         ],
     )
@@ -1550,6 +1551,7 @@
         rom_kind = "Rom",
         tags = [
             "cw310",
+            "exclusive",
             "vivado",
         ],
     )
@@ -1568,6 +1570,92 @@
 # Dict that also includes an invalid redaction value for test purposes.
 REDACT = structs.to_dict(CONST.SHUTDOWN.REDACT)
 
+# Ensure that the watchdog restarts the ROM even when the bite threshold has
+# been artificially inflated.
+[
+    opentitan_gdb_fpga_cw310_test(
+        name = "rom_e2e_asm_watchdog_fpga_cw310_test_otp_" + otp_name,
+        timeout = "short",
+        gdb_script = """
+            target extended-remote :3333
+
+            echo :::: Send OpenOCD the 'reset halt' command.\\n
+            monitor reset halt
+
+            echo :::: Load ROM symbols into GDB.\\n
+            file rom.elf
+
+            echo :::: Run until we check whether ROM execution is enabled.\\n
+            break kRomStartBootMaybeHalt
+            continue
+
+            printf ":::: PC=%p. Expected PC=%p.\\n", $pc, kRomStartBootMaybeHalt
+            if $pc != kRomStartBootMaybeHalt
+                quit 42
+            end
+
+            echo :::: Pretend execution is enabled.\\n
+            set $pc = kRomStartBootExecEn
+
+            break kRomStartStoreT1ToBiteThold
+            continue
+            printf ":::: PC=%p. Expected PC=%p.\\n", $pc, kRomStartStoreT1ToBiteThold
+            if $pc != kRomStartStoreT1ToBiteThold
+                quit 43
+            end
+
+            # Set the bite threshold to UINT32_MAX. We want to exercise that the
+            # bark causes control to reach the interrupt handler.
+            set $t1 = 0xffffffff
+
+            echo :::: Run until right after configuring the watchdog timer.\\n
+            break kRomStartWatchdogEnabled
+            continue
+
+            printf ":::: PC=%p. Expected PC=%p.\\n", $pc, kRomStartWatchdogEnabled
+            if $pc != kRomStartWatchdogEnabled
+                quit 44
+            end
+
+            echo :::: Set breakpoint on NMI handler.\\n
+            delete breakpoints
+            break _asm_exception_handler
+
+            echo :::: Wait for interrupt.\\n
+            set $pc = kRomStartBootMaybeHalt
+            echo :::: Continue.\\n
+            continue
+
+            printf ":::: PC=%p. Expected PC=%p.\\n", $pc, _asm_exception_handler
+            if $pc != _asm_exception_handler
+                quit 45
+            end
+        """,
+        gdb_script_symlinks = {
+            "//sw/device/silicon_creator/rom:rom_fpga_cw310.elf": "rom.elf",
+        },
+        rom_bitstream = ":rom_otp_{}_exec_disabled".format(otp_name),
+        rom_kind = "Rom",
+        tags = [
+            "cw310",
+            "exclusive",
+            "vivado",
+        ],
+    )
+    for otp_name in OTP_CFGS_EXEC_DISABLED
+]
+
+test_suite(
+    name = "rom_e2e_asm_watchdog",
+    tags = [
+        "cw310",
+        "vivado",
+    ],
+    tests = ["rom_e2e_asm_watchdog_fpga_cw310_test_otp_" + otp_name for otp_name in OTP_CFGS_EXEC_DISABLED],
+)
+
+# Shutdown Redact Test
+
 REDACT.update({"INVALID": 0x0})
 
 [
diff --git a/sw/device/silicon_creator/rom/rom_start.S b/sw/device/silicon_creator/rom/rom_start.S
index 6965da8..a74ae49 100644
--- a/sw/device/silicon_creator/rom/rom_start.S
+++ b/sw/device/silicon_creator/rom/rom_start.S
@@ -17,10 +17,19 @@
 #include "otp_ctrl_regs.h"
 #include "pinmux_regs.h"
 #include "pwrmgr_regs.h"
+#include "rv_core_ibex_regs.h"
 #include "sensor_ctrl_regs.h"
 #include "sram_ctrl_regs.h"
 
+// This macro defines convenience labels for tests that use a debugger.
+#define LABEL_FOR_TEST(kName_) .local kName_ ; kName_: ;
+
 .equ UNIMP, 0xc0001073
+// We will configure the watchdog timers to reset the chip in the event that the
+// ROM stalls. The watchdog's bite and bark thresholds are set to 1 and 1.1
+// seconds, respectively, assuming a clock frequency of 200 kHz.
+.equ WDOG_BITE_THOLD, 0x30d400
+.equ WDOG_BARK_THOLD, WDOG_BITE_THOLD * 11 / 10
 
 /**
  * ROM interrupt vectors.
@@ -40,15 +49,15 @@
   /**
    * Initial RISC-V vectored exception/interrupt handlers.
    *
-   * After reset all interrupts are disabled. Only exceptions (interrupt 0) and
-   * non-maskable interrupts (interrupt 31) are possible. For simplicity however
-   * we just set all interrupt handlers to the same exception handler.
+   * After reset, all interrupts are disabled. Only exceptions (interrupt 0) and
+   * non-maskable interrupts (interrupt 31) are possible. For simplicity,
+   * however, we just set all interrupt handlers to the same exception handler.
    *
-   * Since the C runtime is not initialized immediately after reset the initial
+   * Since the C runtime is not initialized immediately after reset, the initial
    * interrupt vector must only call functions written in assembly. Once the C
-   * runtime is intialized the interrupt vector should be replaced.
+   * runtime is intialized, the interrupt vector should be replaced.
    *
-   * If the hardware is operating correctly the assembly interrupt handlers
+   * If the hardware is operating correctly, the assembly interrupt handlers
    * should never be called.
    *
    * Note that the Ibex reset handler (entry point) immediately follows this
@@ -136,6 +145,7 @@
   la gp, __global_pointer$
   .option pop
 
+LABEL_FOR_TEST(kRomStartBootMaybeHalt)
   // Check if we should halt here.
   li   a0, (TOP_EARLGREY_OTP_CTRL_CORE_BASE_ADDR + \
             OTP_CTRL_SW_CFG_WINDOW_REG_OFFSET)
@@ -145,7 +155,13 @@
   wfi
   j .L_halt_loop
 
+LABEL_FOR_TEST(kRomStartBootExecEn)
 .L_exec_en:
+  // Enable NMIs from the watchdog timer.
+  li t0, TOP_EARLGREY_RV_CORE_IBEX_CFG_BASE_ADDR
+  li t1, (1 << RV_CORE_IBEX_NMI_ENABLE_WDOG_EN_BIT)
+  sw t1, RV_CORE_IBEX_NMI_ENABLE_REG_OFFSET(t0)
+
   // Configure the power manager to enable resets.
   // Note: this enables all types of reset request for simplicity.
   li t0, TOP_EARLGREY_PWRMGR_AON_BASE_ADDR
@@ -156,20 +172,19 @@
   li t1, (1 << PWRMGR_CFG_CDC_SYNC_SYNC_BIT)
   sw t1, PWRMGR_CFG_CDC_SYNC_REG_OFFSET(t0)
 
-  // Setup the watchdog bite timer in order to reset the chip if the ROM stalls.
-  // The value below corresponds to 1 s for a clock frequency of 200 kHz.
-  // Since interrupts are disabled the watchdog bark will have no effect
-  // therefore the bark threshold is just set to the highest possible value.
+  // Configure the watchdog's bark and bite thresholds.
   li t0, TOP_EARLGREY_AON_TIMER_AON_BASE_ADDR
-  li t1, 0x30d40
-  sw t1, AON_TIMER_WDOG_BITE_THOLD_REG_OFFSET(t0)
-  li t1, 0xffffffff
+  li t1, WDOG_BARK_THOLD
   sw t1, AON_TIMER_WDOG_BARK_THOLD_REG_OFFSET(t0)
+  li t1, WDOG_BITE_THOLD
+LABEL_FOR_TEST(kRomStartStoreT1ToBiteThold)
+  sw t1, AON_TIMER_WDOG_BITE_THOLD_REG_OFFSET(t0)
 
   // Enable the watchdog timer.
   li t1, (1 << AON_TIMER_WDOG_CTRL_ENABLE_BIT)
   sw t1, AON_TIMER_WDOG_CTRL_REG_OFFSET(t0)
 
+LABEL_FOR_TEST(kRomStartWatchdogEnabled)
   // Clear all the machine-defined interrupts, `MEIE`, `MTIE`, and `MSIE` fields
   // of `mie`.
   li   t0, 0xFFFF0888
diff --git a/sw/device/tests/BUILD b/sw/device/tests/BUILD
index 1e2adbf..fe8047b 100644
--- a/sw/device/tests/BUILD
+++ b/sw/device/tests/BUILD
@@ -272,6 +272,11 @@
 opentitan_functest(
     name = "aon_timer_irq_test",
     srcs = ["aon_timer_irq_test.c"],
+    targets = [
+        "dv",
+        "verilator",
+        "cw310_test_rom",
+    ],
     deps = [
         "//hw/top_earlgrey/sw/autogen:top_earlgrey",
         "//sw/device/lib/base:math",
@@ -291,6 +296,11 @@
 opentitan_functest(
     name = "aon_timer_smoketest",
     srcs = ["aon_timer_smoketest.c"],
+    targets = [
+        "dv",
+        "verilator",
+        "cw310_test_rom",
+    ],
     deps = [
         "//sw/device/lib/base:mmio",
         "//sw/device/lib/dif:aon_timer",
@@ -853,6 +863,11 @@
 opentitan_functest(
     name = "flash_ctrl_idle_low_power_test",
     srcs = ["flash_ctrl_idle_low_power_test.c"],
+    targets = [
+        "dv",
+        "verilator",
+        "cw310_test_rom",
+    ],
     verilator = verilator_params(
         tags = [
             "broken",