osi_compiler.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /* Copyright (C) 2018 RDA Technologies Limited and/or its affiliates("RDA").
  2. * All rights reserved.
  3. *
  4. * This software is supplied "AS IS" without any warranties.
  5. * RDA assumes no responsibility or liability for the use of the software,
  6. * conveys no license or title under any patent, copyright, or mask work
  7. * right to the product. RDA reserves the right to make changes in the
  8. * software without notification. RDA also make no representation or
  9. * warranty that such application will be suitable for the specified use
  10. * without further testing or modification.
  11. */
  12. #ifndef _OSI_COMPILER_H_
  13. #define _OSI_COMPILER_H_
  14. #include <stdint.h>
  15. #include <stdbool.h>
  16. #include <stddef.h>
  17. // macros for alias, either strong or weak. It can't work with LTO.
  18. #define OSI_STRONG_ALIAS(alias, sym) __asm(".global " #alias "\n" #alias " = " #sym)
  19. #define OSI_WEAK_ALIAS(alias, sym) __asm(".weak " #alias "\n" #alias " = " #sym)
  20. // macros for alias, either strong or weak,
  21. #define OSI_DECL_STRONG_ALIAS(oldname, newfunc) newfunc __attribute__((alias(#oldname)))
  22. #define OSI_DECL_WEAK_ALIAS(oldname, newfunc) newfunc __attribute__((weak, alias(#oldname)))
  23. #define OSI_STRINGFY(s) _OSI_STRINGFY(s)
  24. #define _OSI_STRINGFY(s) #s
  25. // macro for nop instruction
  26. #define OSI_NOP asm volatile("nop")
  27. // macro for compiler memory access barrier
  28. #define OSI_BARRIER() asm volatile("" :: \
  29. : "memory")
  30. // macro for alignment attribute
  31. #define OSI_CACHE_LINE_ALIGNED __attribute__((aligned(CONFIG_CACHE_LINE_SIZE)))
  32. #define OSI_ALIGNED(n) __attribute__((aligned(n)))
  33. #define OSI_ATTRIBUTE_ISR __attribute__((interrupt))
  34. #define OSI_ATTRIBUTE_USED __attribute__((used))
  35. #define OSI_ATTRIBUTE_OPTIMIZE(n) __attribute__((optimize(n)))
  36. // macros for "known" sections
  37. #define OSI_SECTION(sect) __attribute__((section(#sect)))
  38. // macros for attributes
  39. #define OSI_WEAK __attribute__((weak))
  40. #define OSI_USED __attribute__((used))
  41. #define OSI_UNUSED __attribute__((unused))
  42. #define OSI_NO_RETURN __attribute__((__noreturn__))
  43. #define OSI_NO_INLINE __attribute__((noinline))
  44. #define OSI_FORCE_INLINE __attribute__((always_inline)) inline
  45. #if __mips__
  46. #define OSI_NO_MIPS16 __attribute__((nomips16))
  47. #define OSI_NAKED
  48. #endif
  49. #if __arm__
  50. #define OSI_NO_MIPS16
  51. #define OSI_NAKED __attribute__((naked))
  52. #define OSI_DMB() asm volatile("dmb 0xf" :: \
  53. : "memory")
  54. #define OSI_DSB() asm volatile("dsb 0xf" :: \
  55. : "memory")
  56. #define OSI_ISB() asm volatile("isb 0xf" :: \
  57. : "memory")
  58. #endif
  59. // macro maybe helpful for compiler optimization
  60. #define OSI_LIKELY(x) __builtin_expect(!!(x), 1)
  61. #define OSI_UNLIKELY(x) __builtin_expect(!!(x), 0)
  62. // macros for MIPS KSEG0/1
  63. #if __mips__
  64. #define OSI_KSEG0(addr) (((unsigned long)(addr)&0x1fffffff) | 0x80000000)
  65. #define OSI_KSEG1(addr) (((unsigned long)(addr)&0x1fffffff) | 0xa0000000)
  66. #define OSI_IS_KSEG0(addr) (((unsigned long)(addr)&0xe0000000) == 0x80000000)
  67. #define OSI_IS_KSEG1(addr) (((unsigned long)(addr)&0xe0000000) == 0xa0000000)
  68. #define OSI_KSEG01_PHY_ADDR(addr) ((unsigned long)(addr)&0x0FFFFFFF)
  69. #endif
  70. typedef struct
  71. {
  72. uint32_t data[8 / 4];
  73. } osiBits64_t, osiBytes8_t;
  74. typedef struct
  75. {
  76. uint32_t data[16 / 4];
  77. } osiBits128_t, osiBytes16_t;
  78. typedef struct
  79. {
  80. uint32_t data[32 / 4];
  81. } osiBits256_t, osiBytes32_t;
  82. typedef struct
  83. {
  84. uint32_t data[64 / 4];
  85. } osiBits512_t, osiBytes64_t;
  86. typedef struct
  87. {
  88. uint32_t data[80 / 4];
  89. } osiBits640_t, osiBytes80_t;
  90. typedef struct
  91. {
  92. uint32_t data[128 / 4];
  93. } osiBits1024_t, osiBytes128_t;
  94. typedef struct
  95. {
  96. uint32_t data[160 / 4];
  97. } osiBits1280_t, osiBytes160_t;
  98. typedef struct
  99. {
  100. uint32_t data[256 / 4];
  101. } osiBits2048_t, osiBytes256_t;
  102. typedef struct
  103. {
  104. uint32_t data[384 / 4];
  105. } osiBits3072_t, osiBytes384_t;
  106. typedef struct
  107. {
  108. uint32_t data[512 / 4];
  109. } osiBits4096_t, osiBytes512_t;
  110. /**
  111. * \brief tiny helper for buffer pointer and size
  112. */
  113. typedef struct
  114. {
  115. uintptr_t ptr; ///< buffer pointer
  116. unsigned size; ///< buffer size
  117. } osiBuffer_t;
  118. /**
  119. * \brief contiguous buffer, with size as first word
  120. */
  121. typedef struct
  122. {
  123. uint32_t size; ///< size the following data
  124. uint32_t data[0]; ///< data
  125. } osiBufSize32_t;
  126. /**
  127. * \brief contiguous buffer, with size as first short
  128. */
  129. typedef struct
  130. {
  131. uint16_t size; ///< size the following data
  132. uint16_t data[0]; ///< data
  133. } osiBufSize16_t;
  134. /**
  135. * \brief contiguous buffer, with size as first byte
  136. */
  137. typedef struct
  138. {
  139. uint8_t size; ///< size the following data
  140. uint8_t data[0]; ///< data
  141. } osiBufSize8_t;
  142. /**
  143. * data structure to define an unsigned integer range
  144. */
  145. typedef struct
  146. {
  147. uint32_t minval; ///< minimal value
  148. uint32_t maxval; ///< maximum value
  149. } osiUintRange_t;
  150. /**
  151. * data structure to define a signed integer range
  152. */
  153. typedef struct
  154. {
  155. int minval; ///< minimal value
  156. int maxval; ///< maximum value
  157. } osiIntRange_t;
  158. /**
  159. * data structure to define a unsigned 64bits integer range
  160. */
  161. typedef struct
  162. {
  163. uint64_t minval; ///< minimal value
  164. uint64_t maxval; ///< maximum value
  165. } osiUint64Range_t;
  166. /**
  167. * data structure to define a signed 64bits integer range
  168. */
  169. typedef struct
  170. {
  171. int64_t minval; ///< minimal value
  172. int64_t maxval; ///< maximum value
  173. } osiInt64Range_t;
  174. // do { ... } while (0) is common trick to avoid if/else error
  175. #define OSI_DO_WHILE0(expr) \
  176. do \
  177. { \
  178. expr \
  179. } while (0)
  180. // just a dead loop
  181. #define OSI_DEAD_LOOP OSI_DO_WHILE0(for (;;);)
  182. // Busy loop wait until condition is true
  183. #define OSI_LOOP_WAIT(cond) OSI_DO_WHILE0(while (!(cond));)
  184. // Busy loop wait util condition is true. When polling peripherals, it is
  185. // needed to avoid read peripheral registers without delay, especially
  186. // when the peripheral is connected to a slow bus. This may cause the bus
  187. // is busy to react CPU register read, and other operations are affected.
  188. #define OSI_POLL_WAIT(cond) OSI_DO_WHILE0(while (!(cond)) { OSI_NOP; OSI_NOP; OSI_NOP; OSI_NOP; })
  189. // Loop wait. Return true if cont_true is meet, return false if cond_false is meet.
  190. #define OSI_LOOP_WAIT_IF(cond_true, cond_false) \
  191. ({ \
  192. bool _waited; \
  193. for (;;) \
  194. { \
  195. if (cond_true) \
  196. { \
  197. _waited = true; \
  198. break; \
  199. } \
  200. if (cond_false) \
  201. { \
  202. _waited = false; \
  203. break; \
  204. } \
  205. } \
  206. _waited; \
  207. })
  208. // Loop wait with timeout
  209. #define OSI_LOOP_WAIT_TIMEOUT_US(cond, us) \
  210. ({ \
  211. bool _waited = false; \
  212. unsigned _us = (us); \
  213. osiElapsedTimer_t _timeout; \
  214. osiElapsedTimerStart(&_timeout); \
  215. do \
  216. { \
  217. if (cond) \
  218. { \
  219. _waited = true; \
  220. break; \
  221. } \
  222. } while (osiElapsedTimeUS(&_timeout) <= _us); \
  223. _waited; \
  224. })
  225. // Loop wait with timeout, also post will be executed for each loop
  226. #define OSI_LOOP_WAIT_POST_TIMEOUT_US(cond, us, post) \
  227. ({ \
  228. bool _waited = false; \
  229. unsigned _us = (us); \
  230. osiElapsedTimer_t _timeout; \
  231. osiElapsedTimerStart(&_timeout); \
  232. for (;;) \
  233. { \
  234. if (cond) \
  235. { \
  236. _waited = true; \
  237. break; \
  238. } \
  239. if (osiElapsedTimeUS(&_timeout) > _us) \
  240. { \
  241. _waited = false; \
  242. break; \
  243. } \
  244. (void)(post); \
  245. } \
  246. _waited; \
  247. })
  248. // macro for fourcc tag
  249. #define OSI_MAKE_TAG(a, b, c, d) ((unsigned)(a) | ((unsigned)(b) << 8) | ((unsigned)(c) << 16) | ((unsigned)(d) << 24))
  250. #define OSI_TAG_EMPTY OSI_MAKE_TAG(' ', ' ', ' ', ' ')
  251. // macro for array dimension
  252. #define OSI_ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
  253. // macros for 2^n, and 2^n alignment
  254. #define OSI_IS_POW2(v) (((v) & ((v)-1)) == 0)
  255. #define OSI_IS_ALIGNED(v, n) (((unsigned long)(v) & ((n)-1)) == 0)
  256. #define OSI_ALIGN_UP(v, n) (((unsigned long)(v) + (n)-1) & ~((n)-1))
  257. #define OSI_ALIGN_DOWN(v, n) ((unsigned long)(v) & ~((n)-1))
  258. #define OSI_DIV_ROUND(m, n) (((m) + ((n) >> 1)) / (n))
  259. #define OSI_DIV_ROUND_UP(n, m) (((n) + (m)-1) / (m))
  260. // macro for compare two chars ignoring case
  261. #define OSI_CHAR_CASE_EQU(a, b) (((a) | 0x20) == ((b) | 0x20))
  262. // macro to increase the pointer, and return the original pointer
  263. #define OSI_PTR_INCR_POST(p, n) ({uintptr_t _orig = (p); (p) += (n); _orig; })
  264. // pointer (signed) diff, either can be any pointer type
  265. #define OSI_PTR_DIFF(a, b) ((intptr_t)(a) - (intptr_t)(b))
  266. // Macro for variadic argument count
  267. #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
  268. #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)
  269. // macros for declaration and definition
  270. #define OSI_DEF_CONST_VAR(decl, ...) static const decl = __VA_ARGS__
  271. #define OSI_DEF_GLOBAL_VAR(decl, ...) decl = __VA_ARGS__
  272. #define OSI_DECL_GLOBAL_VAR(decl, ...) extern decl
  273. // macros to convert CPU endian to little/big endian
  274. #define OSI_TO_LE16(v) (v)
  275. #define OSI_TO_LE32(v) (v)
  276. #define OSI_TO_BE16(v) __builtin_bswap16(v)
  277. #define OSI_TO_BE32(v) __builtin_bswap32(v)
  278. // macros to convert CPU endian from little/big endian
  279. #define OSI_FROM_LE16(v) (v)
  280. #define OSI_FROM_LE32(v) (v)
  281. #define OSI_FROM_BE16(v) __builtin_bswap16(v)
  282. #define OSI_FROM_BE32(v) __builtin_bswap32(v)
  283. // macro for 32bits/16bits/8bits register read and write
  284. #define OSI_REG32_WRITE(address, value) *(volatile uint32_t *)(address) = (value)
  285. #define OSI_REG32_READ(address) (*(volatile uint32_t *)(address))
  286. #define OSI_REG16_WRITE(address, value) *(volatile uint16_t *)(address) = (value)
  287. #define OSI_REG16_READ(address) (*(volatile uint16_t *)(address))
  288. #define OSI_REG8_WRITE(address, value) *(volatile uint8_t *)(address) = (value)
  289. #define OSI_REG8_READ(address) (*(volatile uint8_t *)(address))
  290. // a*b/c, b and c are positive constants
  291. // It can avoid 64bits division, and avoid 32bits overflow of (a*b)
  292. #define OSI_SMULDIV(a, b, c) (((int)(a) * (((b)*0x100000000ULL) / (c))) >> 32)
  293. #define OSI_UMULDIV(a, b, c) (((unsigned)(a) * (((b)*0x100000000ULL) / (c))) >> 32)
  294. // macros for easier writing
  295. #define OSI_KB(n) ((unsigned)(n) * (unsigned)(1024))
  296. #define OSI_MB(n) ((unsigned)(n) * (unsigned)(1024 * 1024))
  297. #define OSI_GB(n) ((unsigned)(n) * (unsigned)(1024 * 1024 * 1024))
  298. #define OSI_MHZ(n) ((unsigned)(n) * (unsigned)(1000 * 1000))
  299. // macros for min, max. the variable will be accessed only once
  300. #define OSI_MIN(type, a, b) ({ type _a = (type)(a); type _b = (type)(b); _a < _b? _a : _b; })
  301. #define OSI_MAX(type, a, b) ({ type _a = (type)(a); type _b = (type)(b); _a > _b? _a : _b; })
  302. #define OSI_ABS(type, a) ({ type _a = (type)(a); _a > 0? _a : -_a; })
  303. // Range [start, end) and region [start, start+size) macros
  304. #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; })
  305. #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; })
  306. #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; })
  307. #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; })
  308. // abs(a - b) <= threshold, a little trick to avoid abs calculation or if-else
  309. #define OSI_ABS_DELTA_LE(a, b, threshold) ({ unsigned _t = (threshold); (unsigned)((a) - (b) + _t) <= 2 * _t; })
  310. // macro to swap 2 variables
  311. #define OSI_SWAP(type, a, b) ({ type _t = (a); (a) = (b); (b) = _t; })
  312. // macro for offsetof and container_of
  313. #define OSI_OFFSETOF(type, member) __builtin_offsetof(type, member)
  314. #define OSI_CONTAINER_OF(ptr, type, member) ((type *)((char *)(ptr)-OSI_OFFSETOF(type, member)))
  315. // assert not enabled by default, and shall not configured globally
  316. #if defined(OSI_LOCAL_DEBUG_ASSERT_ENABLED) && !defined(OSI_DEBUG_ASSERT_DISABLED)
  317. #define OSI_DEBUG_ASSERT(expr) OSI_DO_WHILE0(if (!(expr)) osiPanic();)
  318. #else
  319. #define OSI_DEBUG_ASSERT(expr)
  320. #endif
  321. #ifdef __cplusplus
  322. #define OSI_EXTERN_C extern "C"
  323. #define OSI_EXTERN_C_BEGIN extern "C" {
  324. #define OSI_EXTERN_C_END }
  325. #else
  326. #define OSI_EXTERN_C
  327. #define OSI_EXTERN_C_BEGIN
  328. #define OSI_EXTERN_C_END
  329. #endif
  330. #include "osi_section.h"
  331. #endif