On 3/31/22 06:32, Joe Komlodi wrote:
Occasionally a peripheral will have different operating modes, where the
MMIO layout changes, but some of the register fields have the same offsets
and behaviors.
To help support this, we add SHARED_FIELD_XX macros that create SHIFT,
LENGTH, and MASK macros for the fields that are shared across registers,
and accessors for these fields.
An example use may look as follows:
There is a peripheral with registers REG_MODE1 and REG_MODE2 at
different addreses, and both have a field FIELD1 initialized by
SHARED_FIELD().
Depending on what mode the peripheral is operating in, the user could
extract FIELD1 via
SHARED_ARRAY_FIELD_EX32(s->regs, R_REG_MODE1, FIELD1)
or
SHARED_ARRAY_FIELD_EX32(s->regs, R_REG_MODE2, FIELD1)
Signed-off-by: Joe Komlodi <koml...@google.com>
Change-Id: Id3dc53e7d2f8741c95697cbae69a81bb699fa3cb
I would merge patch 1,3,7 but without the new mode definitions first
and in another header file because we don't need to expose the register
definitions outside the I2C model.
See hw/intc/pnv_xive*regs.h for an example.
Thanks,
C.
---
include/hw/registerfields.h | 70 +++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/include/hw/registerfields.h b/include/hw/registerfields.h
index f2a3c9c41f..cf3bc3a6e3 100644
--- a/include/hw/registerfields.h
+++ b/include/hw/registerfields.h
@@ -108,4 +108,74 @@
#define ARRAY_FIELD_DP64(regs, reg, field, val) \
(regs)[R_ ## reg] = FIELD_DP64((regs)[R_ ## reg], reg, field, val);
+
+/*
+ * These macros can be used for defining and extracting fields that have the
+ * same bit position across multiple registers.
+ */
+
+/* Define shared SHIFT, LENGTH, and MASK constants */
+#define SHARED_FIELD(name, shift, length) \
+ enum { name ## _ ## SHIFT = (shift)}; \
+ enum { name ## _ ## LENGTH = (length)}; \
+ enum { name ## _ ## MASK = MAKE_64BIT_MASK(shift, length)};
+
+/* Extract a shared field */
+#define SHARED_FIELD_EX8(storage, field) \
+ extract8((storage), field ## _SHIFT, field ## _LENGTH)
+
+#define SHARED_FIELD_EX16(storage, field) \
+ extract16((storage), field ## _SHIFT, field ## _LENGTH)
+
+#define SHARED_FIELD_EX32(storage, field) \
+ extract32((storage), field ## _SHIFT, field ## _LENGTH)
+
+#define SHARED_FIELD_EX64(storage, field) \
+ extract64((storage), field ## _SHIFT, field ## _LENGTH)
+
+/* Extract a shared field from a register array */
+#define SHARED_ARRAY_FIELD_EX32(regs, offset, field) \
+ SHARED_FIELD_EX32((regs)[(offset)], field)
+#define SHARED_ARRAY_FIELD_EX64(regs, offset, field) \
+ SHARED_FIELD_EX64((regs)[(offset)], field)
+
+/* Deposit a shared field */
+#define SHARED_FIELD_DP8(storage, field, val) ({ \
+ struct { \
+ unsigned int v:field ## _LENGTH; \
+ } _v = { .v = val }; \
+ uint8_t _d; \
+ _d = deposit32((storage), field ## _SHIFT, field ## _LENGTH, _v.v); \
+ _d; })
+
+#define SHARED_FIELD_DP16(storage, field, val) ({ \
+ struct { \
+ unsigned int v:field ## _LENGTH; \
+ } _v = { .v = val }; \
+ uint16_t _d; \
+ _d = deposit32((storage), field ## _SHIFT, field ## _LENGTH, _v.v); \
+ _d; })
+
+#define SHARED_FIELD_DP32(storage, field, val) ({ \
+ struct { \
+ unsigned int v:field ## _LENGTH; \
+ } _v = { .v = val }; \
+ uint32_t _d; \
+ _d = deposit32((storage), field ## _SHIFT, field ## _LENGTH, _v.v); \
+ _d; })
+
+#define SHARED_FIELD_DP64(storage, field, val) ({ \
+ struct { \
+ uint64_t v:field ## _LENGTH; \
+ } _v = { .v = val }; \
+ uint64_t _d; \
+ _d = deposit64((storage), field ## _SHIFT, field ## _LENGTH, _v.v); \
+ _d; })
+
+/* Deposit a shared field to a register array */
+#define SHARED_ARRAY_FIELD_DP32(regs, offset, field, val) \
+ (regs)[(offset)] = SHARED_FIELD_DP32((regs)[(offset)], field, val);
+#define SHARED_ARRAY_FIELD_DP64(regs, offset, field, val) \
+ (regs)[(offset)] = SHARED_FIELD_DP64((regs)[(offset)], field, val);
+
#endif