/*************************************************************************************** * 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 // 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