Add sysrst_ctrl tests to edacloud

Change-Id: I8cab45d4a37d1fc9e88e268c11b90e505de126d7
diff --git a/hw/top_matcha/dv/chip_sim_cfg.hjson b/hw/top_matcha/dv/chip_sim_cfg.hjson
index d9cf1d4..6b01b1a 100644
--- a/hw/top_matcha/dv/chip_sim_cfg.hjson
+++ b/hw/top_matcha/dv/chip_sim_cfg.hjson
@@ -1152,32 +1152,32 @@
     {
       name: chip_sw_sysrst_ctrl_inputs
       uvm_test_seq: chip_sw_sysrst_ctrl_inputs_vseq
-      sw_images: ["//sw/device/tests/sim_dv:sysrst_ctrl_inputs_test:1"]
+      sw_images: ["//sw/device/tests/sim_dv:sysrst_ctrl_inputs_test:1:matcha"]
       en_run_modes: ["sw_test_mode_test_rom"]
     }
     {
       name: chip_sw_sysrst_ctrl_in_irq
       uvm_test_seq: chip_sw_sysrst_ctrl_in_irq_vseq
-      sw_images: ["//sw/device/tests/sim_dv:sysrst_ctrl_in_irq_test:1"]
+      sw_images: ["//sw/device/tests/sim_dv:sysrst_ctrl_in_irq_test:1:matcha"]
       en_run_modes: ["sw_test_mode_test_rom"]
     }
     {
       name: chip_sw_sysrst_ctrl_ulp_z3_wakeup
       uvm_test_seq: chip_sw_sysrst_ctrl_ulp_z3_wakeup_vseq
-      sw_images: ["//sw/device/tests/sim_dv:sysrst_ctrl_ulp_z3_wakeup_test:1"]
+      sw_images: ["//sw/device/tests/sim_dv:sysrst_ctrl_ulp_z3_wakeup_test:1:matcha"]
       en_run_modes: ["sw_test_mode_test_rom"]
     }
     {
       name: chip_sw_sysrst_ctrl_reset
       uvm_test_seq: chip_sw_sysrst_ctrl_reset_vseq
-      sw_images: ["//sw/device/tests/sim_dv:sysrst_ctrl_reset_test:1"]
+      sw_images: ["//sw/device/tests/sim_dv:sysrst_ctrl_reset_test:1:matcha"]
       en_run_modes: ["sw_test_mode_test_rom"]
       run_opts: ["+sw_test_timeout_ns=36_000_000"]
     }
     {
       name: chip_sw_sysrst_ctrl_outputs
       uvm_test_seq: chip_sw_sysrst_ctrl_outputs_vseq
-      sw_images: ["//sw/device/tests/sim_dv:sysrst_ctrl_outputs_test:1"]
+      sw_images: ["//sw/device/tests/sim_dv:sysrst_ctrl_outputs_test:1:matcha"]
       en_run_modes: ["sw_test_mode_test_rom"]
     }
     {
@@ -2051,6 +2051,7 @@
         "chip_sw_spi_device_tx_rx",
         "chip_sw_spi_host_tx_rx",
         "chip_sw_sram_ctrl_smoketest",
+        "chip_sw_sysrst_ctrl_inputs",
         "chip_sw_uart_smoketest",
         "chip_sw_uart_tx_rx",
       ]
@@ -2136,6 +2137,11 @@
         "chip_sw_spi_device_tx_rx",
         "chip_sw_spi_host_tx_rx",
         "chip_sw_sram_ctrl_smoketest",
+        "chip_sw_sysrst_ctrl_in_irq",
+        "chip_sw_sysrst_ctrl_inputs",
+        "chip_sw_sysrst_ctrl_outputs",
+        "chip_sw_sysrst_ctrl_reset",
+        "chip_sw_sysrst_ctrl_ulp_z3_wakeup",
         "chip_sw_uart_smoketest",
         "chip_sw_uart_tx_rx",
         "chip_tap_straps_dev",
@@ -2233,6 +2239,11 @@
         "chip_sw_spi_host_tx_rx",
         "chip_sw_sram_ctrl_smoketest",
         "chip_sw_uart_smoketest",
+        "chip_sw_sysrst_ctrl_in_irq",
+        "chip_sw_sysrst_ctrl_inputs",
+        "chip_sw_sysrst_ctrl_outputs",
+        "chip_sw_sysrst_ctrl_reset",
+        "chip_sw_sysrst_ctrl_ulp_z3_wakeup",
         "chip_sw_uart_tx_rx",
         "chip_tap_straps_dev",
         "chip_tap_straps_prod",
diff --git a/hw/top_matcha/dv/env/chip_if.sv b/hw/top_matcha/dv/env/chip_if.sv
index a5efa22..1d957a2 100644
--- a/hw/top_matcha/dv/env/chip_if.sv
+++ b/hw/top_matcha/dv/env/chip_if.sv
@@ -484,7 +484,7 @@
   // Functional (muxed) interface: Pin wake up signal.
   // TODO: For these tests, use chip_pins_if instead, so that any pin can be configured to wakeup.
   pins_if #(.Width(1), .PullStrength("Weak")) pinmux_wkup_if(
-    .pins(mios[top_matcha_pkg::MioPadIob7])
+    .pins(mios[top_matcha_pkg::MioPadIod4])
   );
 
   // Functional (muxed) interface: UARTs.
diff --git a/hw/top_matcha/dv/env/seq_lib/chip_sw_sysrst_ctrl_ulp_z3_wakeup_vseq.sv b/hw/top_matcha/dv/env/seq_lib/chip_sw_sysrst_ctrl_ulp_z3_wakeup_vseq.sv
index 820f1a7..a143161 100644
--- a/hw/top_matcha/dv/env/seq_lib/chip_sw_sysrst_ctrl_ulp_z3_wakeup_vseq.sv
+++ b/hw/top_matcha/dv/env/seq_lib/chip_sw_sysrst_ctrl_ulp_z3_wakeup_vseq.sv
@@ -1,3 +1,4 @@
+// Copyright 2023 Google LLC.
 // Copyright lowRISC contributors.
 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
 // SPDX-License-Identifier: Apache-2.0
@@ -66,7 +67,7 @@
 
   virtual function void check_wakeup_pin();
     logic wakeup_result;
-    // Read PAD_Z3WAKEUP_PATH <-> IOB7
+    // Read PAD_Z3WAKEUP_PATH <-> IOD4
     wakeup_result = cfg.chip_vif.pinmux_wkup_if.sample_pin(0);
     `DV_CHECK_EQ_FATAL(wakeup_result, 1'b1);
   endfunction
@@ -84,10 +85,7 @@
   virtual task body();
     super.body();
 
-    // TODO(lowRISC/opentitan:#13373): Revisit pad assignments.
-    // pinmux_wkup_vif (at Iob7) is re-used for PinZ3WakeupOut
-    // due to lack of unused pins. Disable the default drive
-    // to this pin.
+    // Disable the default drive on pinmux_wkup_if (Iod4)
     cfg.chip_vif.pinmux_wkup_if.drive_en_pin(0, 0);
 
     write_test_phase(PHASE_INIT);
diff --git a/sw/device/tests/sim_dv/BUILD b/sw/device/tests/sim_dv/BUILD
index 621ecc8..c45c6f5 100644
--- a/sw/device/tests/sim_dv/BUILD
+++ b/sw/device/tests/sim_dv/BUILD
@@ -255,6 +255,66 @@
     ],
 )
 
+cc_library(
+    name = "sysrst_ctrl_test_lib",
+    deps = [
+        "//sw/device/lib/dif:pinmux",
+        "//sw/device/tests:test_dv_lib",
+        "@lowrisc_opentitan//sw/device/lib/dif:sysrst_ctrl",
+    ],
+)
+
+matcha_dv_test(
+    name = "sysrst_ctrl_inputs_test",
+    srcs = ["sysrst_ctrl_inputs_test.c"],
+    deps = [
+        ":sysrst_ctrl_test_lib",
+    ],
+)
+
+matcha_dv_test(
+    name = "sysrst_ctrl_in_irq_test",
+    srcs = ["sysrst_ctrl_in_irq_test.c"],
+    deps = [
+        ":sysrst_ctrl_test_lib",
+        "@lowrisc_opentitan//sw/device/lib/testing:rv_plic_testutils",
+    ],
+)
+
+matcha_dv_test(
+    name = "sysrst_ctrl_ulp_z3_wakeup_test",
+    srcs = ["sysrst_ctrl_ulp_z3_wakeup_test.c"],
+    deps = [
+        ":sysrst_ctrl_test_lib",
+        "//sw/device/lib/dif:rstmgr",
+        "@lowrisc_opentitan//sw/device/lib/dif:pwrmgr",
+        "@lowrisc_opentitan//sw/device/lib/testing:flash_ctrl_testutils",
+        "@lowrisc_opentitan//sw/device/lib/testing:pwrmgr_testutils",
+        "@lowrisc_opentitan//sw/device/lib/testing:rstmgr_testutils",
+    ],
+)
+
+matcha_dv_test(
+    name = "sysrst_ctrl_reset_test",
+    srcs = ["sysrst_ctrl_reset_test.c"],
+    deps = [
+        ":sysrst_ctrl_test_lib",
+        "//sw/device/lib/dif:rstmgr",
+        "@lowrisc_opentitan//sw/device/lib/dif:pwrmgr",
+        "@lowrisc_opentitan//sw/device/lib/testing:pwrmgr_testutils",
+        "@lowrisc_opentitan//sw/device/lib/testing:rstmgr_testutils",
+    ],
+)
+
+matcha_dv_test(
+    name = "sysrst_ctrl_outputs_test",
+    srcs = ["sysrst_ctrl_outputs_test.c"],
+    deps = [
+        ":sysrst_ctrl_test_lib",
+        "@lowrisc_opentitan//sw/device/lib/testing:flash_ctrl_testutils",
+    ],
+)
+
 ################################################################################
 #  Place the Opentitan-sourced DV test below.                                  #
 #  Opentitan DV binary build flow does not support centOS7, so we pull the     #
diff --git a/sw/device/tests/sim_dv/pwrmgr_sleep_all_wake_ups_impl.c b/sw/device/tests/sim_dv/pwrmgr_sleep_all_wake_ups_impl.c
index a452741..c6bd27a 100644
--- a/sw/device/tests/sim_dv/pwrmgr_sleep_all_wake_ups_impl.c
+++ b/sw/device/tests/sim_dv/pwrmgr_sleep_all_wake_ups_impl.c
@@ -89,7 +89,7 @@
   dif_pinmux_wakeup_config_t detector_cfg = {
       .signal_filter = kDifToggleDisabled,
       .pad_type = kDifPinmuxPadKindMio,
-      .pad_select = kTopMatchaPinmuxInselIob7,
+      .pad_select = kTopMatchaPinmuxInselIod4,
       .mode = kDifPinmuxWakeupModePositiveEdge,
       .counter_threshold = 0 /* Don't need for posedge detection */,
   };
diff --git a/sw/device/tests/sim_dv/sysrst_ctrl_in_irq_test.c b/sw/device/tests/sim_dv/sysrst_ctrl_in_irq_test.c
new file mode 100644
index 0000000..92bb3f2
--- /dev/null
+++ b/sw/device/tests/sim_dv/sysrst_ctrl_in_irq_test.c
@@ -0,0 +1,247 @@
+// Copyright 2023 Google LLC.
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "hw/top_matcha/sw/autogen/top_matcha.h"
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/dif/dif_pinmux.h"
+#include "sw/device/lib/dif/dif_rv_plic.h"
+#include "sw/device/lib/dif/dif_sysrst_ctrl.h"
+#include "sw/device/lib/runtime/ibex.h"
+#include "sw/device/lib/runtime/irq.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/rv_plic_testutils.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_main.h"
+
+OTTF_DEFINE_TEST_CONFIG();
+
+static dif_sysrst_ctrl_t sysrst_ctrl;
+static dif_rv_plic_t plic;
+
+enum {
+  kCurrentTestPhaseTimeoutUsec = 20,
+  kPlicTarget = kTopMatchaPlicTargetIbex0,
+};
+
+static volatile dif_sysrst_ctrl_irq_t irq;
+static volatile top_matcha_plic_peripheral_t peripheral;
+dif_rv_plic_irq_id_t irq_id;
+
+// Test phase written by testbench.
+static volatile const uint8_t kCurrentTestPhase = 0;
+uint8_t phase = 0;
+
+enum {
+  kOutputNumPads = 0x8,
+  kOutputNunMioPads = 0x6,
+};
+
+static const dif_pinmux_index_t kPeripheralInputs[] = {
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey0In,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey1In,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey2In,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonPwrbIn,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonAcPresent,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonLidOpen,
+};
+
+static const dif_pinmux_index_t kInputPads[] = {
+    kTopMatchaPinmuxInselIob3, kTopMatchaPinmuxInselIob6,
+    kTopMatchaPinmuxInselIob8, kTopMatchaPinmuxInselIor13,
+    kTopMatchaPinmuxInselIoc7, kTopMatchaPinmuxInselIoc9,
+};
+
+static const dif_sysrst_ctrl_pin_t kSysrstCtrlInputs[] = {
+    kDifSysrstCtrlPinKey0In,           kDifSysrstCtrlPinKey1In,
+    kDifSysrstCtrlPinKey2In,           kDifSysrstCtrlPinPowerButtonIn,
+    kDifSysrstCtrlPinAcPowerPresentIn, kDifSysrstCtrlPinLidOpenIn,
+    kDifSysrstCtrlPinEcResetInOut,     kDifSysrstCtrlPinFlashWriteProtectInOut,
+};
+
+void test_phase_sync() {
+  test_status_set(kTestStatusInTest);
+  test_status_set(kTestStatusInWfi);
+}
+
+/**
+ * Configure for input change detection, sync with DV side, wait for input
+ * change interrupt, check the interrupt cause and clear it.
+ */
+void sysrst_ctrl_input_change_detect(
+    dif_sysrst_ctrl_key_intr_src_t expected_key_intr_src) {
+  peripheral = UINT32_MAX;
+  IBEX_SPIN_FOR(phase++ == kCurrentTestPhase, kCurrentTestPhaseTimeoutUsec);
+
+  // Configure for input change.
+  dif_sysrst_ctrl_input_change_config_t config = {
+      .input_changes = (dif_sysrst_ctrl_input_change_t)expected_key_intr_src,
+      .debounce_time_threshold = 1,  // 5us
+  };
+  CHECK_DIF_OK(
+      dif_sysrst_ctrl_input_change_detect_configure(&sysrst_ctrl, config));
+
+  test_phase_sync();
+
+  IBEX_SPIN_FOR(phase++ == kCurrentTestPhase, kCurrentTestPhaseTimeoutUsec);
+  // Check that the interrupt isn't triggered at the first part of the test.
+  CHECK(peripheral == UINT32_MAX,
+        "The interrupt is triggered during input glitch.");
+  test_phase_sync();
+
+  wait_for_interrupt();
+  // Check that the interrupt is triggered at the second part of the test.
+  CHECK(peripheral == kTopMatchaPlicPeripheralSysrstCtrlAon,
+        "The interrupt is not triggered during the test.");
+  CHECK(irq_id == kTopMatchaPlicIrqIdSysrstCtrlAonEventDetected,
+        "Wrong irq_id");
+
+  uint32_t causes;
+  CHECK_DIF_OK(
+      dif_sysrst_ctrl_input_change_irq_get_causes(&sysrst_ctrl, &causes));
+  CHECK(causes == expected_key_intr_src, "Intr cause do not match: %d vs %d!",
+        causes, (int)expected_key_intr_src);
+
+  CHECK_DIF_OK(
+      dif_sysrst_ctrl_input_change_irq_clear_causes(&sysrst_ctrl, causes));
+
+  // Reset configuration for input change.
+  config.input_changes = 0;
+  CHECK_DIF_OK(
+      dif_sysrst_ctrl_input_change_detect_configure(&sysrst_ctrl, config));
+}
+
+/**
+ * Configure for key combo change detection, sync with DV side, wait for input
+ * change interrupt, check the interrupt cause and clear it.
+ */
+void sysrst_ctrl_key_combo_detect(dif_sysrst_ctrl_key_combo_t key_combo,
+                                  uint32_t combo_keys) {
+  peripheral = UINT32_MAX;
+  IBEX_SPIN_FOR(phase++ == kCurrentTestPhase, kCurrentTestPhaseTimeoutUsec);
+
+  // Configure for key combo
+  dif_sysrst_ctrl_key_combo_config_t sysrst_ctrl_key_combo_config = {
+      .keys = combo_keys,
+      .detection_time_threshold = 1,
+      .actions = kDifSysrstCtrlKeyComboActionInterrupt,
+      .embedded_controller_reset_duration = 1,
+  };
+  CHECK_DIF_OK(dif_sysrst_ctrl_key_combo_detect_configure(
+      &sysrst_ctrl, key_combo, sysrst_ctrl_key_combo_config));
+
+  test_phase_sync();
+
+  IBEX_SPIN_FOR(phase++ == kCurrentTestPhase, kCurrentTestPhaseTimeoutUsec);
+  // Check that the interrupt isn't triggered at the first part of the test.
+  CHECK(peripheral == UINT32_MAX,
+        "The interrupt is triggered during input glitch.");
+  test_phase_sync();
+
+  wait_for_interrupt();
+  // Check that the interrupt is triggered at the second part of the test.
+  CHECK(peripheral == kTopMatchaPlicPeripheralSysrstCtrlAon,
+        "The interrupt is not triggered during the test.");
+  CHECK(irq_id == kTopMatchaPlicIrqIdSysrstCtrlAonEventDetected,
+        "Wrong irq_id");
+
+  uint32_t causes;
+  CHECK_DIF_OK(dif_sysrst_ctrl_key_combo_irq_get_causes(&sysrst_ctrl, &causes));
+  CHECK(causes == key_combo, "Intr cause do not match: %d vs %d!", causes,
+        (int)key_combo);
+
+  CHECK_DIF_OK(
+      dif_sysrst_ctrl_key_combo_irq_clear_causes(&sysrst_ctrl, causes));
+
+  // Reset configuration for key combo.
+  sysrst_ctrl_key_combo_config.keys = 0;
+  CHECK_DIF_OK(dif_sysrst_ctrl_key_combo_detect_configure(
+      &sysrst_ctrl, key_combo, sysrst_ctrl_key_combo_config));
+}
+
+/**
+ * External interrupt handler.
+ */
+void ottf_external_isr(void) {
+  CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic, kPlicTarget, &irq_id));
+
+  peripheral = (top_matcha_plic_peripheral_t)
+      top_matcha_plic_interrupt_for_peripheral[irq_id];
+
+  if (peripheral == kTopMatchaPlicPeripheralSysrstCtrlAon) {
+    irq =
+        (dif_sysrst_ctrl_irq_t)(irq_id -
+                                (dif_rv_plic_irq_id_t)
+                                    kTopMatchaPlicIrqIdSysrstCtrlAonEventDetected);
+    CHECK_DIF_OK(dif_sysrst_ctrl_irq_acknowledge(&sysrst_ctrl, irq));
+  }
+
+  // Complete the IRQ by writing the IRQ source to the Ibex specific CC.
+  // register.
+  CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic, kPlicTarget, irq_id));
+}
+
+bool test_main(void) {
+  // Enable global and external IRQ at Ibex.
+  irq_global_ctrl(true);
+  irq_external_ctrl(true);
+
+  // Initialize the PLIC.
+  mmio_region_t plic_base_addr =
+      mmio_region_from_addr(TOP_MATCHA_RV_PLIC_BASE_ADDR);
+  CHECK_DIF_OK(dif_rv_plic_init(plic_base_addr, &plic));
+
+  // Enable all the SYSRST CTRL interrupts on PLIC.
+  rv_plic_testutils_irq_range_enable(
+      &plic, kPlicTarget, kTopMatchaPlicIrqIdSysrstCtrlAonEventDetected,
+      kTopMatchaPlicIrqIdSysrstCtrlAonEventDetected);
+
+  // Initialize sysrst ctrl.
+  CHECK_DIF_OK(dif_sysrst_ctrl_init(
+      mmio_region_from_addr(TOP_MATCHA_SYSRST_CTRL_AON_BASE_ADDR),
+      &sysrst_ctrl));
+
+  // Enable sysrst ctrl irq.
+  dif_toggle_t irq_state = kDifToggleEnabled;
+  CHECK_DIF_OK(dif_sysrst_ctrl_irq_set_enabled(
+      &sysrst_ctrl, kDifSysrstCtrlIrqEventDetected, irq_state));
+
+  // Set input pins.
+  dif_pinmux_t pinmux;
+  CHECK_DIF_OK(dif_pinmux_init(
+      mmio_region_from_addr(TOP_MATCHA_PINMUX_AON_BASE_ADDR), &pinmux));
+  for (int i = 0; i < kOutputNunMioPads; ++i) {
+    CHECK_DIF_OK(
+        dif_pinmux_input_select(&pinmux, kPeripheralInputs[i], kInputPads[i]));
+  }
+
+  // Test 14 different input transition. 7 L2H and 7 H2L input transition.
+  for (dif_sysrst_ctrl_key_intr_src_t i =
+           kDifSysrstCtrlKeyIntrStatusInputPowerButtonH2L;
+       i <= kDifSysrstCtrlKeyIntrStatusInputFlashWriteProtectL2H; i = i << 1) {
+    sysrst_ctrl_input_change_detect(i);
+  }
+
+  // Test 4 different combo key intr sources with 2, 3, 4 and 5 combo key
+  // transition H2L.
+  uint32_t combo_keys_0 = kDifSysrstCtrlKeyPowerButton | kDifSysrstCtrlKey0;
+  sysrst_ctrl_key_combo_detect(kDifSysrstCtrlKeyCombo0, combo_keys_0);
+
+  uint32_t combo_keys_1 =
+      kDifSysrstCtrlKey1 | kDifSysrstCtrlKey2 | kDifSysrstCtrlKeyAcPowerPresent;
+  sysrst_ctrl_key_combo_detect(kDifSysrstCtrlKeyCombo1, combo_keys_1);
+
+  uint32_t combo_keys_2 = kDifSysrstCtrlKeyPowerButton | kDifSysrstCtrlKey0 |
+                          kDifSysrstCtrlKey2 | kDifSysrstCtrlKeyAcPowerPresent;
+  sysrst_ctrl_key_combo_detect(kDifSysrstCtrlKeyCombo2, combo_keys_2);
+
+  uint32_t combo_keys_3 = kDifSysrstCtrlKeyPowerButton | kDifSysrstCtrlKey0 |
+                          kDifSysrstCtrlKey1 | kDifSysrstCtrlKey2 |
+                          kDifSysrstCtrlKeyAcPowerPresent;
+  sysrst_ctrl_key_combo_detect(kDifSysrstCtrlKeyCombo3, combo_keys_3);
+
+  // Last sync with dv side.
+  test_status_set(kTestStatusInTest);
+  return true;
+}
diff --git a/sw/device/tests/sim_dv/sysrst_ctrl_inputs_test.c b/sw/device/tests/sim_dv/sysrst_ctrl_inputs_test.c
new file mode 100644
index 0000000..93a6a10
--- /dev/null
+++ b/sw/device/tests/sim_dv/sysrst_ctrl_inputs_test.c
@@ -0,0 +1,88 @@
+// Copyright 2023 Google LLC.
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "hw/top_matcha/sw/autogen/top_matcha.h"
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/dif/dif_pinmux.h"
+#include "sw/device/lib/dif/dif_sysrst_ctrl.h"
+#include "sw/device/lib/runtime/ibex.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_main.h"
+
+OTTF_DEFINE_TEST_CONFIG();
+
+static dif_sysrst_ctrl_t sysrst_ctrl;
+const uint32_t kTestPhaseTimeoutUsec = 10;
+const uint32_t kNumPhases = 10;
+
+// Test phase and expected values written by testbench.
+static volatile const uint8_t kTestPhase = 0;
+static volatile const uint8_t kTestExpected = 0;
+
+enum {
+  kOutputNumPads = 0x8,
+  kOutputNunMioPads = 0x6,
+};
+
+static const dif_pinmux_index_t kPeripheralInputs[] = {
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey0In,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey1In,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey2In,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonPwrbIn,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonAcPresent,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonLidOpen,
+};
+
+static const dif_pinmux_index_t kInputPads[] = {
+    kTopMatchaPinmuxInselIob3, kTopMatchaPinmuxInselIob6,
+    kTopMatchaPinmuxInselIob8, kTopMatchaPinmuxInselIor13,
+    kTopMatchaPinmuxInselIoc7, kTopMatchaPinmuxInselIoc9,
+};
+
+static const dif_sysrst_ctrl_pin_t kSysrstCtrlInputs[] = {
+    kDifSysrstCtrlPinKey0In,           kDifSysrstCtrlPinKey1In,
+    kDifSysrstCtrlPinKey2In,           kDifSysrstCtrlPinPowerButtonIn,
+    kDifSysrstCtrlPinAcPowerPresentIn, kDifSysrstCtrlPinLidOpenIn,
+    kDifSysrstCtrlPinEcResetInOut,     kDifSysrstCtrlPinFlashWriteProtectInOut,
+};
+
+static uint8_t read_input_pins(void) {
+  bool input_value;
+  uint8_t inputs = 0;
+  for (int i = 0; i < kOutputNumPads; ++i) {
+    CHECK_DIF_OK(dif_sysrst_ctrl_input_pin_read(
+        &sysrst_ctrl, kSysrstCtrlInputs[i], &input_value));
+    inputs |= input_value << i;
+  }
+  return inputs;
+}
+
+bool test_main(void) {
+  CHECK_DIF_OK(dif_sysrst_ctrl_init(
+      mmio_region_from_addr(TOP_MATCHA_SYSRST_CTRL_AON_BASE_ADDR),
+      &sysrst_ctrl));
+
+  dif_pinmux_t pinmux;
+  CHECK_DIF_OK(dif_pinmux_init(
+      mmio_region_from_addr(TOP_MATCHA_PINMUX_AON_BASE_ADDR), &pinmux));
+
+  for (int i = 0; i < kOutputNunMioPads; ++i) {
+    CHECK_DIF_OK(
+        dif_pinmux_input_select(&pinmux, kPeripheralInputs[i], kInputPads[i]));
+  }
+  for (int i = 0; i < kNumPhases; ++i) {
+    IBEX_SPIN_FOR(i == kTestPhase, kTestPhaseTimeoutUsec);
+    uint8_t input_pins = read_input_pins();
+    CHECK(kTestExpected == input_pins);
+    // Test status set to InTest then Wfi for testbench synchronization,
+    // an actual WFI instruction is not issued.
+    test_status_set(kTestStatusInTest);
+    test_status_set(kTestStatusInWfi);
+  }
+
+  test_status_set(kTestStatusInTest);
+  return true;
+}
diff --git a/sw/device/tests/sim_dv/sysrst_ctrl_outputs_test.c b/sw/device/tests/sim_dv/sysrst_ctrl_outputs_test.c
new file mode 100644
index 0000000..defa174
--- /dev/null
+++ b/sw/device/tests/sim_dv/sysrst_ctrl_outputs_test.c
@@ -0,0 +1,179 @@
+// Copyright 2023 Google LLC.
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "hw/top_matcha/sw/autogen/top_matcha.h"
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/dif/dif_pinmux.h"
+#include "sw/device/lib/dif/dif_sysrst_ctrl.h"
+#include "sw/device/lib/runtime/ibex.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/flash_ctrl_testutils.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_main.h"
+
+OTTF_DEFINE_TEST_CONFIG();
+
+static dif_pinmux_t pinmux;
+static dif_sysrst_ctrl_t sysrst_ctrl;
+static dif_flash_ctrl_state_t flash;
+
+const uint32_t kTestPhaseTimeoutUsec = 100;
+
+enum {
+  kTestPhaseSetup = 0,
+  kTestPhaseLoopback = 1,
+  kTestPhaseOverrideSetup = 2,
+  kTestPhaseOverrideZeros = 3,
+  kTestPhaseOverrideOnes = 4,
+  kTestPhaseOverrideRelease = 5,
+  kTestPhaseOverrideAndLoopback = 6,
+  kTestPhaseDone = 7,
+};
+
+enum {
+  kAllZero = 0x0,
+  kAllOne = 0xff,
+  kLoopbackPartial = 0x5,
+  kNumMioInputs = 0x4,
+  kNumMioOutputs = 0x6,
+  kOutputNumPads = 0x8,
+};
+
+static const dif_pinmux_index_t kPeripheralInputs[] = {
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey0In,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey1In,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey2In,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonPwrbIn,
+};
+
+static const dif_pinmux_index_t kInputPads[] = {
+    kTopMatchaPinmuxInselIob3,
+    kTopMatchaPinmuxInselIob6,
+    kTopMatchaPinmuxInselIob8,
+    kTopMatchaPinmuxInselIor13,
+};
+
+static const dif_pinmux_index_t kPeripheralOutputs[] = {
+    kTopMatchaPinmuxOutselSysrstCtrlAonKey0Out,
+    kTopMatchaPinmuxOutselSysrstCtrlAonKey1Out,
+    kTopMatchaPinmuxOutselSysrstCtrlAonKey2Out,
+    kTopMatchaPinmuxOutselSysrstCtrlAonPwrbOut,
+    kTopMatchaPinmuxOutselSysrstCtrlAonBatDisable,
+    kTopMatchaPinmuxOutselSysrstCtrlAonZ3Wakeup,
+};
+
+static const dif_pinmux_index_t kOutputPads[] = {
+    kTopMatchaPinmuxMioOutIob9, kTopMatchaPinmuxMioOutIor5,
+    kTopMatchaPinmuxMioOutIor6, kTopMatchaPinmuxMioOutIoc7,
+    kTopMatchaPinmuxMioOutIoc9, kTopMatchaPinmuxMioOutIod4,
+};
+
+static const dif_sysrst_ctrl_pin_t kSysrstCtrlOutputs[] = {
+    kDifSysrstCtrlPinKey0Out,           kDifSysrstCtrlPinKey1Out,
+    kDifSysrstCtrlPinKey2Out,           kDifSysrstCtrlPinPowerButtonOut,
+    kDifSysrstCtrlPinBatteryDisableOut, kDifSysrstCtrlPinZ3WakeupOut,
+    kDifSysrstCtrlPinEcResetInOut,      kDifSysrstCtrlPinFlashWriteProtectInOut,
+};
+
+// Test phase written by testbench.
+static volatile const uint8_t kTestPhase = 0;
+
+// Sets up the pinmux to assign input and output pads
+// to the sysrst_ctrl peripheral as required.
+static void pinmux_setup(void) {
+  for (int i = 0; i < kNumMioInputs; ++i) {
+    CHECK_DIF_OK(
+        dif_pinmux_input_select(&pinmux, kPeripheralInputs[i], kInputPads[i]));
+  }
+  for (int i = 0; i < kNumMioOutputs; ++i) {
+    CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kOutputPads[i],
+                                          kPeripheralOutputs[i]));
+  }
+}
+
+// Waits for the kTestPhase variable to be changed by a backdoor overwrite
+// from the testbench in `chip_sw_sysrst_ctrl_ec_rst_l_vseq.sv`. This will
+// indicate that the testbench is ready to proceed with the next phase of the
+// test. The function `flash_ctrl_testutils_backdoor_wait_update` it's used to
+// deal with possible caching that can prevent the software to read the new
+// value of `kTestPhase`.
+static void sync_with_testbench(void) {
+  // Set WFI status for testbench synchronization,
+  // no actual WFI instruction is issued.
+  test_status_set(kTestStatusInWfi);
+  test_status_set(kTestStatusInTest);
+  flash_ctrl_testutils_backdoor_wait_update(&flash, (uintptr_t)&kTestPhase,
+                                            kTestPhaseTimeoutUsec);
+}
+
+// Enables the sysrst_ctrl overrides for the output pins. Allows
+// both low and high override values.
+static void override_setup(uint8_t pins_to_override) {
+  for (int i = 0; i < kOutputNumPads; ++i) {
+    if ((pins_to_override >> i) & 0x1) {
+      CHECK_DIF_OK(dif_sysrst_ctrl_output_pin_override_set_enabled(
+          &sysrst_ctrl, kSysrstCtrlOutputs[i], kDifToggleEnabled));
+      CHECK_DIF_OK(dif_sysrst_ctrl_output_pin_override_set_allowed(
+          &sysrst_ctrl, kSysrstCtrlOutputs[i], true, true));
+    }
+  }
+}
+
+// Disables the overrides. Allows the outputs to pass-through the
+// values from the relevant input pins.
+static void override_disable(void) {
+  for (int i = 0; i < kOutputNumPads; ++i) {
+    CHECK_DIF_OK(dif_sysrst_ctrl_output_pin_override_set_enabled(
+        &sysrst_ctrl, kSysrstCtrlOutputs[i], kDifToggleDisabled));
+  }
+}
+
+// Sets the values of the output overrides as required.
+static void set_output_overrides(uint8_t override_value) {
+  for (int i = 0; i < kOutputNumPads; ++i) {
+    CHECK_DIF_OK(dif_sysrst_ctrl_output_pin_set_override(
+        &sysrst_ctrl, kSysrstCtrlOutputs[i], (override_value >> i) & 0x1));
+  }
+}
+
+bool test_main(void) {
+  CHECK_DIF_OK(dif_pinmux_init(
+      mmio_region_from_addr(TOP_MATCHA_PINMUX_AON_BASE_ADDR), &pinmux));
+  CHECK_DIF_OK(dif_sysrst_ctrl_init(
+      mmio_region_from_addr(TOP_MATCHA_SYSRST_CTRL_AON_BASE_ADDR),
+      &sysrst_ctrl));
+  flash_ctrl_testutils_backdoor_init(&flash);
+
+  while (kTestPhase < kTestPhaseDone) {
+    switch (kTestPhase) {
+      case kTestPhaseSetup:
+        pinmux_setup();
+        break;
+      case kTestPhaseLoopback:
+        break;
+      case kTestPhaseOverrideSetup:
+        override_setup(kAllOne);
+        break;
+      case kTestPhaseOverrideZeros:
+        set_output_overrides(kAllZero);
+        break;
+      case kTestPhaseOverrideOnes:
+        set_output_overrides(kAllOne);
+        break;
+      case kTestPhaseOverrideRelease:
+        override_disable();
+        break;
+      case kTestPhaseOverrideAndLoopback:
+        override_setup(kLoopbackPartial);
+        set_output_overrides(kLoopbackPartial);
+        break;
+      default:
+        LOG_ERROR("Unexpected test phase : %d", kTestPhase);
+        break;
+    }
+    sync_with_testbench();
+  }
+  return true;
+}
diff --git a/sw/device/tests/sim_dv/sysrst_ctrl_reset_test.c b/sw/device/tests/sim_dv/sysrst_ctrl_reset_test.c
new file mode 100644
index 0000000..5fa723d
--- /dev/null
+++ b/sw/device/tests/sim_dv/sysrst_ctrl_reset_test.c
@@ -0,0 +1,186 @@
+// Copyright 2023 Google LLC.
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "hw/top_matcha/sw/autogen/top_matcha.h"
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/dif/dif_pinmux.h"
+#include "sw/device/lib/dif/dif_pwrmgr.h"
+#include "sw/device/lib/dif/dif_rstmgr.h"
+#include "sw/device/lib/dif/dif_sysrst_ctrl.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/pwrmgr_testutils.h"
+#include "sw/device/lib/testing/rstmgr_testutils.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_main.h"
+
+OTTF_DEFINE_TEST_CONFIG();
+
+static dif_pwrmgr_t pwrmgr;
+static dif_rstmgr_t rstmgr;
+static dif_sysrst_ctrl_t sysrst_ctrl;
+
+enum {
+  kTestPhaseCheckComboReset = 0,
+  kTestPhaseCheckDeepSleepWakeup = 1,
+  kTestPhaseCheckDeepSleepReset = 2,
+  kTestPhaseFinalCheck = 3,
+};
+
+// Threshold/Duration values are not specific to a real-world debounce
+// scenario so are kept short to avoid excessive simulation time.
+// Assuming a 5us aon clock period.
+enum {
+  kDetectionTimeThreshold = 1024,  // ~5ms
+  kEcResetDuration = 512,          // ~2.5ms
+  kDebounceTimeThreshold = 128,    // ~0.6ms
+};
+
+static volatile const uint8_t kTestPhase = 0;
+
+static void check_combo_reset(void) {
+  CHECK_DIF_OK(dif_sysrst_ctrl_key_combo_detect_configure(
+      &sysrst_ctrl, kDifSysrstCtrlKeyCombo0,
+      (dif_sysrst_ctrl_key_combo_config_t){
+          .actions = kDifSysrstCtrlKeyComboActionEcReset |
+                     kDifSysrstCtrlKeyComboActionSelfReset,
+          .detection_time_threshold = kDetectionTimeThreshold,
+          .embedded_controller_reset_duration = kEcResetDuration,
+          .keys = kDifSysrstCtrlKey0 | kDifSysrstCtrlKey1}));
+
+  CHECK_DIF_OK(dif_sysrst_ctrl_input_change_detect_configure(
+      &sysrst_ctrl, (dif_sysrst_ctrl_input_change_config_t){
+                        .debounce_time_threshold = kDebounceTimeThreshold,
+                        .input_changes = kDifSysrstCtrlInputKey0H2L |
+                                         kDifSysrstCtrlInputKey1H2L}));
+  CHECK_DIF_OK(dif_sysrst_ctrl_output_pin_override_configure(
+      &sysrst_ctrl, kDifSysrstCtrlPinFlashWriteProtectInOut,
+      (dif_sysrst_ctrl_pin_config_t){.allow_one = true,
+                                     .allow_zero = true,
+                                     .enabled = kDifToggleEnabled,
+                                     .override_value = true}));
+  // Prepare rstmgr for a reset with sysrst_ctrl (source one).
+  rstmgr_testutils_pre_reset(&rstmgr);
+  CHECK_DIF_OK(dif_pwrmgr_set_request_sources(&pwrmgr, kDifPwrmgrReqTypeReset,
+                                              kDifPwrmgrResetRequestSourceOne,
+                                              kDifToggleEnabled));
+  // Issue WFI and wait for reset condition.
+  test_status_set(kTestStatusInWfi);
+  wait_for_interrupt();
+}
+
+static void check_deep_sleep_wakeup(void) {
+  CHECK_DIF_OK(dif_sysrst_ctrl_ulp_wakeup_configure(
+      &sysrst_ctrl, (dif_sysrst_ctrl_ulp_wakeup_config_t){
+                        .ac_power_debounce_time_threshold = 0,
+                        .lid_open_debounce_time_threshold = 0,
+                        .power_button_debounce_time_threshold = 0,
+                        .enabled = kDifToggleEnabled}));
+  // Setup low power.
+  // Wakeup source is from sysrst_ctrl (source one).
+  rstmgr_testutils_pre_reset(&rstmgr);
+  pwrmgr_testutils_enable_low_power(&pwrmgr, kDifPwrmgrWakeupRequestSourceOne,
+                                    0);
+  // Issue WFI and wait for reset condition.
+  test_status_set(kTestStatusInWfi);
+  wait_for_interrupt();
+}
+
+static void check_deep_sleep_reset(void) {
+  CHECK_DIF_OK(dif_sysrst_ctrl_key_combo_detect_configure(
+      &sysrst_ctrl, kDifSysrstCtrlKeyCombo1,
+      (dif_sysrst_ctrl_key_combo_config_t){
+          .actions = kDifSysrstCtrlKeyComboActionEcReset |
+                     kDifSysrstCtrlKeyComboActionSelfReset,
+          .detection_time_threshold = kDetectionTimeThreshold,
+          .embedded_controller_reset_duration = kEcResetDuration,
+          .keys = kDifSysrstCtrlKey2 | kDifSysrstCtrlKeyPowerButton}));
+  CHECK_DIF_OK(dif_sysrst_ctrl_output_pin_override_configure(
+      &sysrst_ctrl, kDifSysrstCtrlPinFlashWriteProtectInOut,
+      (dif_sysrst_ctrl_pin_config_t){.allow_one = true,
+                                     .allow_zero = true,
+                                     .enabled = kDifToggleEnabled,
+                                     .override_value = true}));
+  CHECK_DIF_OK(dif_sysrst_ctrl_input_change_detect_configure(
+      &sysrst_ctrl, (dif_sysrst_ctrl_input_change_config_t){
+                        .debounce_time_threshold = kDebounceTimeThreshold,
+                        .input_changes = kDifSysrstCtrlInputKey2H2L |
+                                         kDifSysrstCtrlInputPowerButtonH2L}));
+  // Setup low power.
+  // Reset source is from sysrst_ctrl (source one).
+  rstmgr_testutils_pre_reset(&rstmgr);
+  CHECK_DIF_OK(dif_pwrmgr_set_request_sources(&pwrmgr, kDifPwrmgrReqTypeReset,
+                                              kDifPwrmgrResetRequestSourceOne,
+                                              kDifToggleEnabled));
+  // Enable low power with wakeup source other than
+  // sysrst_ctrl (e.g. source two) as we don't want
+  // a wakeup request but instead a reset.
+  pwrmgr_testutils_enable_low_power(&pwrmgr, kDifPwrmgrWakeupRequestSourceTwo,
+                                    0);
+  // Issue WFI and wait for reset condition.
+  test_status_set(kTestStatusInWfi);
+  wait_for_interrupt();
+}
+
+bool test_main(void) {
+  CHECK_DIF_OK(dif_pwrmgr_init(
+      mmio_region_from_addr(TOP_MATCHA_PWRMGR_AON_BASE_ADDR), &pwrmgr));
+  CHECK_DIF_OK(dif_rstmgr_init(
+      mmio_region_from_addr(TOP_MATCHA_RSTMGR_AON_BASE_ADDR), &rstmgr));
+  CHECK_DIF_OK(dif_sysrst_ctrl_init(
+      mmio_region_from_addr(TOP_MATCHA_SYSRST_CTRL_AON_BASE_ADDR),
+      &sysrst_ctrl));
+
+  dif_rstmgr_reset_info_bitfield_t rstmgr_reset_info;
+  rstmgr_reset_info = rstmgr_testutils_reason_get();
+
+  dif_pinmux_t pinmux;
+  CHECK_DIF_OK(dif_pinmux_init(
+      mmio_region_from_addr(TOP_MATCHA_PINMUX_AON_BASE_ADDR), &pinmux));
+  CHECK_DIF_OK(dif_pinmux_input_select(
+      &pinmux, kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey0In,
+      kTopMatchaPinmuxInselIob3));
+  CHECK_DIF_OK(dif_pinmux_input_select(
+      &pinmux, kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey1In,
+      kTopMatchaPinmuxInselIob6));
+  CHECK_DIF_OK(dif_pinmux_input_select(
+      &pinmux, kTopMatchaPinmuxPeripheralInSysrstCtrlAonKey2In,
+      kTopMatchaPinmuxInselIob8));
+  CHECK_DIF_OK(dif_pinmux_input_select(
+      &pinmux, kTopMatchaPinmuxPeripheralInSysrstCtrlAonPwrbIn,
+      kTopMatchaPinmuxInselIob9));
+  CHECK_DIF_OK(dif_pinmux_input_select(
+      &pinmux, kTopMatchaPinmuxPeripheralInSysrstCtrlAonAcPresent,
+      kTopMatchaPinmuxInselIoc7));
+  CHECK_DIF_OK(dif_pinmux_input_select(
+      &pinmux, kTopMatchaPinmuxPeripheralInSysrstCtrlAonLidOpen,
+      kTopMatchaPinmuxInselIoc9));
+
+  CHECK_DIF_OK(dif_sysrst_ctrl_output_pin_override_set_enabled(
+      &sysrst_ctrl, kDifSysrstCtrlPinEcResetInOut, kDifToggleDisabled));
+
+  switch (kTestPhase) {
+    case kTestPhaseCheckComboReset:
+      CHECK(rstmgr_reset_info == kDifRstmgrResetInfoPor);
+      check_combo_reset();
+      break;
+    case kTestPhaseCheckDeepSleepWakeup:
+      CHECK(rstmgr_reset_info == kDifRstmgrResetInfoSysRstCtrl);
+      check_deep_sleep_wakeup();
+      break;
+    case kTestPhaseCheckDeepSleepReset:
+      CHECK(rstmgr_reset_info == kDifRstmgrResetInfoLowPowerExit);
+      check_deep_sleep_reset();
+      break;
+    case kTestPhaseFinalCheck:
+      CHECK(rstmgr_reset_info ==
+            (kDifRstmgrResetInfoSysRstCtrl | kDifRstmgrResetInfoLowPowerExit));
+      return true;
+      break;
+    default:
+      LOG_ERROR("Unexpected test phase : %d", kTestPhase);
+      break;
+  }
+  return false;
+}
diff --git a/sw/device/tests/sim_dv/sysrst_ctrl_ulp_z3_wakeup_test.c b/sw/device/tests/sim_dv/sysrst_ctrl_ulp_z3_wakeup_test.c
new file mode 100644
index 0000000..194e75c
--- /dev/null
+++ b/sw/device/tests/sim_dv/sysrst_ctrl_ulp_z3_wakeup_test.c
@@ -0,0 +1,184 @@
+// Copyright 2023 Google LLC.
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "hw/top_matcha/sw/autogen/top_matcha.h"
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/dif/dif_pinmux.h"
+#include "sw/device/lib/dif/dif_pwrmgr.h"
+#include "sw/device/lib/dif/dif_rstmgr.h"
+#include "sw/device/lib/dif/dif_sysrst_ctrl.h"
+#include "sw/device/lib/runtime/ibex.h"
+#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/testing/flash_ctrl_testutils.h"
+#include "sw/device/lib/testing/pwrmgr_testutils.h"
+#include "sw/device/lib/testing/rstmgr_testutils.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_main.h"
+
+OTTF_DEFINE_TEST_CONFIG();
+
+// This is updated by the sv component of the test
+static volatile const uint8_t kTestPhase = 0;
+
+static dif_pwrmgr_t pwrmgr;
+static dif_rstmgr_t rstmgr;
+static dif_pinmux_t pinmux;
+static dif_sysrst_ctrl_t sysrst_ctrl;
+static dif_flash_ctrl_state_t flash;
+
+enum {
+  kNumMioInPads = 3,
+  kNumMioOutPads = 1,
+  kTestPhaseTimeoutUsec = 500,
+  // This means 20 aon_clk ticks ~= 20 * 5 us = 100 us
+  kDebounceTimer = 20,
+};
+
+enum {
+  kTestPhaseInit = 0,
+  kTestPhaseDriveZero = 1,
+  kTestPhaseWaitNoWakeup = 2,
+  kTestPhaseGlitchLidOpen = 3,
+  kTestPhaseWaitWakeup = 4,
+  kTestPhaseDone = 5,
+};
+
+static const dif_pinmux_index_t kPeripheralInputs[] = {
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonPwrbIn,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonAcPresent,
+    kTopMatchaPinmuxPeripheralInSysrstCtrlAonLidOpen,
+};
+
+static const dif_pinmux_index_t kInputPads[] = {
+    kTopMatchaPinmuxInselIor13,
+    kTopMatchaPinmuxInselIoc7,
+    kTopMatchaPinmuxInselIoc9,
+};
+
+static const dif_pinmux_index_t kPeripheralOutputs[] = {
+    kTopMatchaPinmuxOutselSysrstCtrlAonZ3Wakeup,
+};
+
+static const dif_pinmux_index_t kOutputPads[] = {
+    kTopMatchaPinmuxMioOutIod4,
+};
+
+/**
+ * Sets up the pinmux to assign input and output pads to the sysrst_ctrl
+ * peripheral as required.
+ */
+static void pinmux_setup(void) {
+  for (int i = 0; i < kNumMioInPads; ++i) {
+    CHECK_DIF_OK(
+        dif_pinmux_input_select(&pinmux, kPeripheralInputs[i], kInputPads[i]));
+  }
+
+  for (int i = 0; i < kNumMioOutPads; ++i) {
+    CHECK_DIF_OK(dif_pinmux_output_select(&pinmux, kOutputPads[i],
+                                          kPeripheralOutputs[i]));
+  }
+}
+
+/**
+ * Waits for `kTestPhase` variable to be changed by a backdoor overwrite
+ * from the testbench in chip_sw_<testname>_vseq.sv. This will indicate that
+ * the testbench is ready to proceed with the next phase of the test.
+ */
+static void wait_next_test_phase(void) {
+  // Set WFI status for testbench synchronization,
+  // no actual WFI instruction is issued.
+  test_status_set(kTestStatusInWfi);
+  test_status_set(kTestStatusInTest);
+  flash_ctrl_testutils_backdoor_wait_update(&flash, (uintptr_t)&kTestPhase,
+                                            kTestPhaseTimeoutUsec);
+}
+
+/**
+ * Configure *_debounce_ctl and then enable ULP wakeup.
+ */
+static void configure_wakeup(void) {
+  dif_sysrst_ctrl_ulp_wakeup_config_t wakeup_config;
+
+  // Keep toggle disabled when writing debounce configuration
+  wakeup_config.enabled = kDifToggleDisabled;
+  wakeup_config.ac_power_debounce_time_threshold = kDebounceTimer;
+  wakeup_config.lid_open_debounce_time_threshold = kDebounceTimer;
+  wakeup_config.power_button_debounce_time_threshold = kDebounceTimer;
+
+  CHECK_DIF_OK(
+      dif_sysrst_ctrl_ulp_wakeup_configure(&sysrst_ctrl, wakeup_config));
+
+  CHECK_DIF_OK(
+      dif_sysrst_ctrl_ulp_wakeup_set_enabled(&sysrst_ctrl, kDifToggleEnabled));
+}
+
+static void go_to_sleep(void) {
+  // Wakeup source is from sysrst_ctrl (source one).
+  LOG_INFO("Going to sleep.");
+  test_status_set(kTestStatusInWfi);
+  rstmgr_testutils_pre_reset(&rstmgr);
+  pwrmgr_testutils_enable_low_power(&pwrmgr, kDifPwrmgrWakeupRequestSourceOne,
+                                    /*pwrmgr_domain_config=*/0);
+  wait_for_interrupt();
+}
+
+static bool reset_is_low_power_exit(void) {
+  dif_rstmgr_reset_info_bitfield_t rst_info = rstmgr_testutils_reason_get();
+  rstmgr_testutils_reason_clear();
+  return rst_info == kDifRstmgrResetInfoLowPowerExit;
+}
+
+static bool has_wakeup_happened(void) {
+  bool wakeup_detected;
+  CHECK_DIF_OK(
+      dif_sysrst_ctrl_ulp_wakeup_get_status(&sysrst_ctrl, &wakeup_detected));
+  return wakeup_detected;
+}
+
+bool test_main(void) {
+  CHECK_DIF_OK(dif_sysrst_ctrl_init(
+      mmio_region_from_addr(TOP_MATCHA_SYSRST_CTRL_AON_BASE_ADDR),
+      &sysrst_ctrl));
+  CHECK_DIF_OK(dif_pinmux_init(
+      mmio_region_from_addr(TOP_MATCHA_PINMUX_AON_BASE_ADDR), &pinmux));
+  CHECK_DIF_OK(dif_pwrmgr_init(
+      mmio_region_from_addr(TOP_MATCHA_PWRMGR_AON_BASE_ADDR), &pwrmgr));
+  CHECK_DIF_OK(dif_rstmgr_init(
+      mmio_region_from_addr(TOP_MATCHA_RSTMGR_AON_BASE_ADDR), &rstmgr));
+
+  flash_ctrl_testutils_backdoor_init(&flash);
+
+  while (kTestPhase < kTestPhaseDone) {
+    switch (kTestPhase) {
+      case kTestPhaseInit:
+        pinmux_setup();
+        break;
+      case kTestPhaseDriveZero:
+        configure_wakeup();
+        LOG_INFO("kTestPhaseDriveZero");
+        break;
+      case kTestPhaseWaitNoWakeup:
+        CHECK(!reset_is_low_power_exit());
+        CHECK(!has_wakeup_happened());
+        LOG_INFO("kTestPhaseWaitNoWakeup");
+        go_to_sleep();
+        break;
+      case kTestPhaseGlitchLidOpen:
+        LOG_INFO("kTestPhaseGlitchLidOpen");
+        break;
+      case kTestPhaseWaitWakeup:
+        CHECK(reset_is_low_power_exit());
+        CHECK(has_wakeup_happened());
+        LOG_INFO("kTestPhaseWaitWakeup");
+        break;
+      default:
+        LOG_ERROR("Unexpected test phase : %d", kTestPhase);
+        LOG_INFO("END");
+        break;
+    }
+    wait_next_test_phase();
+  }
+  return true;
+}