[dif/gpio] added autogen'd GPIO IRQ DIFs

This partially addresses #8142.

Note, the GPIO IP can raise 32 different IRQs (one for each GPIO pin),
however, the HJSON lists this as a single interrupt with a width of 32.
As a result, the autogen DIF templates and script had to be updated  to
accomodate this subtle difference.

Additionally, in the process of accomplishing the above, a very minor
bug was found in the unit test template that was fixed, resulting in the
regeneration of the UART IRQ DIFs.

Signed-off-by: Timothy Trippel <ttrippel@google.com>
diff --git a/sw/device/lib/dif/autogen/dif_alert_handler_autogen_unittest.cc b/sw/device/lib/dif/autogen/dif_alert_handler_autogen_unittest.cc
index a2498c4..5652fb3 100644
--- a/sw/device/lib/dif/autogen/dif_alert_handler_autogen_unittest.cc
+++ b/sw/device/lib/dif/autogen/dif_alert_handler_autogen_unittest.cc
@@ -177,9 +177,9 @@
   // Last IRQ is disabled.
   irq_state = kDifToggleEnabled;
   EXPECT_READ32(ALERT_HANDLER_INTR_ENABLE_REG_OFFSET,
-                {{ALERT_HANDLER_INTR_ENABLE_CLASSD_BIT, true}});
+                {{ALERT_HANDLER_INTR_ENABLE_CLASSD_BIT, false}});
   EXPECT_EQ(dif_alert_handler_irq_get_enabled(
-                &alert_handler_, kDifAlertHandlerIrqClassa, &irq_state),
+                &alert_handler_, kDifAlertHandlerIrqClassd, &irq_state),
             kDifOk);
   EXPECT_EQ(irq_state, kDifToggleDisabled);
 }
diff --git a/sw/device/lib/dif/autogen/dif_gpio_autogen.c b/sw/device/lib/dif/autogen/dif_gpio_autogen.c
new file mode 100644
index 0000000..9ae3fcb
--- /dev/null
+++ b/sw/device/lib/dif/autogen/dif_gpio_autogen.c
@@ -0,0 +1,265 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This file is auto-generated.
+
+#include "sw/device/lib/dif/dif_gpio.h"
+
+#include "gpio_regs.h"  // Generated.
+
+/**
+ * Get the corresponding interrupt register bit offset. INTR_STATE,
+ * INTR_ENABLE and INTR_TEST registers have the same bit offsets, so this
+ * routine can be reused.
+ */
+static bool gpio_get_irq_bit_index(dif_gpio_irq_t irq,
+                                   bitfield_bit32_index_t *index_out) {
+  switch (irq) {
+    case kDifGpioIrqGpio0:
+      *index_out = 0;
+      break;
+    case kDifGpioIrqGpio1:
+      *index_out = 1;
+      break;
+    case kDifGpioIrqGpio2:
+      *index_out = 2;
+      break;
+    case kDifGpioIrqGpio3:
+      *index_out = 3;
+      break;
+    case kDifGpioIrqGpio4:
+      *index_out = 4;
+      break;
+    case kDifGpioIrqGpio5:
+      *index_out = 5;
+      break;
+    case kDifGpioIrqGpio6:
+      *index_out = 6;
+      break;
+    case kDifGpioIrqGpio7:
+      *index_out = 7;
+      break;
+    case kDifGpioIrqGpio8:
+      *index_out = 8;
+      break;
+    case kDifGpioIrqGpio9:
+      *index_out = 9;
+      break;
+    case kDifGpioIrqGpio10:
+      *index_out = 10;
+      break;
+    case kDifGpioIrqGpio11:
+      *index_out = 11;
+      break;
+    case kDifGpioIrqGpio12:
+      *index_out = 12;
+      break;
+    case kDifGpioIrqGpio13:
+      *index_out = 13;
+      break;
+    case kDifGpioIrqGpio14:
+      *index_out = 14;
+      break;
+    case kDifGpioIrqGpio15:
+      *index_out = 15;
+      break;
+    case kDifGpioIrqGpio16:
+      *index_out = 16;
+      break;
+    case kDifGpioIrqGpio17:
+      *index_out = 17;
+      break;
+    case kDifGpioIrqGpio18:
+      *index_out = 18;
+      break;
+    case kDifGpioIrqGpio19:
+      *index_out = 19;
+      break;
+    case kDifGpioIrqGpio20:
+      *index_out = 20;
+      break;
+    case kDifGpioIrqGpio21:
+      *index_out = 21;
+      break;
+    case kDifGpioIrqGpio22:
+      *index_out = 22;
+      break;
+    case kDifGpioIrqGpio23:
+      *index_out = 23;
+      break;
+    case kDifGpioIrqGpio24:
+      *index_out = 24;
+      break;
+    case kDifGpioIrqGpio25:
+      *index_out = 25;
+      break;
+    case kDifGpioIrqGpio26:
+      *index_out = 26;
+      break;
+    case kDifGpioIrqGpio27:
+      *index_out = 27;
+      break;
+    case kDifGpioIrqGpio28:
+      *index_out = 28;
+      break;
+    case kDifGpioIrqGpio29:
+      *index_out = 29;
+      break;
+    case kDifGpioIrqGpio30:
+      *index_out = 30;
+      break;
+    case kDifGpioIrqGpio31:
+      *index_out = 31;
+      break;
+    default:
+      return false;
+  }
+
+  return true;
+}
+
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_get_state(const dif_gpio_t *gpio,
+                                    dif_gpio_irq_state_snapshot_t *snapshot) {
+  if (gpio == NULL || snapshot == NULL) {
+    return kDifBadArg;
+  }
+
+  *snapshot = mmio_region_read32(gpio->base_addr, GPIO_INTR_STATE_REG_OFFSET);
+
+  return kDifOk;
+}
+
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_is_pending(const dif_gpio_t *gpio, dif_gpio_irq_t irq,
+                                     bool *is_pending) {
+  if (gpio == NULL || is_pending == NULL) {
+    return kDifBadArg;
+  }
+
+  bitfield_bit32_index_t index;
+  if (!gpio_get_irq_bit_index(irq, &index)) {
+    return kDifBadArg;
+  }
+
+  uint32_t intr_state_reg =
+      mmio_region_read32(gpio->base_addr, GPIO_INTR_STATE_REG_OFFSET);
+
+  *is_pending = bitfield_bit32_read(intr_state_reg, index);
+
+  return kDifOk;
+}
+
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_acknowledge(const dif_gpio_t *gpio,
+                                      dif_gpio_irq_t irq) {
+  if (gpio == NULL) {
+    return kDifBadArg;
+  }
+
+  bitfield_bit32_index_t index;
+  if (!gpio_get_irq_bit_index(irq, &index)) {
+    return kDifBadArg;
+  }
+
+  // Writing to the register clears the corresponding bits (Write-one clear).
+  uint32_t intr_state_reg = bitfield_bit32_write(0, index, true);
+  mmio_region_write32(gpio->base_addr, GPIO_INTR_STATE_REG_OFFSET,
+                      intr_state_reg);
+
+  return kDifOk;
+}
+
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_get_enabled(const dif_gpio_t *gpio,
+                                      dif_gpio_irq_t irq, dif_toggle_t *state) {
+  if (gpio == NULL || state == NULL) {
+    return kDifBadArg;
+  }
+
+  bitfield_bit32_index_t index;
+  if (!gpio_get_irq_bit_index(irq, &index)) {
+    return kDifBadArg;
+  }
+
+  uint32_t intr_enable_reg =
+      mmio_region_read32(gpio->base_addr, GPIO_INTR_ENABLE_REG_OFFSET);
+
+  bool is_enabled = bitfield_bit32_read(intr_enable_reg, index);
+  *state = is_enabled ? kDifToggleEnabled : kDifToggleDisabled;
+
+  return kDifOk;
+}
+
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_set_enabled(const dif_gpio_t *gpio,
+                                      dif_gpio_irq_t irq, dif_toggle_t state) {
+  if (gpio == NULL) {
+    return kDifBadArg;
+  }
+
+  bitfield_bit32_index_t index;
+  if (!gpio_get_irq_bit_index(irq, &index)) {
+    return kDifBadArg;
+  }
+
+  uint32_t intr_enable_reg =
+      mmio_region_read32(gpio->base_addr, GPIO_INTR_ENABLE_REG_OFFSET);
+
+  bool enable_bit = (state == kDifToggleEnabled) ? true : false;
+  intr_enable_reg = bitfield_bit32_write(intr_enable_reg, index, enable_bit);
+  mmio_region_write32(gpio->base_addr, GPIO_INTR_ENABLE_REG_OFFSET,
+                      intr_enable_reg);
+
+  return kDifOk;
+}
+
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_force(const dif_gpio_t *gpio, dif_gpio_irq_t irq) {
+  if (gpio == NULL) {
+    return kDifBadArg;
+  }
+
+  bitfield_bit32_index_t index;
+  if (!gpio_get_irq_bit_index(irq, &index)) {
+    return kDifBadArg;
+  }
+
+  uint32_t intr_test_reg = bitfield_bit32_write(0, index, true);
+  mmio_region_write32(gpio->base_addr, GPIO_INTR_TEST_REG_OFFSET,
+                      intr_test_reg);
+
+  return kDifOk;
+}
+
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_disable_all(
+    const dif_gpio_t *gpio, dif_gpio_irq_enable_snapshot_t *snapshot) {
+  if (gpio == NULL) {
+    return kDifBadArg;
+  }
+
+  // Pass the current interrupt state to the caller, if requested.
+  if (snapshot != NULL) {
+    *snapshot =
+        mmio_region_read32(gpio->base_addr, GPIO_INTR_ENABLE_REG_OFFSET);
+  }
+
+  // Disable all interrupts.
+  mmio_region_write32(gpio->base_addr, GPIO_INTR_ENABLE_REG_OFFSET, 0u);
+
+  return kDifOk;
+}
+
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_restore_all(
+    const dif_gpio_t *gpio, const dif_gpio_irq_enable_snapshot_t *snapshot) {
+  if (gpio == NULL || snapshot == NULL) {
+    return kDifBadArg;
+  }
+
+  mmio_region_write32(gpio->base_addr, GPIO_INTR_ENABLE_REG_OFFSET, *snapshot);
+
+  return kDifOk;
+}
diff --git a/sw/device/lib/dif/autogen/dif_gpio_autogen.h b/sw/device/lib/dif/autogen/dif_gpio_autogen.h
new file mode 100644
index 0000000..4229d45
--- /dev/null
+++ b/sw/device/lib/dif/autogen/dif_gpio_autogen.h
@@ -0,0 +1,194 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef OPENTITAN_SW_DEVICE_LIB_DIF_AUTOGEN_DIF_GPIO_AUTOGEN_H_
+#define OPENTITAN_SW_DEVICE_LIB_DIF_AUTOGEN_DIF_GPIO_AUTOGEN_H_
+
+// This file is auto-generated.
+
+/**
+ * @file
+ * @brief <a href="/hw/ip/gpio/doc/">GPIO</a> Device Interface Functions
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "sw/device/lib/base/macros.h"
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/dif/dif_base.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+
+/**
+ * A handle to gpio.
+ *
+ * This type should be treated as opaque by users.
+ */
+typedef struct dif_gpio {
+  /**
+   * The base address for the gpio hardware registers.
+   */
+  mmio_region_t base_addr;
+} dif_gpio_t;
+
+/**
+ * A gpio interrupt request type.
+ */
+typedef enum dif_gpio_irq {
+  /**
+   * Raised if any of GPIO pin detects configured interrupt mode
+   */
+  kDifGpioIrqGpio0 = 0,
+  kDifGpioIrqGpio1 = 1,
+  kDifGpioIrqGpio2 = 2,
+  kDifGpioIrqGpio3 = 3,
+  kDifGpioIrqGpio4 = 4,
+  kDifGpioIrqGpio5 = 5,
+  kDifGpioIrqGpio6 = 6,
+  kDifGpioIrqGpio7 = 7,
+  kDifGpioIrqGpio8 = 8,
+  kDifGpioIrqGpio9 = 9,
+  kDifGpioIrqGpio10 = 10,
+  kDifGpioIrqGpio11 = 11,
+  kDifGpioIrqGpio12 = 12,
+  kDifGpioIrqGpio13 = 13,
+  kDifGpioIrqGpio14 = 14,
+  kDifGpioIrqGpio15 = 15,
+  kDifGpioIrqGpio16 = 16,
+  kDifGpioIrqGpio17 = 17,
+  kDifGpioIrqGpio18 = 18,
+  kDifGpioIrqGpio19 = 19,
+  kDifGpioIrqGpio20 = 20,
+  kDifGpioIrqGpio21 = 21,
+  kDifGpioIrqGpio22 = 22,
+  kDifGpioIrqGpio23 = 23,
+  kDifGpioIrqGpio24 = 24,
+  kDifGpioIrqGpio25 = 25,
+  kDifGpioIrqGpio26 = 26,
+  kDifGpioIrqGpio27 = 27,
+  kDifGpioIrqGpio28 = 28,
+  kDifGpioIrqGpio29 = 29,
+  kDifGpioIrqGpio30 = 30,
+  kDifGpioIrqGpio31 = 31,
+} dif_gpio_irq_t;
+
+/**
+ * A snapshot of the state of the interrupts for this IP.
+ *
+ * This is an opaque type, to be used with the `dif_gpio_irq_get_state()`
+ * function.
+ */
+typedef uint32_t dif_gpio_irq_state_snapshot_t;
+
+/**
+ * A snapshot of the enablement state of the interrupts for this IP.
+ *
+ * This is an opaque type, to be used with the
+ * `dif_gpio_irq_disable_all()` and `dif_gpio_irq_restore_all()`
+ * functions.
+ */
+typedef uint32_t dif_gpio_irq_enable_snapshot_t;
+
+/**
+ * Returns whether a particular interrupt is currently pending.
+ *
+ * @param gpio A gpio handle.
+ * @param irq An interrupt request.
+ * @param[out] is_pending Out-param for whether the interrupt is pending.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_get_state(const dif_gpio_t *gpio,
+                                    dif_gpio_irq_state_snapshot_t *snapshot);
+
+/**
+ * Returns whether a particular interrupt is currently pending.
+ *
+ * @param gpio A gpio handle.
+ * @param irq An interrupt request.
+ * @param[out] is_pending Out-param for whether the interrupt is pending.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_is_pending(const dif_gpio_t *gpio, dif_gpio_irq_t irq,
+                                     bool *is_pending);
+
+/**
+ * Acknowledges a particular interrupt, indicating to the hardware that it has
+ * been successfully serviced.
+ *
+ * @param gpio A gpio handle.
+ * @param irq An interrupt request.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_acknowledge(const dif_gpio_t *gpio,
+                                      dif_gpio_irq_t irq);
+
+/**
+ * Checks whether a particular interrupt is currently enabled or disabled.
+ *
+ * @param gpio A gpio handle.
+ * @param irq An interrupt request.
+ * @param[out] state Out-param toggle state of the interrupt.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_get_enabled(const dif_gpio_t *gpio,
+                                      dif_gpio_irq_t irq, dif_toggle_t *state);
+
+/**
+ * Sets whether a particular interrupt is currently enabled or disabled.
+ *
+ * @param gpio A gpio handle.
+ * @param irq An interrupt request.
+ * @param state The new toggle state for the interrupt.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_set_enabled(const dif_gpio_t *gpio,
+                                      dif_gpio_irq_t irq, dif_toggle_t state);
+
+/**
+ * Forces a particular interrupt, causing it to be serviced as if hardware had
+ * asserted it.
+ *
+ * @param gpio A gpio handle.
+ * @param irq An interrupt request.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_force(const dif_gpio_t *gpio, dif_gpio_irq_t irq);
+
+/**
+ * Disables all interrupts, optionally snapshotting all enable states for later
+ * restoration.
+ *
+ * @param gpio A gpio handle.
+ * @param[out] snapshot Out-param for the snapshot; may be `NULL`.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_disable_all(const dif_gpio_t *gpio,
+                                      dif_gpio_irq_enable_snapshot_t *snapshot);
+
+/**
+ * Restores interrupts from the given (enable) snapshot.
+ *
+ * @param gpio A gpio handle.
+ * @param snapshot A snapshot to restore from.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_gpio_irq_restore_all(
+    const dif_gpio_t *gpio, const dif_gpio_irq_enable_snapshot_t *snapshot);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif  // __cplusplus
+
+#endif  // OPENTITAN_SW_DEVICE_LIB_DIF_AUTOGEN_DIF_GPIO_AUTOGEN_H_
diff --git a/sw/device/lib/dif/autogen/dif_gpio_autogen_unittest.cc b/sw/device/lib/dif/autogen/dif_gpio_autogen_unittest.cc
new file mode 100644
index 0000000..a5181d9
--- /dev/null
+++ b/sw/device/lib/dif/autogen/dif_gpio_autogen_unittest.cc
@@ -0,0 +1,272 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This file is auto-generated.
+
+#include "sw/device/lib/dif/dif_gpio.h"
+
+#include "gtest/gtest.h"
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/base/testing/mock_mmio.h"
+
+#include "gpio_regs.h"  // Generated.
+
+namespace dif_gpio_autogen_unittest {
+namespace {
+using ::mock_mmio::MmioTest;
+using ::mock_mmio::MockDevice;
+using ::testing::Test;
+
+class GpioTest : public Test, public MmioTest {
+ protected:
+  dif_gpio_t gpio_ = {.base_addr = dev().region()};
+};
+
+using ::testing::Eq;
+
+class IrqGetStateTest : public GpioTest {};
+
+TEST_F(IrqGetStateTest, NullArgs) {
+  dif_gpio_irq_state_snapshot_t irq_snapshot = 0;
+
+  EXPECT_EQ(dif_gpio_irq_get_state(nullptr, &irq_snapshot), kDifBadArg);
+
+  EXPECT_EQ(dif_gpio_irq_get_state(&gpio_, nullptr), kDifBadArg);
+
+  EXPECT_EQ(dif_gpio_irq_get_state(nullptr, nullptr), kDifBadArg);
+}
+
+TEST_F(IrqGetStateTest, SuccessAllRaised) {
+  dif_gpio_irq_state_snapshot_t irq_snapshot = 0;
+
+  EXPECT_READ32(GPIO_INTR_STATE_REG_OFFSET,
+                std::numeric_limits<uint32_t>::max());
+  EXPECT_EQ(dif_gpio_irq_get_state(&gpio_, &irq_snapshot), kDifOk);
+  EXPECT_EQ(irq_snapshot, std::numeric_limits<uint32_t>::max());
+}
+
+TEST_F(IrqGetStateTest, SuccessNoneRaised) {
+  dif_gpio_irq_state_snapshot_t irq_snapshot = 0;
+
+  EXPECT_READ32(GPIO_INTR_STATE_REG_OFFSET, 0);
+  EXPECT_EQ(dif_gpio_irq_get_state(&gpio_, &irq_snapshot), kDifOk);
+  EXPECT_EQ(irq_snapshot, 0);
+}
+
+class IrqIsPendingTest : public GpioTest {};
+
+TEST_F(IrqIsPendingTest, NullArgs) {
+  bool is_pending;
+
+  EXPECT_EQ(dif_gpio_irq_is_pending(nullptr, kDifGpioIrqGpio0, &is_pending),
+            kDifBadArg);
+
+  EXPECT_EQ(dif_gpio_irq_is_pending(&gpio_, kDifGpioIrqGpio0, nullptr),
+            kDifBadArg);
+
+  EXPECT_EQ(dif_gpio_irq_is_pending(nullptr, kDifGpioIrqGpio0, nullptr),
+            kDifBadArg);
+}
+
+TEST_F(IrqIsPendingTest, BadIrq) {
+  bool is_pending;
+  // All interrupt CSRs are 32 bit so interrupt 32 will be invalid.
+  EXPECT_EQ(dif_gpio_irq_is_pending(&gpio_, (dif_gpio_irq_t)32, &is_pending),
+            kDifBadArg);
+}
+
+TEST_F(IrqIsPendingTest, Success) {
+  bool irq_state;
+
+  // Get the first IRQ state.
+  irq_state = false;
+  EXPECT_READ32(GPIO_INTR_STATE_REG_OFFSET, {{0, true}});
+  EXPECT_EQ(dif_gpio_irq_is_pending(&gpio_, kDifGpioIrqGpio0, &irq_state),
+            kDifOk);
+  EXPECT_TRUE(irq_state);
+
+  // Get the last IRQ state.
+  irq_state = true;
+  EXPECT_READ32(GPIO_INTR_STATE_REG_OFFSET, {{31, false}});
+  EXPECT_EQ(dif_gpio_irq_is_pending(&gpio_, kDifGpioIrqGpio31, &irq_state),
+            kDifOk);
+  EXPECT_FALSE(irq_state);
+}
+
+class IrqAcknowledgeTest : public GpioTest {};
+
+TEST_F(IrqAcknowledgeTest, NullArgs) {
+  EXPECT_EQ(dif_gpio_irq_acknowledge(nullptr, kDifGpioIrqGpio0), kDifBadArg);
+}
+
+TEST_F(IrqAcknowledgeTest, BadIrq) {
+  EXPECT_EQ(dif_gpio_irq_acknowledge(nullptr, (dif_gpio_irq_t)32), kDifBadArg);
+}
+
+TEST_F(IrqAcknowledgeTest, Success) {
+  // Clear the first IRQ state.
+  EXPECT_WRITE32(GPIO_INTR_STATE_REG_OFFSET, {{0, true}});
+  EXPECT_EQ(dif_gpio_irq_acknowledge(&gpio_, kDifGpioIrqGpio0), kDifOk);
+
+  // Clear the last IRQ state.
+  EXPECT_WRITE32(GPIO_INTR_STATE_REG_OFFSET, {{31, true}});
+  EXPECT_EQ(dif_gpio_irq_acknowledge(&gpio_, kDifGpioIrqGpio31), kDifOk);
+}
+
+class IrqGetEnabledTest : public GpioTest {};
+
+TEST_F(IrqGetEnabledTest, NullArgs) {
+  dif_toggle_t irq_state;
+
+  EXPECT_EQ(dif_gpio_irq_get_enabled(nullptr, kDifGpioIrqGpio0, &irq_state),
+            kDifBadArg);
+
+  EXPECT_EQ(dif_gpio_irq_get_enabled(&gpio_, kDifGpioIrqGpio0, nullptr),
+            kDifBadArg);
+
+  EXPECT_EQ(dif_gpio_irq_get_enabled(nullptr, kDifGpioIrqGpio0, nullptr),
+            kDifBadArg);
+}
+
+TEST_F(IrqGetEnabledTest, BadIrq) {
+  dif_toggle_t irq_state;
+
+  EXPECT_EQ(dif_gpio_irq_get_enabled(&gpio_, (dif_gpio_irq_t)32, &irq_state),
+            kDifBadArg);
+}
+
+TEST_F(IrqGetEnabledTest, Success) {
+  dif_toggle_t irq_state;
+
+  // First IRQ is enabled.
+  irq_state = kDifToggleDisabled;
+  EXPECT_READ32(GPIO_INTR_ENABLE_REG_OFFSET, {{0, true}});
+  EXPECT_EQ(dif_gpio_irq_get_enabled(&gpio_, kDifGpioIrqGpio0, &irq_state),
+            kDifOk);
+  EXPECT_EQ(irq_state, kDifToggleEnabled);
+
+  // Last IRQ is disabled.
+  irq_state = kDifToggleEnabled;
+  EXPECT_READ32(GPIO_INTR_ENABLE_REG_OFFSET, {{31, false}});
+  EXPECT_EQ(dif_gpio_irq_get_enabled(&gpio_, kDifGpioIrqGpio31, &irq_state),
+            kDifOk);
+  EXPECT_EQ(irq_state, kDifToggleDisabled);
+}
+
+class IrqSetEnabledTest : public GpioTest {};
+
+TEST_F(IrqSetEnabledTest, NullArgs) {
+  dif_toggle_t irq_state = kDifToggleEnabled;
+
+  EXPECT_EQ(dif_gpio_irq_set_enabled(nullptr, kDifGpioIrqGpio0, irq_state),
+            kDifBadArg);
+}
+
+TEST_F(IrqSetEnabledTest, BadIrq) {
+  dif_toggle_t irq_state = kDifToggleEnabled;
+
+  EXPECT_EQ(dif_gpio_irq_set_enabled(&gpio_, (dif_gpio_irq_t)32, irq_state),
+            kDifBadArg);
+}
+
+TEST_F(IrqSetEnabledTest, Success) {
+  dif_toggle_t irq_state;
+
+  // Enable first IRQ.
+  irq_state = kDifToggleEnabled;
+  EXPECT_MASK32(GPIO_INTR_ENABLE_REG_OFFSET, {{0, 0x1, true}});
+  EXPECT_EQ(dif_gpio_irq_set_enabled(&gpio_, kDifGpioIrqGpio0, irq_state),
+            kDifOk);
+
+  // Disable last IRQ.
+  irq_state = kDifToggleDisabled;
+  EXPECT_MASK32(GPIO_INTR_ENABLE_REG_OFFSET, {{31, 0x1, false}});
+  EXPECT_EQ(dif_gpio_irq_set_enabled(&gpio_, kDifGpioIrqGpio31, irq_state),
+            kDifOk);
+}
+
+class IrqForceTest : public GpioTest {};
+
+TEST_F(IrqForceTest, NullArgs) {
+  EXPECT_EQ(dif_gpio_irq_force(nullptr, kDifGpioIrqGpio0), kDifBadArg);
+}
+
+TEST_F(IrqForceTest, BadIrq) {
+  EXPECT_EQ(dif_gpio_irq_force(nullptr, (dif_gpio_irq_t)32), kDifBadArg);
+}
+
+TEST_F(IrqForceTest, Success) {
+  // Force first IRQ.
+  EXPECT_WRITE32(GPIO_INTR_TEST_REG_OFFSET, {{0, true}});
+  EXPECT_EQ(dif_gpio_irq_force(&gpio_, kDifGpioIrqGpio0), kDifOk);
+
+  // Force last IRQ.
+  EXPECT_WRITE32(GPIO_INTR_TEST_REG_OFFSET, {{31, true}});
+  EXPECT_EQ(dif_gpio_irq_force(&gpio_, kDifGpioIrqGpio31), kDifOk);
+}
+
+class IrqDisableAllTest : public GpioTest {};
+
+TEST_F(IrqDisableAllTest, NullArgs) {
+  dif_gpio_irq_enable_snapshot_t irq_snapshot = 0;
+
+  EXPECT_EQ(dif_gpio_irq_disable_all(nullptr, &irq_snapshot), kDifBadArg);
+
+  EXPECT_EQ(dif_gpio_irq_disable_all(nullptr, nullptr), kDifBadArg);
+}
+
+TEST_F(IrqDisableAllTest, SuccessNoSnapshot) {
+  EXPECT_WRITE32(GPIO_INTR_ENABLE_REG_OFFSET, 0);
+  EXPECT_EQ(dif_gpio_irq_disable_all(&gpio_, nullptr), kDifOk);
+}
+
+TEST_F(IrqDisableAllTest, SuccessSnapshotAllDisabled) {
+  dif_gpio_irq_enable_snapshot_t irq_snapshot = 0;
+
+  EXPECT_READ32(GPIO_INTR_ENABLE_REG_OFFSET, 0);
+  EXPECT_WRITE32(GPIO_INTR_ENABLE_REG_OFFSET, 0);
+  EXPECT_EQ(dif_gpio_irq_disable_all(&gpio_, &irq_snapshot), kDifOk);
+  EXPECT_EQ(irq_snapshot, 0);
+}
+
+TEST_F(IrqDisableAllTest, SuccessSnapshotAllEnabled) {
+  dif_gpio_irq_enable_snapshot_t irq_snapshot = 0;
+
+  EXPECT_READ32(GPIO_INTR_ENABLE_REG_OFFSET,
+                std::numeric_limits<uint32_t>::max());
+  EXPECT_WRITE32(GPIO_INTR_ENABLE_REG_OFFSET, 0);
+  EXPECT_EQ(dif_gpio_irq_disable_all(&gpio_, &irq_snapshot), kDifOk);
+  EXPECT_EQ(irq_snapshot, std::numeric_limits<uint32_t>::max());
+}
+
+class IrqRestoreAllTest : public GpioTest {};
+
+TEST_F(IrqRestoreAllTest, NullArgs) {
+  dif_gpio_irq_enable_snapshot_t irq_snapshot = 0;
+
+  EXPECT_EQ(dif_gpio_irq_restore_all(nullptr, &irq_snapshot), kDifBadArg);
+
+  EXPECT_EQ(dif_gpio_irq_restore_all(&gpio_, nullptr), kDifBadArg);
+
+  EXPECT_EQ(dif_gpio_irq_restore_all(nullptr, nullptr), kDifBadArg);
+}
+
+TEST_F(IrqRestoreAllTest, SuccessAllEnabled) {
+  dif_gpio_irq_enable_snapshot_t irq_snapshot =
+      std::numeric_limits<uint32_t>::max();
+
+  EXPECT_WRITE32(GPIO_INTR_ENABLE_REG_OFFSET,
+                 std::numeric_limits<uint32_t>::max());
+  EXPECT_EQ(dif_gpio_irq_restore_all(&gpio_, &irq_snapshot), kDifOk);
+}
+
+TEST_F(IrqRestoreAllTest, SuccessAllDisabled) {
+  dif_gpio_irq_enable_snapshot_t irq_snapshot = 0;
+
+  EXPECT_WRITE32(GPIO_INTR_ENABLE_REG_OFFSET, 0);
+  EXPECT_EQ(dif_gpio_irq_restore_all(&gpio_, &irq_snapshot), kDifOk);
+}
+
+}  // namespace
+}  // namespace dif_gpio_autogen_unittest
diff --git a/sw/device/lib/dif/autogen/dif_hmac_autogen_unittest.cc b/sw/device/lib/dif/autogen/dif_hmac_autogen_unittest.cc
index dac87b5..f85bba2 100644
--- a/sw/device/lib/dif/autogen/dif_hmac_autogen_unittest.cc
+++ b/sw/device/lib/dif/autogen/dif_hmac_autogen_unittest.cc
@@ -154,8 +154,8 @@
   // Last IRQ is disabled.
   irq_state = kDifToggleEnabled;
   EXPECT_READ32(HMAC_INTR_ENABLE_REG_OFFSET,
-                {{HMAC_INTR_ENABLE_HMAC_ERR_BIT, true}});
-  EXPECT_EQ(dif_hmac_irq_get_enabled(&hmac_, kDifHmacIrqHmacDone, &irq_state),
+                {{HMAC_INTR_ENABLE_HMAC_ERR_BIT, false}});
+  EXPECT_EQ(dif_hmac_irq_get_enabled(&hmac_, kDifHmacIrqHmacErr, &irq_state),
             kDifOk);
   EXPECT_EQ(irq_state, kDifToggleDisabled);
 }
diff --git a/sw/device/lib/dif/autogen/dif_uart_autogen_unittest.cc b/sw/device/lib/dif/autogen/dif_uart_autogen_unittest.cc
index a0f5c10..0faea91 100644
--- a/sw/device/lib/dif/autogen/dif_uart_autogen_unittest.cc
+++ b/sw/device/lib/dif/autogen/dif_uart_autogen_unittest.cc
@@ -158,9 +158,9 @@
   // Last IRQ is disabled.
   irq_state = kDifToggleEnabled;
   EXPECT_READ32(UART_INTR_ENABLE_REG_OFFSET,
-                {{UART_INTR_ENABLE_RX_PARITY_ERR_BIT, true}});
+                {{UART_INTR_ENABLE_RX_PARITY_ERR_BIT, false}});
   EXPECT_EQ(
-      dif_uart_irq_get_enabled(&uart_, kDifUartIrqTxWatermark, &irq_state),
+      dif_uart_irq_get_enabled(&uart_, kDifUartIrqRxParityErr, &irq_state),
       kDifOk);
   EXPECT_EQ(irq_state, kDifToggleDisabled);
 }
diff --git a/util/make_new_dif.py b/util/make_new_dif.py
index c93c53a..2330b39 100755
--- a/util/make_new_dif.py
+++ b/util/make_new_dif.py
@@ -69,6 +69,7 @@
             [word.capitalize() for word in self.name_snake.split("_")])
         _multiline_description = irq["desc"][0].upper() + irq["desc"][1:]
         self.description = _multiline_description.replace("\n", " ")
+        self.width = irq["width"] if "width" in irq else 1
 
 
 class Ip:
@@ -200,7 +201,8 @@
                             f"dif_{ip.name_snake}_autogen{filetype}")
 
                 # Read in template.
-                template = Template(template_file.read_text())
+                template = Template(template_file.read_text(),
+                                    strict_undefined=True)
 
                 # Generate output file.
                 out_file.write_text(template.render(ip=ip, irqs=ip.irqs))
diff --git a/util/make_new_dif/dif_autogen.c.tpl b/util/make_new_dif/dif_autogen.c.tpl
index 9c6346f..ff30ffe 100644
--- a/util/make_new_dif/dif_autogen.c.tpl
+++ b/util/make_new_dif/dif_autogen.c.tpl
@@ -44,9 +44,19 @@
 
     switch (irq) {
   % for irq in irqs:
+    ## This handles the GPIO IP case where there is a multi-bit interrupt.
+    % if irq.width > 1:
+      % for irq_idx in range(irq.width):
+        case kDif${ip.name_camel}Irq${irq.name_camel}${irq_idx}:
+          *index_out = ${irq_idx};
+          break;
+      % endfor
+    ## This handles all other IPs.
+    % else:
       case kDif${ip.name_camel}Irq${irq.name_camel}:
         *index_out = ${ip.name_upper}_INTR_STATE_${irq.name_upper}_BIT;
         break;
+    % endif
   % endfor
       default:
         return false;
diff --git a/util/make_new_dif/dif_autogen.h.tpl b/util/make_new_dif/dif_autogen.h.tpl
index 8abe36d..224449e 100644
--- a/util/make_new_dif/dif_autogen.h.tpl
+++ b/util/make_new_dif/dif_autogen.h.tpl
@@ -61,7 +61,15 @@
     /**
      * ${irq.description}
      */
-    kDif${ip.name_camel}Irq${irq.name_camel} = ${loop.index},
+    ## This handles the GPIO IP case where there is a multi-bit interrupt.
+    % if irq.width > 1:
+      % for irq_idx in range(irq.width):
+        kDif${ip.name_camel}Irq${irq.name_camel}${irq_idx} = ${loop.index},
+      % endfor
+    ## This handles all other IPs.
+    % else:
+        kDif${ip.name_camel}Irq${irq.name_camel} = ${loop.index},
+    % endif
   % endfor
   } dif_${ip.name_snake}_irq_t;
 
diff --git a/util/make_new_dif/dif_autogen_unittest.cc.tpl b/util/make_new_dif/dif_autogen_unittest.cc.tpl
index 8c51674..1db3a1d 100644
--- a/util/make_new_dif/dif_autogen_unittest.cc.tpl
+++ b/util/make_new_dif/dif_autogen_unittest.cc.tpl
@@ -90,19 +90,31 @@
 
     EXPECT_EQ(dif_${ip.name_snake}_irq_is_pending(
         nullptr, 
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0,
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel},
+      % endif
         &is_pending),
       kDifBadArg);
 
     EXPECT_EQ(dif_${ip.name_snake}_irq_is_pending(
         &${ip.name_snake}_, 
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0,
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel},
+      % endif
         nullptr),
       kDifBadArg);
 
     EXPECT_EQ(dif_${ip.name_snake}_irq_is_pending(
         nullptr,
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0,
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel},
+      % endif
         nullptr),
       kDifBadArg);
   }
@@ -123,10 +135,18 @@
     // Get the first IRQ state.
     irq_state = false;
     EXPECT_READ32(${ip.name_upper}_INTR_STATE_REG_OFFSET,
-                  {{${ip.name_upper}_INTR_STATE_${irqs[0].name_upper}_BIT, true}});
+      % if irqs[0].width > 1:
+        {{0, true}});
+      % else:
+        {{${ip.name_upper}_INTR_STATE_${irqs[0].name_upper}_BIT, true}});
+      % endif
     EXPECT_EQ(dif_${ip.name_snake}_irq_is_pending(
         &${ip.name_snake}_,
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0,
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel},
+      % endif
         &irq_state),
       kDifOk);
     EXPECT_TRUE(irq_state);
@@ -134,10 +154,18 @@
     // Get the last IRQ state.
     irq_state = true;
     EXPECT_READ32(${ip.name_upper}_INTR_STATE_REG_OFFSET,
-                  {{${ip.name_upper}_INTR_STATE_${irqs[-1].name_upper}_BIT, false}});
+      % if irqs[0].width > 1:
+        {{${irqs[0].width - 1}, false}});
+      % else:
+        {{${ip.name_upper}_INTR_STATE_${irqs[-1].name_upper}_BIT, false}});
+      % endif
     EXPECT_EQ(dif_${ip.name_snake}_irq_is_pending(
         &${ip.name_snake}_,
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}${irqs[0].width - 1},
+      % else:
         kDif${ip.name_camel}Irq${irqs[-1].name_camel},
+      % endif
         &irq_state),
       kDifOk);
     EXPECT_FALSE(irq_state);
@@ -148,7 +176,11 @@
   TEST_F(IrqAcknowledgeTest, NullArgs) {
     EXPECT_EQ(dif_${ip.name_snake}_irq_acknowledge(
         nullptr, 
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0),
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel}),
+      % endif
       kDifBadArg);
   }
 
@@ -162,18 +194,34 @@
   TEST_F(IrqAcknowledgeTest, Success) {
     // Clear the first IRQ state.
     EXPECT_WRITE32(${ip.name_upper}_INTR_STATE_REG_OFFSET,
-                   {{${ip.name_upper}_INTR_STATE_${irqs[0].name_upper}_BIT, true}});
+      % if irqs[0].width > 1:
+         {{0, true}});
+      % else:
+        {{${ip.name_upper}_INTR_STATE_${irqs[0].name_upper}_BIT, true}});
+      % endif
     EXPECT_EQ(dif_${ip.name_snake}_irq_acknowledge(
         &${ip.name_snake}_,
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0),
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel}),
+      % endif
       kDifOk);
 
     // Clear the last IRQ state.
     EXPECT_WRITE32(${ip.name_upper}_INTR_STATE_REG_OFFSET,
-                   {{${ip.name_upper}_INTR_STATE_${irqs[-1].name_upper}_BIT, true}});
+      % if irqs[0].width > 1:
+        {{${irqs[0].width - 1}, true}});
+      % else:
+        {{${ip.name_upper}_INTR_STATE_${irqs[-1].name_upper}_BIT, true}});
+      % endif
     EXPECT_EQ(dif_${ip.name_snake}_irq_acknowledge(
         &${ip.name_snake}_,
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}${irqs[0].width - 1}),
+      % else:
         kDif${ip.name_camel}Irq${irqs[-1].name_camel}),
+      % endif
       kDifOk);
   }
 
@@ -184,19 +232,31 @@
 
     EXPECT_EQ(dif_${ip.name_snake}_irq_get_enabled(
         nullptr, 
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0,
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel},
+      % endif
         &irq_state),
       kDifBadArg);
 
     EXPECT_EQ(dif_${ip.name_snake}_irq_get_enabled(
         &${ip.name_snake}_, 
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0,
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel},
+      % endif
         nullptr),
       kDifBadArg);
 
     EXPECT_EQ(dif_${ip.name_snake}_irq_get_enabled(
         nullptr, 
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0,
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel},
+      % endif
         nullptr),
       kDifBadArg);
   }
@@ -217,10 +277,18 @@
     // First IRQ is enabled.
     irq_state = kDifToggleDisabled;
     EXPECT_READ32(${ip.name_upper}_INTR_ENABLE_REG_OFFSET,
-                  {{${ip.name_upper}_INTR_ENABLE_${irqs[0].name_upper}_BIT, true}});
+      % if irqs[0].width > 1:
+        {{0, true}});
+      % else:
+        {{${ip.name_upper}_INTR_ENABLE_${irqs[0].name_upper}_BIT, true}});
+      % endif
     EXPECT_EQ(dif_${ip.name_snake}_irq_get_enabled(
         &${ip.name_snake}_,
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0,
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel},
+      % endif
         &irq_state),
       kDifOk);
     EXPECT_EQ(irq_state, kDifToggleEnabled);
@@ -228,10 +296,18 @@
     // Last IRQ is disabled.
     irq_state = kDifToggleEnabled;
     EXPECT_READ32(${ip.name_upper}_INTR_ENABLE_REG_OFFSET,
-                  {{${ip.name_upper}_INTR_ENABLE_${irqs[-1].name_upper}_BIT, true}});
+      % if irqs[0].width > 1:
+        {{${irqs[0].width - 1}, false}});
+      % else:
+        {{${ip.name_upper}_INTR_ENABLE_${irqs[-1].name_upper}_BIT, false}});
+      % endif
     EXPECT_EQ(dif_${ip.name_snake}_irq_get_enabled(
         &${ip.name_snake}_,
-        kDif${ip.name_camel}Irq${irqs[0].name_camel},
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}${irqs[0].width - 1},
+      % else:
+        kDif${ip.name_camel}Irq${irqs[-1].name_camel},
+      % endif
         &irq_state),
       kDifOk);
     EXPECT_EQ(irq_state, kDifToggleDisabled);
@@ -244,7 +320,11 @@
 
     EXPECT_EQ(dif_${ip.name_snake}_irq_set_enabled(
         nullptr, 
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0,
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel},
+      % endif
         irq_state),
       kDifBadArg);
   }
@@ -265,24 +345,36 @@
     // Enable first IRQ.
     irq_state = kDifToggleEnabled;
     EXPECT_MASK32(${ip.name_upper}_INTR_ENABLE_REG_OFFSET,
-                  {{${ip.name_upper}_INTR_ENABLE_${irqs[0].name_upper}_BIT,
-                    0x1,
-                    true}});
+      % if irqs[0].width > 1:
+        {{0, 0x1, true}});
+      % else:
+        {{${ip.name_upper}_INTR_ENABLE_${irqs[0].name_upper}_BIT, 0x1, true}});
+      % endif
     EXPECT_EQ(dif_${ip.name_snake}_irq_set_enabled(
         &${ip.name_snake}_,
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0,
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel},
+      % endif
         irq_state),
       kDifOk);
 
     // Disable last IRQ.
     irq_state = kDifToggleDisabled;
     EXPECT_MASK32(${ip.name_upper}_INTR_ENABLE_REG_OFFSET,
-                  {{${ip.name_upper}_INTR_ENABLE_${irqs[-1].name_upper}_BIT, 
-                    0x1, 
-                    false}});
+      % if irqs[0].width > 1:
+        {{${irqs[0].width - 1}, 0x1, false}});
+      % else:
+        {{${ip.name_upper}_INTR_ENABLE_${irqs[-1].name_upper}_BIT, 0x1, false}});
+      % endif
     EXPECT_EQ(dif_${ip.name_snake}_irq_set_enabled(
         &${ip.name_snake}_,
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}${irqs[0].width - 1},
+      % else:
         kDif${ip.name_camel}Irq${irqs[-1].name_camel},
+      % endif
         irq_state),
       kDifOk);
   }
@@ -292,7 +384,11 @@
   TEST_F(IrqForceTest, NullArgs) {
     EXPECT_EQ(dif_${ip.name_snake}_irq_force(
         nullptr, 
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0),
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel}),
+      % endif
       kDifBadArg);
   }
 
@@ -306,18 +402,34 @@
   TEST_F(IrqForceTest, Success) {
     // Force first IRQ.
     EXPECT_WRITE32(${ip.name_upper}_INTR_TEST_REG_OFFSET,
-                   {{${ip.name_upper}_INTR_TEST_${irqs[0].name_upper}_BIT, true}});
+      % if irqs[0].width > 1:
+         {{0, true}});
+      % else:
+         {{${ip.name_upper}_INTR_TEST_${irqs[0].name_upper}_BIT, true}});
+      % endif
     EXPECT_EQ(dif_${ip.name_snake}_irq_force(
         &${ip.name_snake}_,
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[0].name_camel}0),
+      % else:
         kDif${ip.name_camel}Irq${irqs[0].name_camel}),
+      % endif
       kDifOk);
 
     // Force last IRQ.
     EXPECT_WRITE32(${ip.name_upper}_INTR_TEST_REG_OFFSET,
-                   {{${ip.name_upper}_INTR_TEST_${irqs[-1].name_upper}_BIT, true}});
+      % if irqs[0].width > 1:
+        {{${irqs[0].width - 1}, true}});
+      % else:
+        {{${ip.name_upper}_INTR_TEST_${irqs[-1].name_upper}_BIT, true}});
+      % endif
     EXPECT_EQ(dif_${ip.name_snake}_irq_force(
         &${ip.name_snake}_,
+      % if irqs[0].width > 1:
+        kDif${ip.name_camel}Irq${irqs[-1].name_camel}${irqs[0].width - 1}),
+      % else:
         kDif${ip.name_camel}Irq${irqs[-1].name_camel}),
+      % endif
       kDifOk);
   }