/* Copyright (C) 2018 RDA Technologies Limited and/or its affiliates("RDA"). * All rights reserved. * * This software is supplied "AS IS" without any warranties. * RDA assumes no responsibility or liability for the use of the software, * conveys no license or title under any patent, copyright, or mask work * right to the product. RDA reserves the right to make changes in the * software without notification. RDA also make no representation or * warranty that such application will be suitable for the specified use * without further testing or modification. */ #ifndef _OSI_COMPILER_H_ #define _OSI_COMPILER_H_ #include #include #include // macros for alias, either strong or weak. It can't work with LTO. #define OSI_STRONG_ALIAS(alias, sym) __asm(".global " #alias "\n" #alias " = " #sym) #define OSI_WEAK_ALIAS(alias, sym) __asm(".weak " #alias "\n" #alias " = " #sym) // macros for alias, either strong or weak, #define OSI_DECL_STRONG_ALIAS(oldname, newfunc) newfunc __attribute__((alias(#oldname))) #define OSI_DECL_WEAK_ALIAS(oldname, newfunc) newfunc __attribute__((weak, alias(#oldname))) #define OSI_STRINGFY(s) _OSI_STRINGFY(s) #define _OSI_STRINGFY(s) #s // macro for nop instruction #define OSI_NOP asm volatile("nop") // macro for compiler memory access barrier #define OSI_BARRIER() asm volatile("" :: \ : "memory") // macro for alignment attribute #define OSI_CACHE_LINE_ALIGNED __attribute__((aligned(CONFIG_CACHE_LINE_SIZE))) #define OSI_ALIGNED(n) __attribute__((aligned(n))) #define OSI_ATTRIBUTE_ISR __attribute__((interrupt)) #define OSI_ATTRIBUTE_USED __attribute__((used)) #define OSI_ATTRIBUTE_OPTIMIZE(n) __attribute__((optimize(n))) // macros for "known" sections #define OSI_SECTION(sect) __attribute__((section(#sect))) // macros for attributes #define OSI_WEAK __attribute__((weak)) #define OSI_USED __attribute__((used)) #define OSI_UNUSED __attribute__((unused)) #define OSI_NO_RETURN __attribute__((__noreturn__)) #define OSI_NO_INLINE __attribute__((noinline)) #define OSI_FORCE_INLINE __attribute__((always_inline)) inline #if __mips__ #define OSI_NO_MIPS16 __attribute__((nomips16)) #define OSI_NAKED #endif #if __arm__ #define OSI_NO_MIPS16 #define OSI_NAKED __attribute__((naked)) #define OSI_DMB() asm volatile("dmb 0xf" :: \ : "memory") #define OSI_DSB() asm volatile("dsb 0xf" :: \ : "memory") #define OSI_ISB() asm volatile("isb 0xf" :: \ : "memory") #endif // macro maybe helpful for compiler optimization #define OSI_LIKELY(x) __builtin_expect(!!(x), 1) #define OSI_UNLIKELY(x) __builtin_expect(!!(x), 0) // macros for MIPS KSEG0/1 #if __mips__ #define OSI_KSEG0(addr) (((unsigned long)(addr)&0x1fffffff) | 0x80000000) #define OSI_KSEG1(addr) (((unsigned long)(addr)&0x1fffffff) | 0xa0000000) #define OSI_IS_KSEG0(addr) (((unsigned long)(addr)&0xe0000000) == 0x80000000) #define OSI_IS_KSEG1(addr) (((unsigned long)(addr)&0xe0000000) == 0xa0000000) #define OSI_KSEG01_PHY_ADDR(addr) ((unsigned long)(addr)&0x0FFFFFFF) #endif typedef struct { uint32_t data[8 / 4]; } osiBits64_t, osiBytes8_t; typedef struct { uint32_t data[16 / 4]; } osiBits128_t, osiBytes16_t; typedef struct { uint32_t data[32 / 4]; } osiBits256_t, osiBytes32_t; typedef struct { uint32_t data[64 / 4]; } osiBits512_t, osiBytes64_t; typedef struct { uint32_t data[80 / 4]; } osiBits640_t, osiBytes80_t; typedef struct { uint32_t data[128 / 4]; } osiBits1024_t, osiBytes128_t; typedef struct { uint32_t data[160 / 4]; } osiBits1280_t, osiBytes160_t; typedef struct { uint32_t data[256 / 4]; } osiBits2048_t, osiBytes256_t; typedef struct { uint32_t data[384 / 4]; } osiBits3072_t, osiBytes384_t; typedef struct { uint32_t data[512 / 4]; } osiBits4096_t, osiBytes512_t; /** * \brief tiny helper for buffer pointer and size */ typedef struct { uintptr_t ptr; ///< buffer pointer unsigned size; ///< buffer size } osiBuffer_t; /** * \brief contiguous buffer, with size as first word */ typedef struct { uint32_t size; ///< size the following data uint32_t data[0]; ///< data } osiBufSize32_t; /** * \brief contiguous buffer, with size as first short */ typedef struct { uint16_t size; ///< size the following data uint16_t data[0]; ///< data } osiBufSize16_t; /** * \brief contiguous buffer, with size as first byte */ typedef struct { uint8_t size; ///< size the following data uint8_t data[0]; ///< data } osiBufSize8_t; /** * data structure to define an unsigned integer range */ typedef struct { uint32_t minval; ///< minimal value uint32_t maxval; ///< maximum value } osiUintRange_t; /** * data structure to define a signed integer range */ typedef struct { int minval; ///< minimal value int maxval; ///< maximum value } osiIntRange_t; /** * data structure to define a unsigned 64bits integer range */ typedef struct { uint64_t minval; ///< minimal value uint64_t maxval; ///< maximum value } osiUint64Range_t; /** * data structure to define a signed 64bits integer range */ typedef struct { int64_t minval; ///< minimal value int64_t maxval; ///< maximum value } osiInt64Range_t; // do { ... } while (0) is common trick to avoid if/else error #define OSI_DO_WHILE0(expr) \ do \ { \ expr \ } while (0) // just a dead loop #define OSI_DEAD_LOOP OSI_DO_WHILE0(for (;;);) // Busy loop wait until condition is true #define OSI_LOOP_WAIT(cond) OSI_DO_WHILE0(while (!(cond));) // Busy loop wait util condition is true. When polling peripherals, it is // needed to avoid read peripheral registers without delay, especially // when the peripheral is connected to a slow bus. This may cause the bus // is busy to react CPU register read, and other operations are affected. #define OSI_POLL_WAIT(cond) OSI_DO_WHILE0(while (!(cond)) { OSI_NOP; OSI_NOP; OSI_NOP; OSI_NOP; }) // Loop wait. Return true if cont_true is meet, return false if cond_false is meet. #define OSI_LOOP_WAIT_IF(cond_true, cond_false) \ ({ \ bool _waited; \ for (;;) \ { \ if (cond_true) \ { \ _waited = true; \ break; \ } \ if (cond_false) \ { \ _waited = false; \ break; \ } \ } \ _waited; \ }) // Loop wait with timeout #define OSI_LOOP_WAIT_TIMEOUT_US(cond, us) \ ({ \ bool _waited = false; \ unsigned _us = (us); \ osiElapsedTimer_t _timeout; \ osiElapsedTimerStart(&_timeout); \ do \ { \ if (cond) \ { \ _waited = true; \ break; \ } \ } while (osiElapsedTimeUS(&_timeout) <= _us); \ _waited; \ }) // Loop wait with timeout, also post will be executed for each loop #define OSI_LOOP_WAIT_POST_TIMEOUT_US(cond, us, post) \ ({ \ bool _waited = false; \ unsigned _us = (us); \ osiElapsedTimer_t _timeout; \ osiElapsedTimerStart(&_timeout); \ for (;;) \ { \ if (cond) \ { \ _waited = true; \ break; \ } \ if (osiElapsedTimeUS(&_timeout) > _us) \ { \ _waited = false; \ break; \ } \ (void)(post); \ } \ _waited; \ }) // macro for fourcc tag #define OSI_MAKE_TAG(a, b, c, d) ((unsigned)(a) | ((unsigned)(b) << 8) | ((unsigned)(c) << 16) | ((unsigned)(d) << 24)) #define OSI_TAG_EMPTY OSI_MAKE_TAG(' ', ' ', ' ', ' ') // macro for array dimension #define OSI_ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) // macros for 2^n, and 2^n alignment #define OSI_IS_POW2(v) (((v) & ((v)-1)) == 0) #define OSI_IS_ALIGNED(v, n) (((unsigned long)(v) & ((n)-1)) == 0) #define OSI_ALIGN_UP(v, n) (((unsigned long)(v) + (n)-1) & ~((n)-1)) #define OSI_ALIGN_DOWN(v, n) ((unsigned long)(v) & ~((n)-1)) #define OSI_DIV_ROUND(m, n) (((m) + ((n) >> 1)) / (n)) #define OSI_DIV_ROUND_UP(n, m) (((n) + (m)-1) / (m)) // macro for compare two chars ignoring case #define OSI_CHAR_CASE_EQU(a, b) (((a) | 0x20) == ((b) | 0x20)) // macro to increase the pointer, and return the original pointer #define OSI_PTR_INCR_POST(p, n) ({uintptr_t _orig = (p); (p) += (n); _orig; }) // pointer (signed) diff, either can be any pointer type #define OSI_PTR_DIFF(a, b) ((intptr_t)(a) - (intptr_t)(b)) // Macro for variadic argument count #define OSI_VA_NARGS_IMPL(_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, N, ...) N #define OSI_VA_NARGS(...) OSI_VA_NARGS_IMPL(0, ##__VA_ARGS__, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) // macros for declaration and definition #define OSI_DEF_CONST_VAR(decl, ...) static const decl = __VA_ARGS__ #define OSI_DEF_GLOBAL_VAR(decl, ...) decl = __VA_ARGS__ #define OSI_DECL_GLOBAL_VAR(decl, ...) extern decl // macros to convert CPU endian to little/big endian #define OSI_TO_LE16(v) (v) #define OSI_TO_LE32(v) (v) #define OSI_TO_BE16(v) __builtin_bswap16(v) #define OSI_TO_BE32(v) __builtin_bswap32(v) // macros to convert CPU endian from little/big endian #define OSI_FROM_LE16(v) (v) #define OSI_FROM_LE32(v) (v) #define OSI_FROM_BE16(v) __builtin_bswap16(v) #define OSI_FROM_BE32(v) __builtin_bswap32(v) // macro for 32bits/16bits/8bits register read and write #define OSI_REG32_WRITE(address, value) *(volatile uint32_t *)(address) = (value) #define OSI_REG32_READ(address) (*(volatile uint32_t *)(address)) #define OSI_REG16_WRITE(address, value) *(volatile uint16_t *)(address) = (value) #define OSI_REG16_READ(address) (*(volatile uint16_t *)(address)) #define OSI_REG8_WRITE(address, value) *(volatile uint8_t *)(address) = (value) #define OSI_REG8_READ(address) (*(volatile uint8_t *)(address)) // a*b/c, b and c are positive constants // It can avoid 64bits division, and avoid 32bits overflow of (a*b) #define OSI_SMULDIV(a, b, c) (((int)(a) * (((b)*0x100000000ULL) / (c))) >> 32) #define OSI_UMULDIV(a, b, c) (((unsigned)(a) * (((b)*0x100000000ULL) / (c))) >> 32) // macros for easier writing #define OSI_KB(n) ((unsigned)(n) * (unsigned)(1024)) #define OSI_MB(n) ((unsigned)(n) * (unsigned)(1024 * 1024)) #define OSI_GB(n) ((unsigned)(n) * (unsigned)(1024 * 1024 * 1024)) #define OSI_MHZ(n) ((unsigned)(n) * (unsigned)(1000 * 1000)) // macros for min, max. the variable will be accessed only once #define OSI_MIN(type, a, b) ({ type _a = (type)(a); type _b = (type)(b); _a < _b? _a : _b; }) #define OSI_MAX(type, a, b) ({ type _a = (type)(a); type _b = (type)(b); _a > _b? _a : _b; }) #define OSI_ABS(type, a) ({ type _a = (type)(a); _a > 0? _a : -_a; }) // Range [start, end) and region [start, start+size) macros #define OSI_IS_IN_RANGE(type, a, start, end) ({type _a = (type)(a); type _start = (type)(start); type _end = (type)(end); _a >= _start && _a < _end; }) #define OSI_IS_IN_REGION(type, a, start, size) ({type _a = (type)(a); type _start = (type)(start); type _end = _start + (type)(size); _a >= _start && _a < _end; }) #define OSI_RANGE_INSIDE(type, start1, end1, start2, end2) ({type _s1 = (type)(start1), _e1 = (type)(end1), _s2 = (type)(start2), _e2 = (type)(end2); _s1 >= _s2 && _e1 <= _e2; }) #define OSI_REGION_INSIDE(type, start1, size1, start2, size2) ({type _s1 = (type)(start1), _e1 = _s1 + (type)(size1), _s2 = (type)(start2), _e2 = _s2 + (type)(size2); _s1 >= _s2 && _e1 <= _e2; }) // abs(a - b) <= threshold, a little trick to avoid abs calculation or if-else #define OSI_ABS_DELTA_LE(a, b, threshold) ({ unsigned _t = (threshold); (unsigned)((a) - (b) + _t) <= 2 * _t; }) // macro to swap 2 variables #define OSI_SWAP(type, a, b) ({ type _t = (a); (a) = (b); (b) = _t; }) // macro for offsetof and container_of #define OSI_OFFSETOF(type, member) __builtin_offsetof(type, member) #define OSI_CONTAINER_OF(ptr, type, member) ((type *)((char *)(ptr)-OSI_OFFSETOF(type, member))) // assert not enabled by default, and shall not configured globally #if defined(OSI_LOCAL_DEBUG_ASSERT_ENABLED) && !defined(OSI_DEBUG_ASSERT_DISABLED) #define OSI_DEBUG_ASSERT(expr) OSI_DO_WHILE0(if (!(expr)) osiPanic();) #else #define OSI_DEBUG_ASSERT(expr) #endif #ifdef __cplusplus #define OSI_EXTERN_C extern "C" #define OSI_EXTERN_C_BEGIN extern "C" { #define OSI_EXTERN_C_END } #else #define OSI_EXTERN_C #define OSI_EXTERN_C_BEGIN #define OSI_EXTERN_C_END #endif #include "osi_section.h" #endif