[sw, libbase] Create non-volatile bit manipulation library

This change was suggested by Miguel Young, and aims to create a set of
bit manipulation routines that can be used across the project.

The functionality added in this change can be used in mmio library,
which will simply wrap the non-volatile versions. This would make it
easier to create a set of expectations in the mock MMIO library to
mimic the mmio library exactly.

There could be other use-cases outside of DIF that could benefit from
non-volatile bit manipulation API.

Signed-off-by: Silvestrs Timofejevs <silvestrst@lowrisc.org>
diff --git a/sw/device/lib/base/bitfield.c b/sw/device/lib/base/bitfield.c
new file mode 100644
index 0000000..171f0cf
--- /dev/null
+++ b/sw/device/lib/base/bitfield.c
@@ -0,0 +1,9 @@
+// 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/base/bitfield.h"
+
+// |extern| declarations to give the inline functions in the
+// corresponding header a link location.
+extern void bitfield_set_field32(uint32_t bitfield, bitfield_field32_t field);
diff --git a/sw/device/lib/base/bitfield.h b/sw/device/lib/base/bitfield.h
new file mode 100644
index 0000000..3bb5c5a
--- /dev/null
+++ b/sw/device/lib/base/bitfield.h
@@ -0,0 +1,46 @@
+// 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_BASE_BITFIELD_H_
+#define OPENTITAN_SW_DEVICE_LIB_BASE_BITFIELD_H_
+
+#include <stdint.h>
+
+/**
+ * Masked field for use in 32-bit bitfields.
+ *
+ * `index` represents a shift in bits starting from the 0 bit of a given 32-bit
+ * bitfield. It is used to zero the memory inside this bitfield by applying an
+ * inverted `mask` at the `index` offset. `value` is then capped by applying
+ * `mask` and is shifted to the `index` bits of the bitfield.
+ *
+ * Example:
+ * ```
+ * 32-bit bitfield = 0b11111111'11111111'11111111'11111111
+ * set_field32( mask = 0b11111111, index = 16, value = 0b01111110 (126) )
+ * result 32-bit bitfield = 0b11111111'01111110'11111111'11111111
+ * ```
+ */
+typedef struct bitfield_field32 {
+  uint32_t mask;  /**< The field mask. */
+  uint32_t index; /**< The field position within a bitfield. */
+  uint32_t value; /**< The field value to be written. */
+} bitfield_field32_t;
+
+/**
+ * Sets @p field in the @p bitfield.
+ *
+ * This function uses the bitfield_field32 type @p field to set a value
+ * at a given offset in @p bitfield. The relevant portion of @p bitfield
+ * is zeroed before the value is set.
+ *
+ * @param bitfield Bitfield to set the field in.
+ * @param field field within selected register field to be set.
+ */
+inline void bitfield_set_field32(uint32_t bitfield, bitfield_field32_t field) {
+  bitfield &= ~(field.mask << field.index);
+  bitfield |= (field.value & field.mask) << field.index;
+}
+
+#endif  // OPENTITAN_SW_DEVICE_LIB_BASE_BITFIELD_H_
diff --git a/sw/device/lib/base/meson.build b/sw/device/lib/base/meson.build
index 7a0e2e0..cf85dfe 100644
--- a/sw/device/lib/base/meson.build
+++ b/sw/device/lib/base/meson.build
@@ -4,6 +4,14 @@
 
 subdir('freestanding')
 
+# Non volatile bit manipulation helper library (sw_lib_bitfield).
+sw_lib_bitfield = declare_dependency(
+  link_with: static_library(
+    'bitfield_ot',
+    sources: ['bitfield.c'],
+  )
+)
+
 # Memory Operations library (sw_lib_mem)
 sw_lib_mem = declare_dependency(
   link_with: static_library(