[dif, rv_core_ibex] Add address translation and unittest
Signed-off-by: Douglas Reis <doreis@lowrisc.org>
diff --git a/sw/device/lib/base/bitfield.c b/sw/device/lib/base/bitfield.c
index 2cf1204..66c65bd 100644
--- a/sw/device/lib/base/bitfield.c
+++ b/sw/device/lib/base/bitfield.c
@@ -32,3 +32,4 @@
extern int32_t bitfield_popcount32(uint32_t bitfield);
extern int32_t bitfield_parity32(uint32_t bitfield);
extern uint32_t bitfield_byteswap32(uint32_t bitfield);
+extern bool bitfield_is_power_of_two32(uint32_t bitfield);
diff --git a/sw/device/lib/base/bitfield.h b/sw/device/lib/base/bitfield.h
index cab6086..a105f59 100644
--- a/sw/device/lib/base/bitfield.h
+++ b/sw/device/lib/base/bitfield.h
@@ -293,6 +293,18 @@
return __builtin_bswap32(bitfield);
}
+/**
+ * Check whether the bitfield value is power of two aligned.
+ *
+ * Zero will also return false.
+ *
+ * @param bitfield Value to be verified.
+ * @return True if bitfield is power of two, otherwise false.
+ */
+inline bool bitfield_is_power_of_two32(uint32_t bitfield) {
+ return bitfield != 0 && (bitfield & (bitfield - 1)) == 0;
+}
+
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
diff --git a/sw/device/lib/dif/BUILD b/sw/device/lib/dif/BUILD
index 3e5ee1e..218033a 100644
--- a/sw/device/lib/dif/BUILD
+++ b/sw/device/lib/dif/BUILD
@@ -826,8 +826,10 @@
srcs = [
"autogen/dif_rv_core_ibex_autogen.c",
"autogen/dif_rv_core_ibex_autogen.h",
+ "dif_rv_core_ibex.c",
],
hdrs = [
+ "dif_rv_core_ibex.h",
],
deps = [
":base",
@@ -841,6 +843,7 @@
name = "rv_core_ibex_unittest",
srcs = [
"autogen/dif_rv_core_ibex_autogen_unittest.cc",
+ "dif_rv_core_ibex_unittest.cc",
],
deps = [
":rv_core_ibex",
diff --git a/sw/device/lib/dif/dif_rv_core_ibex.c b/sw/device/lib/dif/dif_rv_core_ibex.c
new file mode 100644
index 0000000..5ff1b7e
--- /dev/null
+++ b/sw/device/lib/dif/dif_rv_core_ibex.c
@@ -0,0 +1,163 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "sw/device/lib/dif/dif_rv_core_ibex.h"
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sw/device/lib/base/memory.h"
+#include "sw/device/lib/base/mmio.h"
+
+// #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+#include "rv_core_ibex_regs.h"
+
+typedef struct ibex_addr_translation_regs {
+ uint32_t ibus_maching;
+ uint32_t ibus_remap;
+ uint32_t ibus_en;
+ uint32_t ibus_lock;
+ uint32_t dbus_maching;
+ uint32_t dbus_remap;
+ uint32_t dbus_en;
+ uint32_t dbus_lock;
+} ibex_addr_translation_regs_t;
+
+static const ibex_addr_translation_regs_t
+ kRegsMap[kDifRvCoreIbexAddrTranslationSlotCount] = {
+ [kDifRvCoreIbexAddrTranslationSlot_0] =
+ {
+ .ibus_maching = RV_CORE_IBEX_IBUS_ADDR_MATCHING_0_REG_OFFSET,
+ .ibus_remap = RV_CORE_IBEX_IBUS_REMAP_ADDR_0_REG_OFFSET,
+ .ibus_en = RV_CORE_IBEX_IBUS_ADDR_EN_0_REG_OFFSET,
+ .ibus_lock = RV_CORE_IBEX_IBUS_REGWEN_0_REG_OFFSET,
+ .dbus_maching = RV_CORE_IBEX_DBUS_ADDR_MATCHING_0_REG_OFFSET,
+ .dbus_remap = RV_CORE_IBEX_DBUS_REMAP_ADDR_0_REG_OFFSET,
+ .dbus_en = RV_CORE_IBEX_DBUS_ADDR_EN_0_REG_OFFSET,
+ .dbus_lock = RV_CORE_IBEX_DBUS_REGWEN_0_REG_OFFSET,
+ },
+ [kDifRvCoreIbexAddrTranslationSlot_1] =
+ {
+ .ibus_maching = RV_CORE_IBEX_IBUS_ADDR_MATCHING_1_REG_OFFSET,
+ .ibus_remap = RV_CORE_IBEX_IBUS_REMAP_ADDR_1_REG_OFFSET,
+ .ibus_en = RV_CORE_IBEX_IBUS_ADDR_EN_1_REG_OFFSET,
+ .ibus_lock = RV_CORE_IBEX_IBUS_REGWEN_1_REG_OFFSET,
+ .dbus_maching = RV_CORE_IBEX_DBUS_ADDR_MATCHING_1_REG_OFFSET,
+ .dbus_remap = RV_CORE_IBEX_DBUS_REMAP_ADDR_1_REG_OFFSET,
+ .dbus_en = RV_CORE_IBEX_DBUS_ADDR_EN_1_REG_OFFSET,
+ .dbus_lock = RV_CORE_IBEX_DBUS_REGWEN_1_REG_OFFSET,
+ },
+};
+
+/**
+ * Convert the region address and size into a natural power of two address.
+ *
+ * @param addr Region start address.
+ * @param size region size.
+ * @return Napot address
+ */
+static uint32_t to_napot(uint32_t addr, size_t size) {
+ return addr | (size - 1) >> 1;
+}
+
+/**
+ * Split a natural power of two address into a start address and size.
+ *
+ * @param napot Address formated in NAPOT.
+ * @param size Pointer to receive the region size.
+ * @return The region start address.
+ */
+static uint32_t from_napot(uint32_t napot, size_t *size) {
+ for (size_t i = 1; i < sizeof(uint32_t) * 8; ++i) {
+ uint32_t ref = (1u << i) - 1;
+ if ((napot & ref) == ref >> 1) {
+ *size = 1u << i;
+ break;
+ }
+ }
+ return napot & ~((*size - 1) >> 1);
+}
+
+dif_result_t dif_rv_core_ibex_configure_addr_translation(
+ const dif_rv_core_ibex_t *rv_core_ibex,
+ dif_rv_core_ibex_addr_translation_slot_t slot,
+ dif_rv_core_ibex_addr_translation_region_t region) {
+ if (rv_core_ibex == NULL || slot >= kDifRvCoreIbexAddrTranslationSlotCount) {
+ return kDifBadArg;
+ }
+
+ if (!bitfield_is_power_of_two32(region.dbus.size) ||
+ !bitfield_is_power_of_two32(region.ibus.size)) {
+ return kDifBadArg;
+ }
+
+ const ibex_addr_translation_regs_t regs = kRegsMap[slot];
+
+ if (mmio_region_read32(rv_core_ibex->base_addr, regs.dbus_lock) == 0 ||
+ mmio_region_read32(rv_core_ibex->base_addr, regs.ibus_lock) == 0) {
+ return kDifLocked;
+ }
+
+ uint32_t mask = to_napot(region.ibus.matching_addr, region.ibus.size);
+ mmio_region_write32(rv_core_ibex->base_addr, regs.ibus_maching, mask);
+ mmio_region_write32(rv_core_ibex->base_addr, regs.ibus_remap,
+ region.ibus.remap_addr);
+ mmio_region_write32(rv_core_ibex->base_addr, regs.ibus_en, 1);
+
+ mask = to_napot(region.dbus.matching_addr, region.dbus.size);
+ mmio_region_write32(rv_core_ibex->base_addr, regs.dbus_maching, mask);
+ mmio_region_write32(rv_core_ibex->base_addr, regs.dbus_remap,
+ region.dbus.remap_addr);
+ mmio_region_write32(rv_core_ibex->base_addr, regs.dbus_en, 1);
+
+ return kDifOk;
+}
+
+dif_result_t dif_rv_core_ibex_read_addr_translation(
+ const dif_rv_core_ibex_t *rv_core_ibex,
+ dif_rv_core_ibex_addr_translation_slot_t slot,
+ dif_rv_core_ibex_addr_translation_region_t *region) {
+ if (rv_core_ibex == NULL || region == NULL ||
+ slot >= kDifRvCoreIbexAddrTranslationSlotCount) {
+ return kDifBadArg;
+ }
+
+ const ibex_addr_translation_regs_t regs = kRegsMap[slot];
+
+ uint32_t reg = mmio_region_read32(rv_core_ibex->base_addr, regs.ibus_maching);
+ region->ibus.matching_addr = from_napot(reg, ®ion->ibus.size);
+
+ region->ibus.remap_addr =
+ mmio_region_read32(rv_core_ibex->base_addr, regs.ibus_remap);
+
+ reg = mmio_region_read32(rv_core_ibex->base_addr, regs.dbus_maching);
+ region->dbus.matching_addr = from_napot(reg, ®ion->dbus.size);
+
+ region->dbus.remap_addr =
+ mmio_region_read32(rv_core_ibex->base_addr, regs.dbus_remap);
+
+ return kDifOk;
+}
+
+dif_result_t dif_rv_core_ibex_lock_addr_translation(
+ const dif_rv_core_ibex_t *rv_core_ibex,
+ dif_rv_core_ibex_addr_translation_slot_t slot) {
+ if (rv_core_ibex == NULL || slot >= kDifRvCoreIbexAddrTranslationSlotCount) {
+ return kDifBadArg;
+ }
+
+ const ibex_addr_translation_regs_t regs = kRegsMap[slot];
+
+ // Only locks in case it is not locked already.
+ if (mmio_region_read32(rv_core_ibex->base_addr, regs.dbus_lock) == 1) {
+ mmio_region_write32(rv_core_ibex->base_addr, regs.dbus_lock, 0);
+ }
+
+ if (mmio_region_read32(rv_core_ibex->base_addr, regs.ibus_lock) == 1) {
+ mmio_region_write32(rv_core_ibex->base_addr, regs.ibus_lock, 0);
+ }
+
+ return kDifOk;
+}
diff --git a/sw/device/lib/dif/dif_rv_core_ibex.h b/sw/device/lib/dif/dif_rv_core_ibex.h
new file mode 100644
index 0000000..9753cd6
--- /dev/null
+++ b/sw/device/lib/dif/dif_rv_core_ibex.h
@@ -0,0 +1,122 @@
+// 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_DIF_RV_CORE_IBEX_H_
+#define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_RV_CORE_IBEX_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"
+
+#include "sw/device/lib/dif/autogen/dif_rv_core_ibex_autogen.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * Address translation slot.
+ */
+typedef enum dif_rv_core_ibex_addr_translation_slot {
+ kDifRvCoreIbexAddrTranslationSlot_0,
+ kDifRvCoreIbexAddrTranslationSlot_1,
+ kDifRvCoreIbexAddrTranslationSlotCount,
+} dif_rv_core_ibex_addr_translation_slot_t;
+
+/**
+ * Address tranlation matching region.
+ *
+ * The value programmed is done at power-of-2 alignment. For example, if the
+ * intended matching region is 0x8000_0000 to 0x8000_FFFF, the value
+ * programmed is 0x8000_7FFF.
+ *
+ * The value programmed can be determined from the translation granule. Assume
+ * the user wishes to translate a specific 64KB block to a different address:
+ * 64KB has a hex value of 0x10000. Subtract 1 from this value and then right
+ * shift by one to obtain 0x7FFF. This value is then logically OR'd with the
+ * upper address bits that would select which 64KB to translate.
+ */
+typedef struct dif_rv_core_ibex_addr_translation_pair {
+ /**
+ * Matching address (Virtual address).
+ * When an incoming transaction matches the matching
+ * region, it is redirected to the new address. If a transaction does not
+ * match, then it is directly passed through.
+ */
+ uintptr_t matching_addr;
+
+ /**
+ * Remap address (Physical address).
+ * The region where the matched transtaction will be
+ * redirected to.
+ */
+ uintptr_t remap_addr;
+
+ /**
+ * Address region size.
+ */
+ size_t size;
+} dif_rv_core_ibex_addr_translation_pair_t;
+
+/**
+ * Addresses translation region.
+ */
+typedef struct dif_rv_core_ibex_addr_translation_region {
+ /**
+ * Region representing the instruction bus.
+ */
+ dif_rv_core_ibex_addr_translation_pair_t ibus;
+
+ /**
+ * Region representing the data bus.
+ */
+ dif_rv_core_ibex_addr_translation_pair_t dbus;
+} dif_rv_core_ibex_addr_translation_region_t;
+
+/**
+ * Configure the instruction and data bus in the address translation `slot`.
+ *
+ * @param rv_core_ibex Handle.
+ * @param slot Slot to be used.
+ * @param region Dbus and Ibus addresses.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_rv_core_ibex_configure_addr_translation(
+ const dif_rv_core_ibex_t *rv_core_ibex,
+ dif_rv_core_ibex_addr_translation_slot_t slot,
+ dif_rv_core_ibex_addr_translation_region_t region);
+
+/**
+ *
+ * @param rv_core_ibex Handle.
+ * @param slot Slot to be read.
+ * @param[out] region Pointer to receive the Dbus and Ibus addresses.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_rv_core_ibex_read_addr_translation(
+ const dif_rv_core_ibex_t *rv_core_ibex,
+ dif_rv_core_ibex_addr_translation_slot_t slot,
+ dif_rv_core_ibex_addr_translation_region_t *region);
+
+/**
+ * Lock the `slot` registers. Once locked it can no longer be unlocked until the
+ * next system reset.
+ *
+ * @param rv_core_ibex Handle.
+ * @param slot Slot to be locked.
+ * @return The result of the operation.
+ */
+OT_WARN_UNUSED_RESULT
+dif_result_t dif_rv_core_ibex_lock_addr_translation(
+ const dif_rv_core_ibex_t *rv_core_ibex,
+ dif_rv_core_ibex_addr_translation_slot_t slot);
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
+
+#endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_RV_CORE_IBEX_H_
diff --git a/sw/device/lib/dif/dif_rv_core_ibex_unittest.cc b/sw/device/lib/dif/dif_rv_core_ibex_unittest.cc
new file mode 100644
index 0000000..6a8d6b1
--- /dev/null
+++ b/sw/device/lib/dif/dif_rv_core_ibex_unittest.cc
@@ -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
+
+#include "sw/device/lib/dif/dif_rv_core_ibex.h"
+
+#include "gtest/gtest.h"
+#include "sw/device/lib/base/mmio.h"
+#include "sw/device/lib/base/testing/mock_mmio.h"
+#include "sw/device/lib/dif/dif_test_base.h"
+
+extern "C" {
+#include "rv_core_ibex_regs.h" // Generated.
+} // extern "C"
+
+// We define global namespace == and << to make `dif_i2c_timing_params_t` work
+// nicely with EXPECT_EQ.
+bool operator==(const dif_rv_core_ibex_addr_translation_region_t a,
+ const dif_rv_core_ibex_addr_translation_region_t b) {
+ return memcmp(&a, &b, sizeof(dif_rv_core_ibex_addr_translation_region_t)) ==
+ 0;
+}
+
+std::ostream &operator<<(
+ std::ostream &os,
+ const dif_rv_core_ibex_addr_translation_region_t ®ion) {
+ return os << "{\n"
+ << "ibus = {\n"
+ << " .matching_addr = " << region.ibus.matching_addr << ",\n"
+ << " .remap_addr = " << region.ibus.remap_addr << ",\n"
+ << " .size = " << region.ibus.size << ",\n"
+ << "},\n"
+ << "dbus = {\n"
+ << " .matching_addr = " << region.dbus.matching_addr << ",\n"
+ << " .remap_addr = " << region.dbus.remap_addr << ",\n"
+ << " .size = " << region.dbus.size << ",\n"
+ << "},\n"
+ << "}";
+}
+
+namespace dif_rv_core_ibex_test {
+using mock_mmio::MmioTest;
+using mock_mmio::MockDevice;
+using testing::Test;
+
+// Base class for the rest fixtures in this file.
+class RvCoreIbexTest : public testing::Test, public mock_mmio::MmioTest {};
+
+// Base class for the rest of the tests in this file, provides a
+// `dif_aes_t` instance.
+class RvCoreIbexTestInitialized : public RvCoreIbexTest {
+ protected:
+ dif_rv_core_ibex_t ibex_;
+
+ RvCoreIbexTestInitialized() {
+ EXPECT_DIF_OK(dif_rv_core_ibex_init(dev().region(), &ibex_));
+ }
+};
+
+class AddressTranslationTest : public RvCoreIbexTestInitialized {
+ protected:
+ static constexpr dif_rv_core_ibex_addr_translation_region_t kRegion = {
+ .ibus =
+ {
+ .matching_addr = 0x9000000,
+ .remap_addr = 0x2000000,
+ .size = 0x8000,
+ },
+ .dbus =
+ {
+ .matching_addr = 0x9000000,
+ .remap_addr = 0x2000000,
+ .size = 0x8000,
+ },
+ };
+
+ uint32_t Napot(uint32_t addr, size_t size) { return addr | (size - 1) >> 1; }
+};
+constexpr dif_rv_core_ibex_addr_translation_region_t
+ AddressTranslationTest::kRegion;
+
+TEST_F(AddressTranslationTest, Slot0Success) {
+ EXPECT_READ32(RV_CORE_IBEX_DBUS_REGWEN_0_REG_OFFSET, 1);
+ EXPECT_READ32(RV_CORE_IBEX_IBUS_REGWEN_0_REG_OFFSET, 1);
+
+ EXPECT_WRITE32(RV_CORE_IBEX_IBUS_ADDR_MATCHING_0_REG_OFFSET, 0x9003fff);
+ EXPECT_WRITE32(RV_CORE_IBEX_IBUS_REMAP_ADDR_0_REG_OFFSET,
+ kRegion.ibus.remap_addr);
+ EXPECT_WRITE32(RV_CORE_IBEX_IBUS_ADDR_EN_0_REG_OFFSET, 1);
+
+ EXPECT_WRITE32(RV_CORE_IBEX_DBUS_ADDR_MATCHING_0_REG_OFFSET, 0x9003fff);
+ EXPECT_WRITE32(RV_CORE_IBEX_DBUS_REMAP_ADDR_0_REG_OFFSET,
+ kRegion.dbus.remap_addr);
+ EXPECT_WRITE32(RV_CORE_IBEX_DBUS_ADDR_EN_0_REG_OFFSET, 1);
+
+ EXPECT_DIF_OK(dif_rv_core_ibex_configure_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_0, kRegion));
+}
+
+TEST_F(AddressTranslationTest, Slot1Success) {
+ EXPECT_READ32(RV_CORE_IBEX_DBUS_REGWEN_1_REG_OFFSET, 1);
+ EXPECT_READ32(RV_CORE_IBEX_IBUS_REGWEN_1_REG_OFFSET, 1);
+ EXPECT_WRITE32(RV_CORE_IBEX_IBUS_ADDR_MATCHING_1_REG_OFFSET, 0x9003fff);
+ EXPECT_WRITE32(RV_CORE_IBEX_IBUS_REMAP_ADDR_1_REG_OFFSET,
+ kRegion.ibus.remap_addr);
+ EXPECT_WRITE32(RV_CORE_IBEX_IBUS_ADDR_EN_1_REG_OFFSET, 1);
+
+ EXPECT_WRITE32(RV_CORE_IBEX_DBUS_ADDR_MATCHING_1_REG_OFFSET, 0x9003fff);
+ EXPECT_WRITE32(RV_CORE_IBEX_DBUS_REMAP_ADDR_1_REG_OFFSET,
+ kRegion.dbus.remap_addr);
+ EXPECT_WRITE32(RV_CORE_IBEX_DBUS_ADDR_EN_1_REG_OFFSET, 1);
+
+ EXPECT_DIF_OK(dif_rv_core_ibex_configure_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_1, kRegion));
+}
+
+TEST_F(AddressTranslationTest, PowerOfTwoAlignmentSuccess) {
+ dif_rv_core_ibex_addr_translation_region_t region = kRegion;
+
+ region.ibus.matching_addr = 0x8000000;
+ region.dbus.matching_addr = 0x8000000;
+
+ for (size_t i = 0; i < (sizeof(uint32_t) * 8) - 1; ++i) {
+ region.ibus.size = 1u << i;
+ region.dbus.size = 1u << i;
+
+ EXPECT_READ32(RV_CORE_IBEX_DBUS_REGWEN_0_REG_OFFSET, 1);
+ EXPECT_READ32(RV_CORE_IBEX_IBUS_REGWEN_0_REG_OFFSET, 1);
+
+ EXPECT_WRITE32(RV_CORE_IBEX_IBUS_ADDR_MATCHING_0_REG_OFFSET,
+ Napot(region.ibus.matching_addr, region.ibus.size));
+ EXPECT_WRITE32(RV_CORE_IBEX_IBUS_REMAP_ADDR_0_REG_OFFSET,
+ region.ibus.remap_addr);
+ EXPECT_WRITE32(RV_CORE_IBEX_IBUS_ADDR_EN_0_REG_OFFSET, 1);
+
+ EXPECT_WRITE32(RV_CORE_IBEX_DBUS_ADDR_MATCHING_0_REG_OFFSET,
+ Napot(region.dbus.matching_addr, region.dbus.size));
+ EXPECT_WRITE32(RV_CORE_IBEX_DBUS_REMAP_ADDR_0_REG_OFFSET,
+ region.dbus.remap_addr);
+ EXPECT_WRITE32(RV_CORE_IBEX_DBUS_ADDR_EN_0_REG_OFFSET, 1);
+
+ EXPECT_DIF_OK(dif_rv_core_ibex_configure_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_0, region));
+ }
+}
+
+TEST_F(AddressTranslationTest, ReadSlot0Success) {
+ EXPECT_READ32(RV_CORE_IBEX_IBUS_ADDR_MATCHING_0_REG_OFFSET, 0x9003fff);
+ EXPECT_READ32(RV_CORE_IBEX_IBUS_REMAP_ADDR_0_REG_OFFSET,
+ kRegion.ibus.remap_addr);
+
+ EXPECT_READ32(RV_CORE_IBEX_DBUS_ADDR_MATCHING_0_REG_OFFSET, 0x9003fff);
+ EXPECT_READ32(RV_CORE_IBEX_DBUS_REMAP_ADDR_0_REG_OFFSET,
+ kRegion.dbus.remap_addr);
+
+ dif_rv_core_ibex_addr_translation_region_t region;
+ EXPECT_DIF_OK(dif_rv_core_ibex_read_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_0, ®ion));
+
+ EXPECT_EQ(region, kRegion);
+}
+
+TEST_F(AddressTranslationTest, LockSlot0Success) {
+ EXPECT_READ32(RV_CORE_IBEX_DBUS_REGWEN_0_REG_OFFSET, 1);
+ EXPECT_WRITE32(RV_CORE_IBEX_DBUS_REGWEN_0_REG_OFFSET, 0);
+ EXPECT_READ32(RV_CORE_IBEX_IBUS_REGWEN_0_REG_OFFSET, 1);
+ EXPECT_WRITE32(RV_CORE_IBEX_IBUS_REGWEN_0_REG_OFFSET, 0);
+
+ EXPECT_DIF_OK(dif_rv_core_ibex_lock_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_0));
+}
+
+TEST_F(AddressTranslationTest, LockSlot0LockedSuccess) {
+ EXPECT_READ32(RV_CORE_IBEX_DBUS_REGWEN_0_REG_OFFSET, 0);
+ EXPECT_READ32(RV_CORE_IBEX_IBUS_REGWEN_0_REG_OFFSET, 0);
+
+ EXPECT_DIF_OK(dif_rv_core_ibex_lock_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_0));
+}
+
+TEST_F(AddressTranslationTest, LockSlot1Success) {
+ EXPECT_READ32(RV_CORE_IBEX_DBUS_REGWEN_1_REG_OFFSET, 1);
+ EXPECT_WRITE32(RV_CORE_IBEX_DBUS_REGWEN_1_REG_OFFSET, 0);
+ EXPECT_READ32(RV_CORE_IBEX_IBUS_REGWEN_1_REG_OFFSET, 1);
+ EXPECT_WRITE32(RV_CORE_IBEX_IBUS_REGWEN_1_REG_OFFSET, 0);
+
+ EXPECT_DIF_OK(dif_rv_core_ibex_lock_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_1));
+}
+
+TEST_F(AddressTranslationTest, LockSlot1LockedSuccess) {
+ EXPECT_READ32(RV_CORE_IBEX_DBUS_REGWEN_1_REG_OFFSET, 0);
+ EXPECT_READ32(RV_CORE_IBEX_IBUS_REGWEN_1_REG_OFFSET, 0);
+
+ EXPECT_DIF_OK(dif_rv_core_ibex_lock_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_1));
+}
+
+TEST_F(AddressTranslationTest, BadArg) {
+ dif_rv_core_ibex_addr_translation_region_t region;
+ EXPECT_DIF_BADARG(dif_rv_core_ibex_configure_addr_translation(
+ nullptr, kDifRvCoreIbexAddrTranslationSlot_1, region));
+ EXPECT_DIF_BADARG(dif_rv_core_ibex_configure_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlotCount, region));
+
+ EXPECT_DIF_BADARG(dif_rv_core_ibex_read_addr_translation(
+ nullptr, kDifRvCoreIbexAddrTranslationSlot_1, ®ion));
+ EXPECT_DIF_BADARG(dif_rv_core_ibex_read_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlotCount, ®ion));
+ EXPECT_DIF_BADARG(dif_rv_core_ibex_read_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_1, nullptr));
+
+ EXPECT_DIF_BADARG(dif_rv_core_ibex_lock_addr_translation(
+ nullptr, kDifRvCoreIbexAddrTranslationSlot_1));
+ EXPECT_DIF_BADARG(dif_rv_core_ibex_lock_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlotCount));
+}
+
+TEST_F(AddressTranslationTest, Slot0DbusLocked) {
+ EXPECT_READ32(RV_CORE_IBEX_DBUS_REGWEN_0_REG_OFFSET, 0);
+
+ EXPECT_EQ(dif_rv_core_ibex_configure_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_0, kRegion),
+ kDifLocked);
+}
+
+TEST_F(AddressTranslationTest, Slot0IbusLocked) {
+ EXPECT_READ32(RV_CORE_IBEX_DBUS_REGWEN_0_REG_OFFSET, 1);
+ EXPECT_READ32(RV_CORE_IBEX_IBUS_REGWEN_0_REG_OFFSET, 0);
+
+ EXPECT_EQ(dif_rv_core_ibex_configure_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_0, kRegion),
+ kDifLocked);
+}
+
+TEST_F(AddressTranslationTest, Slot1DbusLocked) {
+ EXPECT_READ32(RV_CORE_IBEX_DBUS_REGWEN_1_REG_OFFSET, 0);
+
+ EXPECT_EQ(dif_rv_core_ibex_configure_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_1, kRegion),
+ kDifLocked);
+}
+
+TEST_F(AddressTranslationTest, Slot1IbusLocked) {
+ EXPECT_READ32(RV_CORE_IBEX_DBUS_REGWEN_1_REG_OFFSET, 1);
+ EXPECT_READ32(RV_CORE_IBEX_IBUS_REGWEN_1_REG_OFFSET, 0);
+
+ EXPECT_EQ(dif_rv_core_ibex_configure_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_1, kRegion),
+ kDifLocked);
+}
+
+TEST_F(AddressTranslationTest, NotPowerOfTwo) {
+ dif_rv_core_ibex_addr_translation_region_t region = kRegion;
+ region.dbus.size += 0x20;
+ EXPECT_DIF_BADARG(dif_rv_core_ibex_configure_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_1, region));
+
+ region.dbus.size -= 0x20;
+ region.ibus.size += 0x20;
+ EXPECT_DIF_BADARG(dif_rv_core_ibex_configure_addr_translation(
+ &ibex_, kDifRvCoreIbexAddrTranslationSlot_0, region));
+}
+
+} // namespace dif_rv_core_ibex_test