From 1a91f92d4c6c06be6ee5f8511a40ba0da100c670 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 4 Jan 2025 21:58:52 +0900 Subject: [PATCH 1/7] sys: util: Add `GET_ARGS_FIRST_N` to get the first N of the args Gets the specified number of elements from the beginning of the list. This is the symmetircal operation as `GET_ARGS_LESS_N`. Signed-off-by: TOKITA Hiroshi --- include/zephyr/sys/util_loops.h | 382 ++++++++++++++++++++++++++++++++ include/zephyr/sys/util_macro.h | 10 + 2 files changed, 392 insertions(+) diff --git a/include/zephyr/sys/util_loops.h b/include/zephyr/sys/util_loops.h index 8c71edd16f363..afe2c004a6087 100644 --- a/include/zephyr/sys/util_loops.h +++ b/include/zephyr/sys/util_loops.h @@ -1051,6 +1051,388 @@ _47, _48, _49, _50, _51, _52, _53, _54, _55, \ _56, _57, _58, _59, _60, _61, _62, _63, ...) __VA_ARGS__ +#define Z_GET_ARGS_FIRST_0(...) + +#define Z_GET_ARGS_FIRST_1(_0, ...) _0 + +#define Z_GET_ARGS_FIRST_2(_0, _1, ...) _0, _1 + +#define Z_GET_ARGS_FIRST_3(_0, _1, _2, ...) _0, _1, _2 + +#define Z_GET_ARGS_FIRST_4(_0, _1, _2, _3, ...) _0, _1, _2, _3 + +#define Z_GET_ARGS_FIRST_5(_0, _1, _2, _3, _4, ...) _0, _1, _2, _3, _4 + +#define Z_GET_ARGS_FIRST_6(_0, _1, _2, _3, _4, _5, ...) _0, _1, _2, _3, _4, _5 + +#define Z_GET_ARGS_FIRST_7(_0, _1, _2, _3, _4, _5, _6, ...) _0, _1, _2, _3, _4, _5, _6 + +#define Z_GET_ARGS_FIRST_8(_0, _1, _2, _3, _4, _5, _6, _7, ...) _0, _1, _2, _3, _4, _5, _6, _7 + +#define Z_GET_ARGS_FIRST_9(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8 + +#define Z_GET_ARGS_FIRST_10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9 + +#define Z_GET_ARGS_FIRST_11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10 + +#define Z_GET_ARGS_FIRST_12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11 + +#define Z_GET_ARGS_FIRST_13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12 + +#define Z_GET_ARGS_FIRST_14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13 + +#define Z_GET_ARGS_FIRST_15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14 + +#define Z_GET_ARGS_FIRST_16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15 + +#define Z_GET_ARGS_FIRST_17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16 + +#define Z_GET_ARGS_FIRST_18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17 + +#define Z_GET_ARGS_FIRST_19(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18 + +#define Z_GET_ARGS_FIRST_20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19 + +#define Z_GET_ARGS_FIRST_21(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20 + +#define Z_GET_ARGS_FIRST_22(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21 + +#define Z_GET_ARGS_FIRST_23(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22 + +#define Z_GET_ARGS_FIRST_24(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23 + +#define Z_GET_ARGS_FIRST_25(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24 + +#define Z_GET_ARGS_FIRST_26(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25 + +#define Z_GET_ARGS_FIRST_27(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26 + +#define Z_GET_ARGS_FIRST_28(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27 + +#define Z_GET_ARGS_FIRST_29(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28 + +#define Z_GET_ARGS_FIRST_30(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29 + +#define Z_GET_ARGS_FIRST_31(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30 + +#define Z_GET_ARGS_FIRST_32(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31 + +#define Z_GET_ARGS_FIRST_33(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32 + +#define Z_GET_ARGS_FIRST_34(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33 + +#define Z_GET_ARGS_FIRST_35(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34 + +#define Z_GET_ARGS_FIRST_36(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35 + +#define Z_GET_ARGS_FIRST_37(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36 + +#define Z_GET_ARGS_FIRST_38(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37 + +#define Z_GET_ARGS_FIRST_39(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38 + +#define Z_GET_ARGS_FIRST_40(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39 + +#define Z_GET_ARGS_FIRST_41(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40 + +#define Z_GET_ARGS_FIRST_42(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41 + +#define Z_GET_ARGS_FIRST_43(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42 + +#define Z_GET_ARGS_FIRST_44(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43 + +#define Z_GET_ARGS_FIRST_45(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44 + +#define Z_GET_ARGS_FIRST_46(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45 + +#define Z_GET_ARGS_FIRST_47(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46 + +#define Z_GET_ARGS_FIRST_48(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47 + +#define Z_GET_ARGS_FIRST_49(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48 + +#define Z_GET_ARGS_FIRST_50(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49 + +#define Z_GET_ARGS_FIRST_51(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50 + +#define Z_GET_ARGS_FIRST_52(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, _51, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51 + +#define Z_GET_ARGS_FIRST_53(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, _51, _52, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, \ + _52 + +#define Z_GET_ARGS_FIRST_54(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, \ + _52, _53 + +#define Z_GET_ARGS_FIRST_55(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, \ + _52, _53, _54 + +#define Z_GET_ARGS_FIRST_56(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, \ + _52, _53, _54, _55 + +#define Z_GET_ARGS_FIRST_57(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, \ + _52, _53, _54, _55, _56 + +#define Z_GET_ARGS_FIRST_58(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, \ + ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, \ + _52, _53, _54, _55, _56, _57 + +#define Z_GET_ARGS_FIRST_59(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, \ + _58, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, \ + _52, _53, _54, _55, _56, _57, _58 + +#define Z_GET_ARGS_FIRST_60(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, \ + _58, _59, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, \ + _52, _53, _54, _55, _56, _57, _58, _59 + +#define Z_GET_ARGS_FIRST_61(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, \ + _58, _59, _60, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, \ + _52, _53, _54, _55, _56, _57, _58, _59, _60 + +#define Z_GET_ARGS_FIRST_62(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, \ + _58, _59, _60, _61, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, \ + _52, _53, _54, _55, _56, _57, _58, _59, _60, _61 + +#define Z_GET_ARGS_FIRST_63(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, \ + _58, _59, _60, _61, _62, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, \ + _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62 + +#define Z_GET_ARGS_FIRST_64(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \ + _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, \ + _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, \ + _58, _59, _60, _61, _62, _63, ...) \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, \ + _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, \ + _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63 + #define Z_FOR_EACH_IDX_FIXED_ARG_EXEC(idx, x, fixed_arg0, fixed_arg1) \ fixed_arg0(idx, x, fixed_arg1) diff --git a/include/zephyr/sys/util_macro.h b/include/zephyr/sys/util_macro.h index c8901e21454ae..cba3a6140a76a 100644 --- a/include/zephyr/sys/util_macro.h +++ b/include/zephyr/sys/util_macro.h @@ -400,6 +400,16 @@ extern "C" { */ #define GET_ARGS_LESS_N(N, ...) Z_GET_ARGS_LESS_##N(__VA_ARGS__) +/** + * @brief Get the first N arguments from the argument list. + * + * @param N Number of arguments to take. + * @param ... Variable list of arguments. + * + * @return argument list only contains first N arguments. + */ +#define GET_ARGS_FIRST_N(N, ...) Z_GET_ARGS_FIRST_##N(__VA_ARGS__) + /** * @brief Like a || b, but does evaluation and * short-circuiting at C preprocessor time. From f6af6de9d182dc172296790d8593a987f6d4a309 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 18 Jan 2025 18:47:01 +0900 Subject: [PATCH 2/7] tests: unit: util: Add test for `GET_ARGS_FIRST_N` Add `GET_ARGS_FIRST_N` tests. Signed-off-by: TOKITA Hiroshi --- tests/unit/util/main.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/unit/util/main.c b/tests/unit/util/main.c index 358466f8f9f2e..6e350f59e08d1 100644 --- a/tests/unit/util/main.c +++ b/tests/unit/util/main.c @@ -559,6 +559,28 @@ ZTEST(util, test_GET_ARGS_LESS_N) { zassert_equal(c[0], 3); } +ZTEST(util, test_GET_ARGS_FIRST_N) +{ + uint8_t a[] = {GET_ARGS_FIRST_N(0, 1, 2, 3)}; + uint8_t b[] = {GET_ARGS_FIRST_N(1, 1, 2, 3)}; + uint8_t c[] = {GET_ARGS_FIRST_N(2, 1, 2, 3)}; + uint8_t d[] = {GET_ARGS_FIRST_N(3, 1, 2, 3)}; + + zassert_equal(sizeof(a), 0); + + zassert_equal(sizeof(b), 1); + zassert_equal(b[0], 1); + + zassert_equal(sizeof(c), 2); + zassert_equal(c[0], 1); + zassert_equal(c[1], 2); + + zassert_equal(sizeof(d), 3); + zassert_equal(d[0], 1); + zassert_equal(d[1], 2); + zassert_equal(d[2], 3); +} + ZTEST(util, test_mixing_GET_ARG_and_FOR_EACH) { #undef TEST_MACRO #define TEST_MACRO(x) x, From 47300572d3568e9f3fd8b34f5bac15c32f64424f Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Tue, 25 Mar 2025 12:00:37 +0900 Subject: [PATCH 3/7] dts: bindings: Change `*-map-mask` and `*-map-pass-thru` as array type. They must be `array` type to match the existing `interrupt-map-mask` and `interrupt-map-pass-thru`. And also, updating descriptions. Signed-off-by: TOKITA Hiroshi --- dts/bindings/gpio/gpio-nexus.yaml | 8 ++++++-- dts/bindings/pwm/pwm-nexus.yaml | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/dts/bindings/gpio/gpio-nexus.yaml b/dts/bindings/gpio/gpio-nexus.yaml index a1bcbc61e5ae0..d33676f7d4f5d 100644 --- a/dts/bindings/gpio/gpio-nexus.yaml +++ b/dts/bindings/gpio/gpio-nexus.yaml @@ -2,6 +2,10 @@ # SPDX-License-Identifier: Apache-2.0 # Common fields for GPIO nexus nodes +# +# see 2.5 Nexus Nodes and Specifier Mapping +# https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#nexus-nodes-and-specifier-mapping +# in the Devicetree Specification properties: gpio-map: @@ -9,10 +13,10 @@ properties: required: true gpio-map-mask: - type: compound + type: array gpio-map-pass-thru: - type: compound + type: array "#gpio-cells": type: int diff --git a/dts/bindings/pwm/pwm-nexus.yaml b/dts/bindings/pwm/pwm-nexus.yaml index 17901d23ced3c..e11921e4f8838 100644 --- a/dts/bindings/pwm/pwm-nexus.yaml +++ b/dts/bindings/pwm/pwm-nexus.yaml @@ -2,6 +2,10 @@ # SPDX-License-Identifier: Apache-2.0 # Common fields for PWM nexus nodes +# +# see 2.5 Nexus Nodes and Specifier Mapping +# https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#nexus-nodes-and-specifier-mapping +# in the Devicetree Specification properties: pwm-map: From 71b9134c17e8ab4ac205c289978f1d9dcdbdf222 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Tue, 25 Mar 2025 21:12:09 +0900 Subject: [PATCH 4/7] dts: bindings: Add interrupt-nexus and io-channel-nexus base bindings Add a base binding for interrupt and io-channel nexus nodes. This makes the implicit definitions explicit. Replace existing individual map definitions with this. This file does not define a specific `compatible` on its own, So you should include this file before using it practically. Signed-off-by: TOKITA Hiroshi --- dts/bindings/adc/arduino,uno-adc.yaml | 18 +------------- dts/bindings/iio/io-channel-nexus.yaml | 24 +++++++++++++++++++ .../interrupt-controller/interrupt-nexus.yaml | 24 +++++++++++++++++++ .../pcie/host/pci-host-ecam-generic.yaml | 8 +------ 4 files changed, 50 insertions(+), 24 deletions(-) create mode 100644 dts/bindings/iio/io-channel-nexus.yaml create mode 100644 dts/bindings/interrupt-controller/interrupt-nexus.yaml diff --git a/dts/bindings/adc/arduino,uno-adc.yaml b/dts/bindings/adc/arduino,uno-adc.yaml index 854e640914a4f..6d409b861b13f 100644 --- a/dts/bindings/adc/arduino,uno-adc.yaml +++ b/dts/bindings/adc/arduino,uno-adc.yaml @@ -13,20 +13,4 @@ description: | compatible: "arduino,uno-adc" -include: base.yaml - -properties: - io-channel-map: - type: compound - required: true - - io-channel-map-mask: - type: compound - - io-channel-map-pass-thru: - type: compound - - "#io-channel-cells": - type: int - required: true - description: Number of items to expect in an ADC specifier +include: [base.yaml, io-channel-nexus.yaml] diff --git a/dts/bindings/iio/io-channel-nexus.yaml b/dts/bindings/iio/io-channel-nexus.yaml new file mode 100644 index 0000000000000..9c9d6be5b0d56 --- /dev/null +++ b/dts/bindings/iio/io-channel-nexus.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2025 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +# Common fields for io-channel nexus +# +# see 2.5 Nexus Nodes and Specifier Mapping +# https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#nexus-nodes-and-specifier-mapping +# in the Devicetree Specification + +properties: + io-channel-map: + type: compound + required: true + + io-channel-map-mask: + type: array + + io-channel-map-pass-thru: + type: array + + "#io-channel-cells": + type: int + required: true + description: Number of items to expect in the io-channel specifier, such as ADC channels. diff --git a/dts/bindings/interrupt-controller/interrupt-nexus.yaml b/dts/bindings/interrupt-controller/interrupt-nexus.yaml new file mode 100644 index 0000000000000..1b5eda6876160 --- /dev/null +++ b/dts/bindings/interrupt-controller/interrupt-nexus.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2025 TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +# Common fields for interrupt nexus nodes +# +# See 2.4 Interrupts and Interrupt Mapping +# https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#interrupts-and-interrupt-mapping +# in the Devicetree Specification + +properties: + interrupt-map: + type: compound + required: true + + interrupt-map-mask: + type: array + + interrupt-map-pass-thru: + type: array + + "#interrupt-cells": + type: int + required: true + description: Number of items to expect in a interrupt specifier diff --git a/dts/bindings/pcie/host/pci-host-ecam-generic.yaml b/dts/bindings/pcie/host/pci-host-ecam-generic.yaml index fea7d35ef17a5..0a42b180665a3 100644 --- a/dts/bindings/pcie/host/pci-host-ecam-generic.yaml +++ b/dts/bindings/pcie/host/pci-host-ecam-generic.yaml @@ -5,7 +5,7 @@ description: PCIe Controller in ECAM mode compatible: "pci-host-ecam-generic" -include: pcie-controller.yaml +include: [pcie-controller.yaml, interrupt-nexus.yaml] properties: reg: @@ -22,11 +22,5 @@ properties: definition of non-prefetchable memory. One or both of prefetchable Memory and IO Space may also be provided. - interrupt-map-mask: - type: array - - interrupt-map: - type: compound - bus-range: type: array From 81c33ad2372992112a7ec66a818fcf99e2abc45e Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sun, 23 Mar 2025 20:07:55 +0900 Subject: [PATCH 5/7] scripts: dts: Add handling for `*-map` property This change introduces generating definitions corresponding to `*-map` property, which was currently discarded. For `*-map` properties are made able to be treated as a variation of phandle-array, assign sequential cell names for each group of specifiers (child_specifier_0, child_specifier_1, ..., parent_specifier_0, ...). The `*-map` data is like a two-dimensional array, so it is difficult to handle with the existing APIs, so we will also provide new APIs. Signed-off-by: TOKITA Hiroshi --- doc/build/dts/macros.bnf | 67 +++ include/zephyr/devicetree.h | 1 + include/zephyr/devicetree/map.h | 462 ++++++++++++++++++ scripts/dts/gen_defines.py | 68 +++ .../src/devicetree/edtlib.py | 151 ++++++ 5 files changed, 749 insertions(+) create mode 100644 include/zephyr/devicetree/map.h mode change 100755 => 100644 scripts/dts/gen_defines.py diff --git a/doc/build/dts/macros.bnf b/doc/build/dts/macros.bnf index f5e676f8f44a3..8a15b3d9b6993 100644 --- a/doc/build/dts/macros.bnf +++ b/doc/build/dts/macros.bnf @@ -22,6 +22,8 @@ node-macro = property-macro node-macro =/ pinctrl-macro ; A macro about the GPIO hog properties in a node. node-macro =/ gpiohogs-macro +; A macro about the map properties in a node. +node-macro =/ map-macro ; EXISTS macro: node exists in the devicetree node-macro =/ %s"DT_N" path-id %s"_EXISTS" ; Bus macros: the plain BUS is a way to access a node's bus controller. @@ -231,6 +233,71 @@ gpiohogs-macro =/ %s"DT_N" path-id %s"_GPIO_HOGS_IDX_" DIGIT %s"_VAL_flags_EXIST ; #define DT_N__GPIO_HOGS_IDX_0_VAL_flags 0x30 gpiohogs-macro =/ %s"DT_N" path-id %s"_GPIO_HOGS_IDX_" DIGIT %s"_VAL_flags" + +; -------------------------------------------------------------------- +; map-macro: a macro related to map properties +; +; Macros are generated when there is a property ending with '-map' as shown below. +; +; connector { +; ... +; interrupt-map = <0 1 &intc0 2 3>; +; }; +; +; The existence of map entry; +; +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_EXISTS 1 +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT "_EXISTS" +; +; The child addrsss length, value, and existence. +; +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_CHILD_ADDRESS_LEN 1 +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_CHILD_ADDRESS_IDX_0 0 +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_CHILD_ADDRESS_IDX_0_EXISTS 1 +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT %s"_CHILD_ADDRESS_LEN" +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT %s"_CHILD_ADDRESS_IDX_" DIGIT +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT %s"_CHILD_ADDRESS_IDX_" DIGIT %s"_EXISTS" +; +; The length of child specifiers length, value, and existence. +; +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_CHILD_SPECIFIER_LEN 1 +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_CHILD_SPECIFIER_IDX_0_EXISTS 1 +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_CHILD_SPECIFIER_IDX_0 0 +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT %s"_CHILD_SPECIFIER_LEN" +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT %s"_CHILD_SPECIFIER_IDX_" DIGIT +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT %s"_CHILD_SPECIFIER_IDX_" DIGIT "_EXISTS" +; +; The parent node of this map. +; +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_PARENT DT_N_S_gpio_emul +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT %s"_PARENT" +; +; The length of parent addrsss, value, and existence. +; +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_PARENT_ADDRESS_LEN 1 +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_PARENT_ADDRESS_IDX_0 2 +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_PARENT_ADDRESS_IDX_0_EXISTS 1 +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT %s"_PARENT_ADDRESS_LEN" +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT %s"_PARENT_ADDRESS_IDX_" DIGIT +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT %s"_PARENT_ADDRESS_IDX_" DIGIT "_EXISTS" +; +; The length of parent specifiers length, value, and existence. +; +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_PARENT_SPECIFIER_LEN 1 +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_PARENT_SPECIFIER_IDX_0_EXISTS 1 +; #define DT_N_S_connector_P_interrupt_map_MAP_ENTRY_0_PARENT_SPECIFIER_IDX_0 3 +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT %s"_PARENT_SPECIFIER_LEN" +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT %s"_PARENT_SPECIFIER_IDX_" DIGIT +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_MAP_ENTRY_" DIGIT %s"_PARENT_SPECIFIER_IDX_" DIGIT "_EXISTS" +; +; Iteration helpers for map. +; +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_FOREACH_MAP_ENTRY" +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_FOREACH_MAP_ENTRY_SEP" +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_FOREACH_MAP_ENTRY_VARGS" +map-macro =/ %s"DT_N" path-id %s"_P_" prop-id %s"_FOREACH_MAP_ENTRY_SEP_VARGS" + + ; -------------------------------------------------------------------- ; property-macro: a macro related to a node property ; diff --git a/include/zephyr/devicetree.h b/include/zephyr/devicetree.h index e10cb7c8c5fec..c928f98ef72c8 100644 --- a/include/zephyr/devicetree.h +++ b/include/zephyr/devicetree.h @@ -5571,5 +5571,6 @@ #include #include #include +#include #endif /* ZEPHYR_INCLUDE_DEVICETREE_H_ */ diff --git a/include/zephyr/devicetree/map.h b/include/zephyr/devicetree/map.h new file mode 100644 index 0000000000000..6b797f22d2c53 --- /dev/null +++ b/include/zephyr/devicetree/map.h @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2025 TOKITA Hiroshi + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DEVICETREE_MAP_H_ +#define ZEPHYR_INCLUDE_DEVICETREE_MAP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup devicetree-map Devicetree Map API + * + * @brief Helper macros for handling map properties. + * + * This module provides helper macros that facilitate interrupt mapping and + * specifier mapping based on DeviceTree specifications. It enables the extraction + * and interpretation of mapping data represented as phandle-arrays. + * + * In a typical DeviceTree fragment, properties ending with "-map" specify: + * - The child specifier to be mapped. + * - The parent node (phandle) to which the mapping applies. + * - The parent specifier associated with the mapping. + * + * For example, when the following DeviceTree snippet is defined: + * + * @code{.dts} + * n: node { + * gpio-map = <0 1 &gpio0 2 3>, <4 5 &gpio0 6 7>; + * }; + * @endcode + * + * In the first mapping entry: + * - `0 1` are the child specifiers. + * - &gpio0 is the parent node. + * - `2 3` are the parent specifiers. + * + * The map API provides the following macros for access to specific parts of a mapping entry: + * - DT_MAP_ENTRY_CHILD_ADDRESS_BY_IDX() + * - DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX() + * - DT_MAP_ENTRY_PARENT_ADDRESS_BY_IDX() + * - DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX() + * - DT_MAP_ENTRY_PARENT_BY_IDX() + * + * These macros extract, respectively, the child specifier arguments, the parent specifier + * arguments, and the parent node argument from a mapping element identified by its node ID, + * property name, and index. + * + * For instance: + * + * @code{.c} + * #define SRC_AND_DST(node_id, map, entry_idx) \ + * { DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(node_id, map, entry_idx, 0)), \ + * DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(node_id, map, entry_idx, 0)) } + * + * int src_and_dst[][2] = { + * DT_FOREACH_MAP_ENTRY_SEP(DT_NODELABEL(n), gpio_map, SRC_AND_DST, (,)) + * }; + * @endcode + * + * The above expansion yields: + * + * @code{.c} + * int src_and_dst[][2] = {{0, 2}, {4, 6}}; + * @endcode + * + * @ingroup devicetree + * @{ + */ + +/** + * @brief Returns the existence of map property. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @retval True if the map exists, otherwise 0. + * + * @see DT_NODE_HAS_PROP + */ +#define DT_NODE_HAS_MAP(node_id, prop) DT_NODE_HAS_PROP(node_id, prop) + +/** + * @brief Returns the number of maps for the given property. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @return The total count of mapping entries. + * + * @see DT_PROP_LEN + */ +#define DT_MAP_LEN(node_id, prop) DT_PROP_LEN(node_id, prop) + +/** + * @brief Is index @p idx valid for an array type property? + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx index to check + * @return An expression which evaluates to 1 if @p idx is a valid index + * into the given property, and 0 otherwise. + */ +#define DT_MAP_HAS_ENTRY_BY_IDX(node_id, prop, entry_idx) \ + IS_ENABLED(DT_CAT6(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _EXISTS)) + +/** + * @brief Checks if the map property has any entries. + * + * Equivalent to calling @ref DT_MAP_HAS_ENTRY_BY_IDX with @p entry_idx set to + * zero. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @return An expression which evaluates to 1 if @p idx is a valid index + * into the given property, and 0 otherwise. + */ +#define DT_MAP_HAS_ENTRY(node_id, prop) DT_MAP_HAS_ENTRY_BY_IDX(node_id, prop, 0) + +/** + * @brief Get the number of child addresses. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @return The number of child addresses. + */ +#define DT_MAP_ENTRY_CHILD_ADDRESS_LEN(node_id, prop, entry_idx) \ + DT_CAT6(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _CHILD_ADDRESS_LEN) + +/** + * @brief Checks if the child address has the specified index. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @param param_idx The index in the child addresses. + * @retval True if the child address has the index, otherwise 0. + */ +#define DT_MAP_ENTRY_HAS_CHILD_ADDRESS_BY_IDX(node_id, prop, entry_idx, param_idx) \ + IS_ENABLED(DT_CAT8(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _CHILD_ADDRESS_IDX_, \ + param_idx, _EXISTS)) + +/** + * @brief Checks if the mapping entry has any child addresses. + * + * Equivalent to calling @ref DT_MAP_ENTRY_HAS_CHILD_ADDRESS_BY_IDX with + * @p param_idx set to zero. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @retval True if the child address has the index, otherwise 0. + */ +#define DT_MAP_ENTRY_HAS_CHILD_ADDRESS(node_id, prop, entry_idx) \ + DT_MAP_ENTRY_HAS_CHILD_ADDRESS_BY_IDX(node_id, prop, entry_idx, 0) + +/** + * @brief Get the child address element from a mapping entry, by index. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @param param_idx The index in the child addresses. + * @return The element of the specified position of the child addresses. + */ +#define DT_MAP_ENTRY_CHILD_ADDRESS_BY_IDX(node_id, prop, entry_idx, param_idx) \ + DT_CAT7(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _CHILD_ADDRESS_IDX_, param_idx) + +/** + * @brief Get the first child address element from a mapping entry. + * + * Equivalent to calling @ref DT_MAP_ENTRY_CHILD_ADDRESS_BY_IDX with + * @p param_idx set to zero. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @return The element of the specified position of the child addresses. + */ +#define DT_MAP_ENTRY_CHILD_ADDRESS(node_id, prop, entry_idx) \ + DT_MAP_ENTRY_CHILD_ADDRESS_BY_IDX(node_id, prop, entry_idx, 0) + +/** + * @brief Get the number of child specifiers. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @return The number of child specifiers. + */ +#define DT_MAP_ENTRY_CHILD_SPECIFIER_LEN(node_id, prop, entry_idx) \ + DT_CAT6(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _CHILD_SPECIFIER_LEN) + +/** + * @brief Checks if the child specifier has the specified index. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @param param_idx The index in the child specifiers. + * @retval True if the child specifier has the index, otherwise 0. + */ +#define DT_MAP_ENTRY_HAS_CHILD_SPECIFIER_BY_IDX(node_id, prop, entry_idx, param_idx) \ + IS_ENABLED(DT_CAT8(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _CHILD_SPECIFIER_IDX_, \ + param_idx, _EXISTS)) + +/** + * @brief Checks if the mapping entry has any child specifiers. + * + * Equivalent to calling @ref DT_MAP_ENTRY_HAS_CHILD_SPECIFIER_BY_IDX with + * @p param_idx set to zero. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @retval True if the child specifier has the index, otherwise 0. + */ +#define DT_MAP_ENTRY_HAS_CHILD_SPECIFIER(node_id, prop, entry_idx) \ + DT_MAP_ENTRY_HAS_CHILD_SPECIFIER_BY_IDX(node_id, prop, entry_idx, 0) + +/** + * @brief Get the child specifier element from a mapping entry, by index. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @param param_idx The index in the child specifiers. + * @return The element of the specified position of the child specifiers. + */ +#define DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(node_id, prop, entry_idx, param_idx) \ + DT_CAT7(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _CHILD_SPECIFIER_IDX_, param_idx) + +/** + * @brief Get the first child specifier element from a mapping entry. + * + * Equivalent to calling @ref DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX with + * @p param_idx set to zero. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @return The element of the specified position of the child specifiers. + */ +#define DT_MAP_ENTRY_CHILD_SPECIFIER(node_id, prop, entry_idx) \ + DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(node_id, prop, entry_idx, 0) + +/** + * @brief Extracts the parent node from a mapping entry. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @return The parent node id. + */ +#define DT_MAP_ENTRY_PARENT_BY_IDX(node_id, prop, entry_idx) \ + DT_CAT6(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _PARENT) + +/** + * @brief Extracts the parent node from the first mapping entry. + * + * Equivalent to calling @ref DT_MAP_ENTRY_PARENT_BY_IDX with @p entry_idx set + * to zero. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @return The parent node id. + */ +#define DT_MAP_ENTRY_PARENT(node_id, prop) \ + DT_MAP_ENTRY_PARENT_BY_IDX(node_id, prop, 0) + +/** + * @brief Get the number of parent addresses. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @return The number of parent addresses. + */ +#define DT_MAP_ENTRY_PARENT_ADDRESS_LEN(node_id, prop, entry_idx) \ + DT_CAT6(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _PARENT_ADDRESS_LEN) + +/** + * @brief Checks if the parent address has the specified index. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @param param_idx The index in the parent addresses. + * @retval True if the parent address has the index, otherwise 0. + */ +#define DT_MAP_ENTRY_HAS_PARENT_ADDRESS_BY_IDX(node_id, prop, entry_idx, param_idx) \ + IS_ENABLED(DT_CAT8(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _PARENT_ADDRESS_IDX_, \ + param_idx, _EXISTS)) + +/** + * @brief Checks if the mapping entry has any parent addresses. + * + * Equivalent to calling @ref DT_MAP_ENTRY_HAS_PARENT_ADDRESS_BY_IDX with + * @p param_idx set to zero. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @retval True if the parent address has the index, otherwise 0. + */ +#define DT_MAP_ENTRY_HAS_PARENT_ADDRESS(node_id, prop, entry_idx) \ + DT_MAP_ENTRY_HAS_PARENT_ADDRESS_BY_IDX(node_id, prop, entry_idx, 0) + +/** + * @brief Get the parent address element from a mapping entry, by index. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @param param_idx The index in the parent addresses. + * @retval The element of the specified position of the parent addresses. + */ +#define DT_MAP_ENTRY_PARENT_ADDRESS_BY_IDX(node_id, prop, entry_idx, param_idx) \ + DT_CAT7(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _PARENT_ADDRESS_IDX_, param_idx) + +/** + * @brief Get the first parent address element from a mapping entry. + * + * Equivalent to calling @ref DT_MAP_ENTRY_PARENT_ADDRESS_BY_IDX with + * @p param_idx set to zero. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @retval The element of the specified position of the parent addresses. + */ +#define DT_MAP_ENTRY_PARENT_ADDRESS(node_id, prop, entry_idx) \ + DT_MAP_ENTRY_PARENT_ADDRESS_BY_IDX(node_id, prop, entry_idx, 0) + +/** + * @brief Get the number of parent specifiers. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @retval The number of parent specifiers. + */ +#define DT_MAP_ENTRY_PARENT_SPECIFIER_LEN(node_id, prop, entry_idx) \ + DT_CAT6(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _PARENT_SPECIFIER_LEN) + +/** + * @brief Checks if the parent specifier has the specified index. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @param param_idx The index in the parent specifiers. + * @retval True if the parent specifier has the index, otherwise 0. + */ +#define DT_MAP_ENTRY_HAS_PARENT_SPECIFIER_BY_IDX(node_id, prop, entry_idx, param_idx) \ + IS_ENABLED(DT_CAT8(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _PARENT_SPECIFIER_IDX_, \ + param_idx, _EXISTS)) + +/** + * @brief Checks if the mapping entry has any parent specifiers. + * + * Equivalent to calling @ref DT_MAP_ENTRY_HAS_PARENT_SPECIFIER_BY_IDX with + * @p param_idx set to zero. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @retval True if the parent specifier has the index, otherwise 0. + */ +#define DT_MAP_ENTRY_HAS_PARENT_SPECIFIER(node_id, prop, entry_idx) \ + DT_MAP_ENTRY_HAS_PARENT_SPECIFIER_BY_IDX(node_id, prop, entry_idx, 0) + +/** + * @brief Get the parent specifier element from a mapping entry, by index. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @param param_idx The index in the parent specifiers. + * @retval The element of the specified position of the parent specifiers. + */ +#define DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(node_id, prop, entry_idx, param_idx) \ + DT_CAT7(node_id, _P_, prop, _MAP_ENTRY_, entry_idx, _PARENT_SPECIFIER_IDX_, param_idx) + +/** + * @brief Get the first parent specifier element from a mapping entry. + * + * Equivalent to calling @ref DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX with + * @p param_idx set to zero. + * + * @param node_id The node identifier. + * @param prop The map property name. i.e. "gpio_map" + * @param entry_idx The mapping entry index. + * @retval The element of the specified position of the parent specifiers. + */ +#define DT_MAP_ENTRY_PARENT_SPECIFIER(node_id, prop, entry_idx) \ + DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(node_id, prop, entry_idx, 0) + +/** + * @brief Invokes @p fn for each map entry in the @p map. + * + * @param node_id node identifier + * @param prop The map property name. i.e. "gpio_map" + * @param fn macro to invoke + * + * @see DT_FOREACH_PROP_ELEM + */ +#define DT_FOREACH_MAP_ENTRY(node_id, prop, fn) DT_CAT4(node_id, _P_, prop, _FOREACH_MAP_ENTRY)(fn) + +/** + * @brief Invokes @p fn for each map entry in the @p map with separator. + * + * @param node_id node identifier + * @param prop The map property name. i.e. "gpio_map" + * @param fn macro to invoke + * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; + * this is required to enable providing a comma as separator. + * + * @see DT_FOREACH_PROP_ELEM_SEP + */ +#define DT_FOREACH_MAP_ENTRY_SEP(node_id, prop, fn, sep) \ + DT_CAT4(node_id, _P_, prop, _FOREACH_MAP_ENTRY_SEP)(fn, sep) + +/** + * @brief Invokes @p fn for each map entry in the @p map with separator. + * + * @param node_id node identifier + * @param prop The map property name. i.e. "gpio_map" + * @param fn macro to invoke + * @param ... variable number of arguments to pass to fn + * + * @see DT_FOREACH_PROP_ELEM_VARGS + */ +#define DT_FOREACH_MAP_ENTRY_VARGS(node_id, prop, fn, ...) \ + DT_CAT4(node_id, _P_, prop, _FOREACH_MAP_ENTRY_VARGS)(fn, __VA_ARGS__) + +/** + * @brief Invokes @p fn for each map entry in the @p map with separator. + * + * @param node_id node identifier + * @param prop The map property name. i.e. "gpio_map" + * @param fn macro to invoke + * @param sep Separator (e.g. comma or semicolon). Must be in parentheses; + * this is required to enable providing a comma as separator. + * @param ... variable number of arguments to pass to fn + * + * @see DT_FOREACH_PROP_ELEM_SEP_VARGS + */ +#define DT_FOREACH_MAP_ENTRY_SEP_VARGS(node_id, prop, fn, sep, ...) \ + DT_CAT4(node_id, _P_, prop, _FOREACH_MAP_ENTRY_SEP_VARGS)(fn, sep, __VA_ARGS__) + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_DEVICETREE_MAP_H_ */ diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py old mode 100755 new mode 100644 index e3913dd585b79..b991935540dba --- a/scripts/dts/gen_defines.py +++ b/scripts/dts/gen_defines.py @@ -288,6 +288,7 @@ def write_special_props(node: edtlib.Node) -> None: write_pinctrls(node) write_fixed_partitions(node) write_gpio_hogs(node) + write_maps(node) def write_ranges(node: edtlib.Node) -> None: @@ -579,6 +580,73 @@ def write_gpio_hogs(node: edtlib.Node) -> None: out_dt_define(macro, val) +def write_maps(node: edtlib.Node) -> None: + if len(node.maps.keys()) == 0: + return + + out_comment("Map properties:") + + macro2val = {} + + for bn, entries in node.maps.items(): + basename = str2ident(bn) + plen = len(entries) + prop_id = f"{basename}_map" + macro = f"{node.z_path_id}_P_{basename}_map" + + # _LEN and _EXISTS share the grammer with `prop` element. + + macro2val[f"{macro}_LEN"] = plen + macro2val[f"{macro}_EXISTS"] = 1 + + # Map node specific definitions + for i, mp in enumerate(entries): + macro2val[f"{macro}_MAP_ENTRY_{i}_EXISTS"] = 1 + + macro2val[f"{macro}_MAP_ENTRY_{i}_CHILD_ADDRESS_LEN"] = len(mp.child_addresses) + for n, addr in enumerate(mp.child_addresses): + macro2val[f"{macro}_MAP_ENTRY_{i}_CHILD_ADDRESS_IDX_{n}_EXISTS"] = 1 + macro2val[f"{macro}_MAP_ENTRY_{i}_CHILD_ADDRESS_IDX_{n}"] = addr + + macro2val[f"{macro}_MAP_ENTRY_{i}_CHILD_SPECIFIER_LEN"] = len(mp.child_specifiers) + for n, sp in enumerate(mp.child_specifiers): + macro2val[f"{macro}_MAP_ENTRY_{i}_CHILD_SPECIFIER_IDX_{n}_EXISTS"] = 1 + macro2val[f"{macro}_MAP_ENTRY_{i}_CHILD_SPECIFIER_IDX_{n}"] = sp + + macro2val[f"{macro}_MAP_ENTRY_{i}_PARENT"] = "DT_" + node_z_path_id(mp.parent) + macro2val[f"{macro}_MAP_ENTRY_{i}_PARENT_ADDRESS_LEN"] = len(mp.parent_addresses) + for n, addr in enumerate(mp.parent_addresses): + macro2val[f"{macro}_MAP_ENTRY_{i}_PARENT_ADDRESS_IDX_{n}_EXISTS"] = 1 + macro2val[f"{macro}_MAP_ENTRY_{i}_PARENT_ADDRESS_IDX_{n}"] = addr + macro2val[f"{macro}_MAP_ENTRY_{i}_PARENT_SPECIFIER_LEN"] = len(mp.parent_specifiers) + for n, sp in enumerate(mp.parent_specifiers): + macro2val[f"{macro}_MAP_ENTRY_{i}_PARENT_SPECIFIER_IDX_{n}_EXISTS"] = 1 + macro2val[f"{macro}_MAP_ENTRY_{i}_PARENT_SPECIFIER_IDX_{n}"] = sp + + macro2val[f"{macro}_FOREACH_MAP_ENTRY(fn)"] = ' \\\n\t'.join( + f'fn(DT_{node.z_path_id}, {prop_id}, {i})' for i in range(plen) + ) + + macro2val[f"{macro}_FOREACH_MAP_ENTRY_SEP(fn, sep)"] = ( + ' DT_DEBRACKET_INTERNAL sep \\\n\t'.join( + f'fn(DT_{node.z_path_id}, {prop_id}, {i})' for i in range(plen) + ) + ) + + macro2val[f"{macro}_FOREACH_MAP_ENTRY_VARGS(fn, ...)"] = ' \\\n\t'.join( + f'fn(DT_{node.z_path_id}, {prop_id}, {i}, __VA_ARGS__)' for i in range(plen) + ) + + macro2val[f"{macro}_FOREACH_MAP_ENTRY_SEP_VARGS(fn, sep, ...)"] = ( + ' DT_DEBRACKET_INTERNAL sep \\\n\t'.join( + f'fn(DT_{node.z_path_id}, {prop_id}, {i}, __VA_ARGS__)' for i in range(plen) + ) + ) + + for mc, val in macro2val.items(): + out_dt_define(mc, val) + + def write_vanilla_props(node: edtlib.Node) -> None: # Writes macros for any and all properties defined in the # "properties" section of the binding for the node. diff --git a/scripts/dts/python-devicetree/src/devicetree/edtlib.py b/scripts/dts/python-devicetree/src/devicetree/edtlib.py index 183bb9ffb57a9..ef9571364cce1 100644 --- a/scripts/dts/python-devicetree/src/devicetree/edtlib.py +++ b/scripts/dts/python-devicetree/src/devicetree/edtlib.py @@ -898,6 +898,55 @@ def name_as_token(self): "See the class docstring" return str_as_token(self.name) if self.name is not None else None +@dataclass +class MapEntry: + """ + Represents a single entry parsed from a ``*-map`` property. For example, + the value '<0 0 &gpio0 14 0>' from 'gpio-map = <0 0 &gpio0 14 0>, <1 0 &gpio0 0 0>;' + becomes one ``MapEntry`` instance. + + These attributes are available on ``MapEntry`` objects: + + node: + The Node instance whose property contains the map entry. + + child_addresses: + A list of integers describing the unit address portion that precedes the + child specifier. ``interrupt-map`` entries, for example, begin with the + child unit address whose length is determined by ``#address-cells`` on the + nexus node or its parent. When no address cells are defined this list is + empty. + + child_specifiers: + A list of integers read from the child side of the map entry after any + address words. These are the specifier cells that precede the parent + phandle. + + parent: + The parent Node instance. + + parent_addresses: + The unit address portion that follows the parent phandle. Its length is + derived from the parent's ``#address-cells`` (with the same parent lookup + fallback as in the devicetree specification). Empty when no address cells + are provided. + + parent_specifiers: + A list of integers describing the parent side of the mapping after any + parent address cells. These values correspond to the ``*-cells`` + definition in the parent's binding. + + basename: + The base name of the ``*-map`` property, which also describes the + specifier space for the mapping. + """ + node: 'Node' + child_addresses: list[int] + child_specifiers: list[int] + parent: 'Node' + parent_addresses: list[int] + parent_specifiers: list[int] + basename: str class Node: """ @@ -1045,6 +1094,11 @@ class Node: list is empty if the node does not hog any GPIOs. Only relevant for GPIO hog nodes. + maps: + A dictionary that the list of MapEntry instances associated with a string key. + The key is the basename-part of the node property name, the value is + the entries of the property value. + is_pci_device: True if the node is a PCI device. """ @@ -1317,6 +1371,103 @@ def gpio_hogs(self) -> list[ControllerAndData]: return res + @property + def maps(self) -> dict[str, list[MapEntry]]: + "See the class docstring" + + res: dict[str, list[MapEntry]] = {} + + def count_specifier_cells(node: dtlib_Node, specifier: str) -> int: + """Return the number of specifier cells for *specifier* in *node*.""" + + cells_prop = f"#{specifier}-cells" + + if cells_prop not in node.props: + _err(f"{node!r} lacks required '{cells_prop}' property") + + return node.props[cells_prop].to_num() + + def count_address_cells(node: dtlib_Node) -> int: + """Return the number of interrupt address cells for *node*.""" + + if "#address-cells" in node.props: + return node.props["#address-cells"].to_num() + + if node.parent and "#address-cells" in node.parent.props: + return node.parent.props["#address-cells"].to_num() + + return 0 + + for prop in [v for k, v in self._node.props.items() if k.endswith("-map")]: + specifier_space = prop.name[:-4] # Strip '-map' + entries : list[MapEntry] = [] + raw = prop.value + while raw: + if len(raw) < 4: + # Not enough room for phandle + _err("bad value for " + repr(prop)) + + child_address_cells = 0 + if specifier_space == "interrupt": + child_address_cells = count_address_cells(prop.node) + + child_specifier_cells = count_specifier_cells(prop.node, specifier_space) + child_total_cells = child_address_cells + child_specifier_cells + + if len(raw) < 4 * child_total_cells: + _err("bad value for " + repr(prop)) + + child_cells = to_nums(raw[: 4 * child_total_cells]) + child_addresses = child_cells[:child_address_cells] + child_specifiers = child_cells[child_address_cells:] + + raw = raw[4 * child_total_cells :] + phandle = to_num(raw[:4]) + raw = raw[4:] + + parent_node = prop.node.dt.phandle2node.get(phandle) + if parent_node is None: + _err(f"parent node cannot be found from phandle:{phandle}") + + parent: Node = self.edt._node2enode[parent_node] + if parent is None: + _err("parent cannot be found from: " + repr(parent_node)) + + parent_address_cells = 0 + if specifier_space == "interrupt": + parent_address_cells = count_address_cells(parent_node) + + parent_specifier_cells = count_specifier_cells(parent_node, specifier_space) + parent_total_cells = parent_address_cells + parent_specifier_cells + + if len(raw) < 4 * parent_total_cells: + _err("bad value for " + repr(prop)) + + parent_cells = to_nums(raw[: 4 * parent_total_cells]) + parent_addresses = parent_cells[:parent_address_cells] + parent_specifiers = parent_cells[parent_address_cells:] + + raw = raw[4 * parent_total_cells :] + + entries.append( + MapEntry( + node=self, + child_addresses=child_addresses, + child_specifiers=child_specifiers, + parent=parent, + parent_addresses=parent_addresses, + parent_specifiers=parent_specifiers, + basename=specifier_space, + ) + ) + + if len(raw) != 0: + _err(f"unexpected prop.value remainings: {raw}") + + res[specifier_space] = entries + + return res + @property def has_child_binding(self) -> bool: """ From 0da9709a9676d39a0a52b0d9c4cda36002e43a70 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Sat, 20 Sep 2025 13:07:53 +0900 Subject: [PATCH 6/7] scripts: dts: devicetree: tests: Add a map property test Add a map property test for `test_edtlib.py`. Signed-off-by: TOKITA Hiroshi --- scripts/dts/python-devicetree/tests/test.dts | 17 +++- .../python-devicetree/tests/test_edtlib.py | 93 +++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/scripts/dts/python-devicetree/tests/test.dts b/scripts/dts/python-devicetree/tests/test.dts index 032eb8c843c0b..91663cde6af8e 100644 --- a/scripts/dts/python-devicetree/tests/test.dts +++ b/scripts/dts/python-devicetree/tests/test.dts @@ -71,6 +71,7 @@ interrupt-controller; }; nexus { + #address-cells = <2>; #interrupt-cells = <2>; interrupt-map = < 0 0 0 0 &{/interrupt-map-test/controller-0} 0 0 @@ -78,7 +79,13 @@ 0 0 0 2 &{/interrupt-map-test/controller-2} 0 0 0 0 0 2 0 1 0 0 &{/interrupt-map-test/controller-0} 0 3 0 1 0 1 &{/interrupt-map-test/controller-1} 0 0 0 4 - 0 1 0 2 &{/interrupt-map-test/controller-2} 0 0 0 0 0 5>; + 0 1 0 2 &{/interrupt-map-test/controller-2} 0 0 0 0 0 5 + 0 1 1 0 &{/interrupt-map-no-address/controller} 6>; + }; + empty { + #address-cells = <2>; + #interrupt-cells = <2>; + interrupt-map = <>; }; nexus-0 { #address-cells = <0>; @@ -163,6 +170,14 @@ }; }; + interrupt-map-no-address { + controller { + compatible = "interrupt-one-cell"; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + // // 'ranges' // diff --git a/scripts/dts/python-devicetree/tests/test_edtlib.py b/scripts/dts/python-devicetree/tests/test_edtlib.py index f26b5fa158150..13c4756cdc499 100644 --- a/scripts/dts/python-devicetree/tests/test_edtlib.py +++ b/scripts/dts/python-devicetree/tests/test_edtlib.py @@ -130,6 +130,99 @@ def test_interrupts(): edtlib.ControllerAndData(node=node, controller=edt.get_node('/interrupt-map-bitops-test/controller'), data={'one': 3, 'two': 2}, name=None, basename=None) ] + +def test_maps(): + '''Tests for the maps property.''' + with from_here(): + edt = edtlib.EDT("test.dts", ["test-bindings"]) + + nexus = edt.get_node("/interrupt-map-test/nexus") + controller_0 = edt.get_node("/interrupt-map-test/controller-0") + controller_1 = edt.get_node("/interrupt-map-test/controller-1") + controller_2 = edt.get_node("/interrupt-map-test/controller-2") + controller_no_addr = edt.get_node("/interrupt-map-no-address/controller") + + assert len(nexus.maps.keys()) == 1 + assert "interrupt" in nexus.maps + + entries = nexus.maps["interrupt"] + assert len(entries) == 7 + + assert entries[0] == edtlib.MapEntry( + node=nexus, + child_addresses=[0, 0], + child_specifiers=[0, 0], + parent=controller_0, + parent_addresses=[0], + parent_specifiers=[0], + basename="interrupt", + ) + + assert entries[1] == edtlib.MapEntry( + node=nexus, + child_addresses=[0, 0], + child_specifiers=[0, 1], + parent=controller_1, + parent_addresses=[0, 0], + parent_specifiers=[0, 1], + basename="interrupt", + ) + + assert entries[2] == edtlib.MapEntry( + node=nexus, + child_addresses=[0, 0], + child_specifiers=[0, 2], + parent=controller_2, + parent_addresses=[0, 0, 0], + parent_specifiers=[0, 0, 2], + basename="interrupt", + ) + + assert entries[3] == edtlib.MapEntry( + node=nexus, + child_addresses=[0, 1], + child_specifiers=[0, 0], + parent=controller_0, + parent_addresses=[0], + parent_specifiers=[3], + basename="interrupt", + ) + + assert entries[4] == edtlib.MapEntry( + node=nexus, + child_addresses=[0, 1], + child_specifiers=[0, 1], + parent=controller_1, + parent_addresses=[0, 0], + parent_specifiers=[0, 4], + basename="interrupt", + ) + + assert entries[5] == edtlib.MapEntry( + node=nexus, + child_addresses=[0, 1], + child_specifiers=[0, 2], + parent=controller_2, + parent_addresses=[0, 0, 0], + parent_specifiers=[0, 0, 5], + basename="interrupt", + ) + + assert entries[6] == edtlib.MapEntry( + node=nexus, + child_addresses=[0, 1], + child_specifiers=[1, 0], + parent=controller_no_addr, + parent_addresses=[], + parent_specifiers=[6], + basename="interrupt", + ) + + empty = edt.get_node("/interrupt-map-test/empty") + assert len(empty.maps) == 1 + assert "interrupt" in empty.maps + assert len(empty.maps["interrupt"]) == 0 + def test_ranges(): '''Tests for the ranges property''' with from_here(): From 6974b3cad474661bf6d4562603bc0e88e637347a Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Mon, 14 Apr 2025 01:58:25 +0900 Subject: [PATCH 7/7] tests: lib: devicetree: api: Add map property tests Add tests for map property related macros. Add `native_sim/native/64` to allowed platforms. Signed-off-by: TOKITA Hiroshi --- dts/bindings/test/vnd,gpio-nexus.yaml | 8 ++ dts/bindings/test/vnd,intr-nexus.yaml | 8 ++ tests/lib/devicetree/api/app.overlay | 52 +++++++++ tests/lib/devicetree/api/src/main.c | 140 +++++++++++++++++++++++++ tests/lib/devicetree/api/testcase.yaml | 1 + 5 files changed, 209 insertions(+) create mode 100644 dts/bindings/test/vnd,gpio-nexus.yaml create mode 100644 dts/bindings/test/vnd,intr-nexus.yaml diff --git a/dts/bindings/test/vnd,gpio-nexus.yaml b/dts/bindings/test/vnd,gpio-nexus.yaml new file mode 100644 index 0000000000000..2274be7451da1 --- /dev/null +++ b/dts/bindings/test/vnd,gpio-nexus.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2025, TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: VND GPIO nexus + +include: [gpio-nexus.yaml] + +compatible: "vnd,gpio-nexus" diff --git a/dts/bindings/test/vnd,intr-nexus.yaml b/dts/bindings/test/vnd,intr-nexus.yaml new file mode 100644 index 0000000000000..f3b194c558385 --- /dev/null +++ b/dts/bindings/test/vnd,intr-nexus.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2025, TOKITA Hiroshi +# SPDX-License-Identifier: Apache-2.0 + +description: VND interrupt nexus + +include: [interrupt-nexus.yaml] + +compatible: "vnd,intr-nexus" diff --git a/tests/lib/devicetree/api/app.overlay b/tests/lib/devicetree/api/app.overlay index 0404be3974d41..87fdaa0ca6a02 100644 --- a/tests/lib/devicetree/api/app.overlay +++ b/tests/lib/devicetree/api/app.overlay @@ -946,4 +946,56 @@ compatible = "vnd,non-deprecated-label"; label = "FOO"; }; + + gpio-map-test { + connector { + compatible = "vnd,gpio-nexus"; + #gpio-cells = <2>; + gpio-map = <1 2 &{/gpio-map-test/parent} 3 + 4 5 &{/gpio-map-test/parent} 6>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0x0 0x3f>; + }; + parent { + compatible = "gpio-dst"; + gpio-controller; + #gpio-cells = <1>; + }; + }; + + interrupt-map-test { + #address-cells = <2>; + #size-cells = <0>; + + controller-0@0 { + compatible = "vnd,cpu-intc"; + reg = <0x0 0x0>; + #address-cells = <1>; + #interrupt-cells = <1>; + interrupt-controller; + }; + controller-1@1 { + compatible = "vnd,intc"; + reg = <0x0 0x1>; + #address-cells = <2>; + #interrupt-cells = <2>; + interrupt-controller; + }; + nexus { + compatible = "vnd,intr-nexus"; + #address-cells = <2>; + #interrupt-cells = <2>; + interrupt-map = < + 0 0 1 2 &{/interrupt-map-test/controller-0@0} 3 4 + 0 0 5 6 &{/interrupt-map-test/controller-1@1} 7 8 9 0 + 0 1 9 8 &{/interrupt-map-test/controller-0@0} 7 6 + 0 1 5 4 &{/interrupt-map-test/controller-1@1} 3 2 1 0>; + }; + empty { + compatible = "vnd,intr-nexus"; + #address-cells = <2>; + #interrupt-cells = <2>; + interrupt-map = <>; + }; + }; }; diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c index 54d95555fe694..24951b314b02e 100644 --- a/tests/lib/devicetree/api/src/main.c +++ b/tests/lib/devicetree/api/src/main.c @@ -112,6 +112,10 @@ #define TEST_SUBPARTITION_1 DT_PATH(test, test_mtd_ffeeddcc, flash_20000000, partitions, \ partition_100, partition_40) +#define TEST_GPIO_CONNECTOR DT_PATH(gpio_map_test, connector) +#define TEST_INTERRUPT_NEXUS DT_PATH(interrupt_map_test, nexus) +#define TEST_INTERRUPT_NEXUS_EMPTY DT_PATH(interrupt_map_test, empty) + #define ZEPHYR_USER DT_PATH(zephyr_user) #define TA_HAS_COMPAT(compat) DT_NODE_HAS_COMPAT(TEST_ARRAYS, compat) @@ -3890,4 +3894,140 @@ ZTEST(devicetree_api, test_nvmem_devictree_inst) "/test/test-nvmem-provider"); } +#define INTERRUPT_NEXUS_CHECK_0(n, p, i, ...) \ + zassert_equal(DT_MAP_ENTRY_CHILD_ADDRESS_LEN(n, p, i), 2); \ + zassert_equal(DT_MAP_ENTRY_CHILD_ADDRESS_BY_IDX(n, p, i, 0), 0); \ + zassert_equal(DT_MAP_ENTRY_CHILD_ADDRESS_BY_IDX(n, p, i, 1), 0); \ + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_LEN(n, p, i), 2); \ + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(n, p, i, 0), 1); \ + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(n, p, i, 1), 2); \ + zassert_equal(DT_MAP_ENTRY_PARENT_ADDRESS_LEN(n, p, i), 1); \ + zassert_equal(DT_MAP_ENTRY_PARENT_ADDRESS_BY_IDX(n, p, i, 0), 3); \ + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER_LEN(n, p, i), 1); \ + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(n, p, i, 0), 4); \ + zassert_str_equal(STRINGIFY(DT_MAP_ENTRY_PARENT(n, p)), \ + "DT_N_S_interrupt_map_test_S_controller_0_0"); + +#define INTERRUPT_NEXUS_CHECK_1(n, p, i, ...) \ + zassert_equal(DT_MAP_ENTRY_CHILD_ADDRESS_LEN(n, p, i), 2); \ + zassert_equal(DT_MAP_ENTRY_CHILD_ADDRESS(n, p, i), 0); \ + zassert_equal(DT_MAP_ENTRY_CHILD_ADDRESS_BY_IDX(n, p, i, 1), 0); \ + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_LEN(n, p, i), 2); \ + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER(n, p, i), 5); \ + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(n, p, i, 1), 6); \ + zassert_equal(DT_MAP_ENTRY_PARENT_ADDRESS_LEN(n, p, i), 2); \ + zassert_equal(DT_MAP_ENTRY_PARENT_ADDRESS(n, p, i), 7); \ + zassert_equal(DT_MAP_ENTRY_PARENT_ADDRESS_BY_IDX(n, p, i, 1), 8); \ + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER_LEN(n, p, i), 2); \ + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER(n, p, i), 9); \ + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(n, p, i, 1), 0); \ + zassert_str_equal(STRINGIFY(DT_MAP_ENTRY_PARENT_BY_IDX(n, p, i)), \ + "DT_N_S_interrupt_map_test_S_controller_1_1"); + +#define INTERRUPT_NEXUS_CHECK_2(n, p, i, ...) \ + zassert_equal(DT_MAP_ENTRY_CHILD_ADDRESS_LEN(n, p, i), 2); \ + zassert_equal(DT_MAP_ENTRY_CHILD_ADDRESS_BY_IDX(n, p, i, 0), 0); \ + zassert_equal(DT_MAP_ENTRY_CHILD_ADDRESS_BY_IDX(n, p, i, 1), 1); \ + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_LEN(n, p, i), 2); \ + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(n, p, i, 0), 9); \ + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(n, p, i, 1), 8); \ + zassert_equal(DT_MAP_ENTRY_PARENT_ADDRESS_LEN(n, p, i), 1); \ + zassert_equal(DT_MAP_ENTRY_PARENT_ADDRESS_BY_IDX(n, p, i, 0), 7); \ + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER_LEN(n, p, i), 1); \ + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(n, p, i, 0), 6); \ + zassert_str_equal(STRINGIFY(DT_MAP_ENTRY_PARENT_BY_IDX(n, p, i)), \ + "DT_N_S_interrupt_map_test_S_controller_0_0"); + +#define INTERRUPT_NEXUS_CHECK_3(n, p, i, ...) \ + zassert_equal(DT_MAP_ENTRY_CHILD_ADDRESS_LEN(n, p, i), 2); \ + zassert_equal(DT_MAP_ENTRY_CHILD_ADDRESS_BY_IDX(n, p, i, 0), 0); \ + zassert_equal(DT_MAP_ENTRY_CHILD_ADDRESS_BY_IDX(n, p, i, 1), 1); \ + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_LEN(n, p, i), 2); \ + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(n, p, i, 0), 5); \ + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(n, p, i, 1), 4); \ + zassert_equal(DT_MAP_ENTRY_PARENT_ADDRESS_LEN(n, p, i), 2); \ + zassert_equal(DT_MAP_ENTRY_PARENT_ADDRESS_BY_IDX(n, p, i, 0), 3); \ + zassert_equal(DT_MAP_ENTRY_PARENT_ADDRESS_BY_IDX(n, p, i, 1), 2); \ + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER_LEN(n, p, i), 2); \ + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(n, p, i, 0), 1); \ + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(n, p, i, 1), 0); \ + zassert_str_equal(STRINGIFY(DT_MAP_ENTRY_PARENT_BY_IDX(n, p, i)), \ + "DT_N_S_interrupt_map_test_S_controller_1_1"); + +#define INTERRUPT_NEXUS_CHECK(n, p, i) UTIL_CAT(INTERRUPT_NEXUS_CHECK_, i)(n, p, i) +#define INTERRUPT_NEXUS_CHECK_VARGS(n, p, i, ...) UTIL_CAT(INTERRUPT_NEXUS_CHECK_, i)(n, p, i) + +#define EMPTY_MAP_SHOULD_NOT_RUN(...) zassert_unreachable("map should be empty") + +ZTEST(devicetree_api, test_map) +{ + zassert_equal(DT_PROP_LEN(TEST_GPIO_CONNECTOR, gpio_map_mask), 2); + zassert_equal(DT_PROP_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map_mask, 0), 0xffffffff); + zassert_equal(DT_PROP_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map_mask, 1), 0xffffffc0); + zassert_equal(DT_PROP_LEN(TEST_GPIO_CONNECTOR, gpio_map_pass_thru), 2); + zassert_equal(DT_PROP_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map_pass_thru, 0), 0x0); + zassert_equal(DT_PROP_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map_pass_thru, 1), 0x3f); + + zassert_equal(DT_PROP_LEN(TEST_GPIO_CONNECTOR, gpio_map), 2); + + zassert_equal(DT_MAP_ENTRY_CHILD_ADDRESS_LEN(TEST_GPIO_CONNECTOR, gpio_map, 0), 0); + zassert_equal(DT_MAP_ENTRY_PARENT_ADDRESS_LEN(TEST_GPIO_CONNECTOR, gpio_map, 0), 0); + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_LEN(TEST_GPIO_CONNECTOR, gpio_map, 0), 2); + zassert_equal(DT_MAP_ENTRY_HAS_CHILD_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 0, 1), + 1); + zassert_equal(DT_MAP_ENTRY_HAS_CHILD_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 0, 2), + 0); + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 0, 0), 1); + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 0, 1), 2); + + zassert_str_equal(STRINGIFY(DT_MAP_ENTRY_PARENT_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 0)), + "DT_N_S_gpio_map_test_S_parent"); + + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER_LEN(TEST_GPIO_CONNECTOR, gpio_map, 1), 1); + zassert_equal(DT_MAP_ENTRY_HAS_PARENT_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 1, 0), + 1); + zassert_equal(DT_MAP_ENTRY_HAS_PARENT_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 1, 1), + 0); + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 0, 0), 3); + + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_LEN(TEST_GPIO_CONNECTOR, gpio_map, 1), 2); + zassert_equal(DT_MAP_ENTRY_HAS_CHILD_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 1, 1), + 1); + zassert_equal(DT_MAP_ENTRY_HAS_CHILD_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 1, 2), + 0); + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 1, 0), 4); + zassert_equal(DT_MAP_ENTRY_CHILD_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 1, 1), 5); + + zassert_str_equal(STRINGIFY(DT_MAP_ENTRY_PARENT_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 1)), + "DT_N_S_gpio_map_test_S_parent"); + + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER_LEN(TEST_GPIO_CONNECTOR, gpio_map, 0), 1); + zassert_equal(DT_MAP_ENTRY_HAS_PARENT_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 0, 0), + 1); + zassert_equal(DT_MAP_ENTRY_HAS_PARENT_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 0, 1), + 0); + zassert_equal(DT_MAP_ENTRY_PARENT_SPECIFIER_BY_IDX(TEST_GPIO_CONNECTOR, gpio_map, 1, 0), 6); + + zassert_true(DT_NODE_HAS_MAP(TEST_INTERRUPT_NEXUS_EMPTY, interrupt_map), ""); + zassert_equal(DT_MAP_LEN(TEST_INTERRUPT_NEXUS_EMPTY, interrupt_map), 0); + zassert_equal(DT_MAP_HAS_ENTRY(TEST_INTERRUPT_NEXUS_EMPTY, interrupt_map), 0); + + DT_FOREACH_MAP_ENTRY(TEST_INTERRUPT_NEXUS_EMPTY, interrupt_map, EMPTY_MAP_SHOULD_NOT_RUN); + DT_FOREACH_MAP_ENTRY_SEP(TEST_INTERRUPT_NEXUS_EMPTY, interrupt_map, + EMPTY_MAP_SHOULD_NOT_RUN, ()); + DT_FOREACH_MAP_ENTRY_VARGS(TEST_INTERRUPT_NEXUS_EMPTY, interrupt_map, + EMPTY_MAP_SHOULD_NOT_RUN, 1234); + DT_FOREACH_MAP_ENTRY_SEP_VARGS(TEST_INTERRUPT_NEXUS_EMPTY, interrupt_map, + EMPTY_MAP_SHOULD_NOT_RUN, (), 1234); + + zassert_equal(DT_MAP_HAS_ENTRY_BY_IDX(TEST_INTERRUPT_NEXUS, interrupt_map, 3), 1); + zassert_equal(DT_MAP_HAS_ENTRY_BY_IDX(TEST_INTERRUPT_NEXUS, interrupt_map, 4), 0); + DT_FOREACH_MAP_ENTRY(TEST_INTERRUPT_NEXUS, interrupt_map, INTERRUPT_NEXUS_CHECK) + DT_FOREACH_MAP_ENTRY_SEP(TEST_INTERRUPT_NEXUS, interrupt_map, INTERRUPT_NEXUS_CHECK, ()) + DT_FOREACH_MAP_ENTRY_VARGS(TEST_INTERRUPT_NEXUS, interrupt_map, INTERRUPT_NEXUS_CHECK_VARGS, + 9999); + DT_FOREACH_MAP_ENTRY_SEP_VARGS(TEST_INTERRUPT_NEXUS, interrupt_map, + INTERRUPT_NEXUS_CHECK_VARGS, (), 9999); +} + ZTEST_SUITE(devicetree_api, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/lib/devicetree/api/testcase.yaml b/tests/lib/devicetree/api/testcase.yaml index ded886833ac87..2759a047ab7d6 100644 --- a/tests/lib/devicetree/api/testcase.yaml +++ b/tests/lib/devicetree/api/testcase.yaml @@ -5,6 +5,7 @@ tests: # will mostly likely be the fastest. platform_allow: - native_sim + - native_sim/native/64 - qemu_x86 - qemu_x86_64 - qemu_cortex_m3