/*************************************************************************************** * Copyright (c) 2014-2022 Zihao Yu, Nanjing University * * NEMU is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * * See the Mulan PSL v2 for more details. ***************************************************************************************/ #ifndef __MACRO_H__ #define __MACRO_H__ #include // macro stringizing #define str_temp(x) #x #define str(x) str_temp(x) // strlen() for string constant #define STRLEN(CONST_STR) (sizeof(CONST_STR) - 1) // calculate the length of an array #define ARRLEN(arr) (int)(sizeof(arr) / sizeof(arr[0])) // macro concatenation #define concat_temp(x, y) x##y #define concat(x, y) concat_temp(x, y) #define concat3(x, y, z) concat(concat(x, y), z) #define concat4(x, y, z, w) concat3(concat(x, y), z, w) #define concat5(x, y, z, v, w) concat4(concat(x, y), z, v, w) // macro testing // See https://stackoverflow.com/questions/26099745/test-if-preprocessor-symbol-is-defined-inside-macro #define CHOOSE2nd(a, b, ...) b #define MUX_WITH_COMMA(contain_comma, a, b) CHOOSE2nd(contain_comma a, b) #define MUX_MACRO_PROPERTY(p, macro, a, b) \ MUX_WITH_COMMA(concat(p, macro), a, b) // define placeholders for some property #define __P_DEF_0 X, #define __P_DEF_1 X, #define __P_ONE_1 X, #define __P_ZERO_0 X, // define some selection functions based on the properties of BOOLEAN macro #define MUXDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, X, Y) #define MUXNDEF(macro, X, Y) MUX_MACRO_PROPERTY(__P_DEF_, macro, Y, X) #define MUXONE(macro, X, Y) MUX_MACRO_PROPERTY(__P_ONE_, macro, X, Y) #define MUXZERO(macro, X, Y) MUX_MACRO_PROPERTY(__P_ZERO_, macro, X, Y) // test if a boolean macro is defined #define ISDEF(macro) MUXDEF(macro, 1, 0) // test if a boolean macro is undefined #define ISNDEF(macro) MUXNDEF(macro, 1, 0) // test if a boolean macro is defined to 1 #define ISONE(macro) MUXONE(macro, 1, 0) // test if a boolean macro is defined to 0 #define ISZERO(macro) MUXZERO(macro, 1, 0) // test if a macro of ANY type is defined // NOTE1: it ONLY works inside a function, since it calls `strcmp()` // NOTE2: macros defined to themselves (#define A A) will get wrong results #define isdef(macro) (strcmp("" #macro, "" str(macro)) != 0) // simplification for conditional compilation #define __IGNORE(...) #define __KEEP(...) __VA_ARGS__ // keep the code if a boolean macro is defined #define IFDEF(macro, ...) MUXDEF(macro, __KEEP, __IGNORE)(__VA_ARGS__) // keep the code if a boolean macro is undefined #define IFNDEF(macro, ...) MUXNDEF(macro, __KEEP, __IGNORE)(__VA_ARGS__) // keep the code if a boolean macro is defined to 1 #define IFONE(macro, ...) MUXONE(macro, __KEEP, __IGNORE)(__VA_ARGS__) // keep the code if a boolean macro is defined to 0 #define IFZERO(macro, ...) MUXZERO(macro, __KEEP, __IGNORE)(__VA_ARGS__) // functional-programming-like macro (X-macro) // apply the function `f` to each element in the container `c` // NOTE1: `c` should be defined as a list like: // f(a0) f(a1) f(a2) ... // NOTE2: each element in the container can be a tuple #define MAP(c, f) c(f) #define BITMASK(bits) ((1ull << (bits)) - 1) #define BITS(x, hi, lo) \ (((x) >> (lo)) & BITMASK((hi) - (lo) + 1)) // similar to x[hi:lo] in verilog #define SEXT(x, len) \ ({ \ struct { \ int64_t n : len; \ } __x = {.n = x}; \ (uint64_t) __x.n; \ }) #define ROUNDUP(a, sz) ((((uintptr_t)a) + (sz)-1) & ~((sz)-1)) #define ROUNDDOWN(a, sz) ((((uintptr_t)a)) & ~((sz)-1)) #define PG_ALIGN __attribute((aligned(4096))) #define FAILED_GOTO(tag, exp) \ do { \ if ((exp)) \ goto tag; \ } while (0) #if !defined(likely) #define likely(cond) __builtin_expect(cond, 1) #define unlikely(cond) __builtin_expect(cond, 0) #endif #define __EXPORT __attribute__((visibility("default"))) // for AM IOE #define io_read(reg) \ ({ \ reg##_T __io_param; \ ioe_read(reg, &__io_param); \ __io_param; \ }) #define io_write(reg, ...) \ ({ \ reg##_T __io_param = (reg##_T){__VA_ARGS__}; \ ioe_write(reg, &__io_param); \ }) #endif