From bd73cd55124aa5c032291932f15591d0b6efdf70 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 7 Sep 2021 23:40:24 -0400 Subject: [PATCH] sys: util: provide bitfield construction/extraction utility macros Those are especially useful with hardware device registers. They behave the same way as their Linux equivalent, with a much simpler implementation for now. Example: #define REG_FIELD_A GENMASK(6, 0) #define REG_FIELD_B BIT(7) #define REG_FIELD_C GENMASK(15, 8) #define REG_FIELD_D GENMASK(31, 16) Get: a = FIELD_GET(REG_FIELD_A, reg); b = FIELD_GET(REG_FIELD_B, reg); Set: reg = FIELD_PREP(REG_FIELD_A, 1) | FIELD_PREP(REG_FIELD_B, 0) | FIELD_PREP(REG_FIELD_C, c) | FIELD_PREP(REG_FIELD_D, 0x40); Modify: reg &= ~REG_FIELD_C; reg |= FIELD_PREP(REG_FIELD_C, c); Signed-off-by: Nicolas Pitre --- include/sys/util.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/sys/util.h b/include/sys/util.h index 08739ff9ec6..c9db6a654f4 100644 --- a/include/sys/util.h +++ b/include/sys/util.h @@ -58,6 +58,22 @@ extern "C" { #define GENMASK(h, l) \ (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +/** @brief Extract the Least Significant Bit from @p value. */ +#define LSB_GET(value) ((value) & -(value)) + +/** + * @brief Extract a bitfield element from @p value corresponding to + * the field mask @p mask. + */ +#define FIELD_GET(mask, value) (((value) & (mask)) / LSB_GET(mask)) + +/** + * @brief Prepare a bitfield element using @p value with @p mask representing + * its field position and width. The result should be combined + * with other fields using a logical OR. + */ +#define FIELD_PREP(mask, value) (((value) * LSB_GET(mask)) & (mask)) + /** @brief 0 if @p cond is true-ish; causes a compile error otherwise. */ #define ZERO_OR_COMPILE_ERROR(cond) ((int) sizeof(char[1 - 2 * !(cond)]) - 1)