diff mbox series

[RFC,1/7] hw/registerfields: Add shared fields macros

Message ID 20220331043248.2237838-2-komlodi@google.com
State New
Headers show
Series aspeed: i2c: Add new mode support | expand

Commit Message

Joe Komlodi March 31, 2022, 4:32 a.m. UTC
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 <komlodi@google.com>
Change-Id: Id3dc53e7d2f8741c95697cbae69a81bb699fa3cb
---
 include/hw/registerfields.h | 70 +++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

Comments

Cédric Le Goater April 6, 2022, 10:26 a.m. UTC | #1
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 <komlodi@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
diff mbox series

Patch

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