1 /***************************************************************************//**
2 * @file
3 * @brief General purpose utilities.
4 *******************************************************************************
5 * # License
6 * <b>Copyright 2021 Silicon Laboratories Inc. www.silabs.com</b>
7 *******************************************************************************
8 *
9 * SPDX-License-Identifier: Zlib
10 *
11 * The licensor of this software is Silicon Laboratories Inc.
12 *
13 * This software is provided 'as-is', without any express or implied
14 * warranty. In no event will the authors be held liable for any damages
15 * arising from the use of this software.
16 *
17 * Permission is granted to anyone to use this software for any purpose,
18 * including commercial applications, and to alter it and redistribute it
19 * freely, subject to the following restrictions:
20 *
21 * 1. The origin of this software must not be misrepresented; you must not
22 * claim that you wrote the original software. If you use this software
23 * in a product, an acknowledgment in the product documentation would be
24 * appreciated but is not required.
25 * 2. Altered source versions must be plainly marked as such, and must not be
26 * misrepresented as being the original software.
27 * 3. This notice may not be removed or altered from any source distribution.
28 *
29 ******************************************************************************/
30
31 #ifndef SL_COMMON_H
32 #define SL_COMMON_H
33
34 #include <stdint.h>
35 #include <stdbool.h>
36 #include "sl_assert.h"
37
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41
42 #if !defined(__STATIC_INLINE)
43 #if !defined(__unix__) && defined(__arm__)
44 /* Compiler agnostic definitions */
45 #include "cmsis_compiler.h"
46 #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
47 #define __STATIC_INLINE static inline
48 #else
49 #warning Please provide a macro for your compiler and architecture
50 #define __STATIC_INLINE static
51 #endif
52 #endif
53
54 /***************************************************************************//**
55 * @addtogroup common COMMON - Common Utilities
56 * @brief General purpose utilities and cross-compiler support
57 * @details
58 * This SDK supports the following compilers/IDEs:
59 * @li Simplicity Studio
60 * @li IAR Embedded Workbench
61 * @li Keil uVision IDE
62 * @li Plain armgcc
63 *
64 * Certain compiler features such as alignment is implemented differently in the tools.
65 * Therefore, macros such as @ref SL_ALIGN are provided to enable compiler independent
66 * code.
67 *
68 * @note RAM code macros are implemented in [RAMFUNC](/gecko-platform/<docspace-docleaf-version>/emlib-efm32g/).
69 * Cross-compiler RAM code support needs extended documentation and it is therefore
70 * implemented as a separate module.
71 *
72 * @{
73 ******************************************************************************/
74
75 /** @brief Macros to concatenate. */
76 #define _SL_CONCAT_2(first, second) first ## second
77 #define SL_CONCAT_PASTER_2(first, second) _SL_CONCAT_2(first, second) ///< sl concat paster 2.
78 #define _SL_CONCAT_3(first, second, third) first ## second ## third
79 #define SL_CONCAT_PASTER_3(first, second, third) _SL_CONCAT_3(first, second, third) ///< sl concat paster 3.
80 #define _SL_CONCAT_4(first, second, third, fourth) first ## second ## third ## fourth
81 #define SL_CONCAT_PASTER_4(first, second, third, fourth) _SL_CONCAT_4(first, second, third, fourth) ///< sl concat paster 4.
82
83 /** @brief Round n up to closest interval of i. */
84 #define SL_CEILING(n, i) ((((n) + (i) - 1U) / (i)) * (i))
85
86 /** @brief Round n down to closest interval of i. */
87 #define SL_FLOOR(n, i) ((n / i) * i)
88
89 /** @brief Stringify X */
90 #define STRINGIZE(X) #X
91
92 #if !defined(__GNUC__)
93 /* Not GCC compilers */
94
95 /** @brief Macros for giving the compiler hints about the likelihood of a branch. */
96 #define SL_BRANCH_LIKELY(x) (x)
97 #define SL_BRANCH_UNLIKELY(x) (x)
98
99 /** @brief Macro for getting minimum value. */
100 #define SL_MIN(a, b) ((a) < (b) ? (a) : (b))
101
102 /** @brief Macro for getting maximum value. */
103 #define SL_MAX(a, b) ((a) > (b) ? (a) : (b))
104
105 /** @brief Macros for handling packed structures. */
106 #define SL_PACK_START(X) _Pragma(STRINGIZE(pack(X)))
107 #define SL_PACK_END() _Pragma("pack()")
108 #define SL_ATTRIBUTE_PACKED
109
110 #if defined(__CC_ARM)
111 /** @brief MDK-ARM compiler: Macros for handling aligned structures. */
112 #define SL_ALIGN(X) __align(X)
113
114 /** MDK-ARM compiler: Macro for handling weak symbols. */
115 #define SL_WEAK __attribute__ ((weak))
116
117 /** MDK-ARM compiler: Macro for handling non-returning functions. */
118 #define SL_NORETURN __attribute__ ((noreturn))
119
120 /** MDK-ARM compiler: Macro for handling section placement */
121 #define SL_ATTRIBUTE_SECTION(X) __attribute__ ((section(X)))
122 #endif
123
124 #if defined(__ICCARM__)
125
126 #if (__VER__ >= 8000000)
127 /** @brief Obsoleted macro from version 8.00 and on . */
128 #define _STD_BEGIN
129 /** @brief Obsoleted macro from version 8.00 and on . */
130 #define _STD_END
131 #endif
132
133 /** @brief IAR Embedded Workbench: Macros for handling aligned structures. */
134 #define SL_ALIGN(X) _Pragma(STRINGIZE(data_alignment = X))
135
136 /** @brief IAR Embedded Workbench: Macros for handling weak symbols. */
137 #define SL_WEAK __weak
138
139 /** @brief IAR Embedded Workbench: Macro for handling non-returning functions. */
140 #define SL_NORETURN __noreturn
141
142 /* *INDENT-OFF* */
143 /** IAR Embedded Workbench: Macro for handling section placement */
144 #define SL_ATTRIBUTE_SECTION(X) @ X
145 #endif
146 /* *INDENT-ON* */
147
148 #define SL_ATTRIBUTE_ALIGN(X)
149
150 /** @brief Macro for notifying the compiler of an intended
151 * switch case fallthrough. */
152 #define SL_FALLTHROUGH
153
154 /** @brief A macro for notifying the compiler to ignore type limit check. */
155 #define SL_IGNORE_TYPE_LIMIT_BEGIN
156 #define SL_IGNORE_TYPE_LIMIT_END
157
158 #else // !defined(__GNUC__)
159 /* GCC compilers */
160
161 /** @brief Macros for giving the compiler hints about the likelihood of a branch. */
162 #define SL_BRANCH_LIKELY(x) __builtin_expect(!!(x), 1)
163 #define SL_BRANCH_UNLIKELY(x) __builtin_expect(!!(x), 0)
164
165 /** @brief A macro for getting the minimum value. No side-effects, a and b are evaluated one time only. */
166 #define SL_MIN(a, b) __extension__({ __typeof__(a)_a = (a); __typeof__(b)_b = (b); _a < _b ? _a : _b; })
167
168 /** @brief A macro for getting the maximum value. No side-effects, a and b are evaluated one time only. */
169 #define SL_MAX(a, b) __extension__({ __typeof__(a)_a = (a); __typeof__(b)_b = (b); _a > _b ? _a : _b; })
170
171 /** @brief A GCC style macro for handling packed structures. */
172 #define SL_ATTRIBUTE_PACKED __attribute__ ((packed))
173
174 /** @brief A macro for handling packed structures.
175 * @n Use this macro before the structure definition.
176 * @n X denotes the maximum alignment of structure members. X is not supported with
177 * GCC. GCC always uses 1 byte maximum alignment.
178 */
179 #define SL_PACK_START(x)
180
181 /** @brief A macro for handling packed structures.
182 * @n Use this macro after the structure definition.
183 * @n With GCC, add SL_ATTRIBUTE_PACKED after the closing curly braces of the structure
184 * definition.
185 */
186 #define SL_PACK_END()
187
188 /** @brief GCC style macro for aligning a variable. */
189 #define SL_ATTRIBUTE_ALIGN(X) __attribute__ ((aligned(X)))
190
191 /** @brief A macro for aligning a variable.
192 * @n Use this macro before the variable definition.
193 * @n X denotes the storage alignment value in bytes.
194 * @n To be GCC-compatible, use SL_ATTRIBUTE_ALIGN(X) before the semicolon on normal
195 * variables. Use SL_ATTRIBUTE_ALIGN(X) before the opening curly brace on structure variables.
196 */
197 #define SL_ALIGN(X)
198
199 /** @brief A macro for defining a weak symbol. */
200 #define SL_WEAK __attribute__ ((weak))
201
202 /** @brief A macro for handling non-returning functions. */
203 #define SL_NORETURN __attribute__ ((noreturn))
204
205 /** A macro for placing a variable in a section.
206 * @n Use this macro after the variable definition, before the equal sign or a semicolon.
207 * @n X denotes the section to place the variable in.
208 */
209 #define SL_ATTRIBUTE_SECTION(X) __attribute__ ((section(X)))
210
211 /** @brief A macro for notifying the compiler of an intended
212 * switch case fallthrough. */
213 #if __GNUC__ >= 7
214 #define SL_FALLTHROUGH __attribute__ ((fallthrough));
215 #else
216 #define SL_FALLTHROUGH
217 #endif
218
219 /** @brief A macro for notifying the compiler to ignore type limit check. */
220 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
221 #define SL_IGNORE_TYPE_LIMIT_BEGIN \
222 _Pragma("GCC diagnostic push") \
223 _Pragma("GCC diagnostic ignored \"-Wtype-limits\"")
224 #define SL_IGNORE_TYPE_LIMIT_END \
225 _Pragma("GCC diagnostic pop")
226 #else
227 #define SL_IGNORE_TYPE_LIMIT_BEGIN
228 #define SL_IGNORE_TYPE_LIMIT_END ///< A MACRO to notify the compiler, limit END.
229 #endif
230
231 #endif // !defined(__GNUC__)
232
233 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
234
235 /** @brief
236 * Macro for marking deprecated functions
237 *
238 * @details
239 * SL_DEPRECATED_API_SDK_<RELEASE> is used to mark functions that are
240 * deprecated and should not be used from a given version of the SDK.
241 * The accompanying SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_<RELEASE>
242 * define can be set to suppress warnings generated when using
243 * deprecated APIs.
244 */
245 #ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_3_0
246 #define SL_DEPRECATED_API_SDK_3_0
247 #else
248 #define SL_DEPRECATED_API_SDK_3_0 __attribute__ ((deprecated))
249 #endif
250
251 #ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_3_2
252 #define SL_DEPRECATED_API_SDK_3_2
253 #else
254 #define SL_DEPRECATED_API_SDK_3_2 __attribute__ ((deprecated))
255 #endif
256
257 #ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_3_3
258 #define SL_DEPRECATED_API_SDK_3_3
259 #else
260 #define SL_DEPRECATED_API_SDK_3_3 __attribute__ ((deprecated))
261 #endif
262
263 #ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_4_1
264 #define SL_DEPRECATED_API_SDK_4_1
265 #else
266 #define SL_DEPRECATED_API_SDK_4_1 __attribute__ ((deprecated))
267 #endif
268
269 #ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_4_2
270 #define SL_DEPRECATED_API_SDK_4_2
271 #else
272 #define SL_DEPRECATED_API_SDK_4_2 __attribute__ ((deprecated))
273 #endif
274
275 #ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_4_4
276 #define SL_DEPRECATED_API_SDK_4_4
277 #else
278 #define SL_DEPRECATED_API_SDK_4_4 __attribute__ ((deprecated))
279 #endif
280
281 #ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_2024_6
282 #define SL_DEPRECATED_API_SDK_2024_6
283 #else
284 #define SL_DEPRECATED_API_SDK_2024_6 __attribute__ ((deprecated))
285 #endif
286 /** @endcond */
287
288 /***************************************************************************//**
289 * @brief
290 * Count trailing number of zeros. Use CLZ instruction if available.
291 *
292 * @param[in] value
293 * Data value to check for number of trailing zero bits.
294 *
295 * @return
296 * A number of trailing zeros in value.
297 ******************************************************************************/
SL_CTZ(uint32_t value)298 __STATIC_INLINE uint32_t SL_CTZ(uint32_t value)
299 {
300 #if defined(__CORTEX_M) && (__CORTEX_M >= 3U)
301 return __CLZ(__RBIT(value));
302
303 #else
304 uint32_t zeros;
305 for (zeros = 0; (zeros < 32) && ((value & 0x1) == 0); zeros++, value >>= 1) {
306 ;
307 }
308 return zeros;
309 #endif
310 }
311
312 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
313 /* Deprecated function. New code should use @ref SL_CTZ. */
EFM32_CTZ(uint32_t value)314 __STATIC_INLINE uint32_t EFM32_CTZ(uint32_t value)
315 {
316 return SL_CTZ(value);
317 }
318 /** @endcond */
319
320 /***************************************************************************//**
321 * @brief
322 * Reverse the bits. Use the RBIT instruction if available, else process.
323 *
324 * @param[in] value
325 * Data value to reverse.
326 *
327 * @return
328 * A reversed value.
329 ******************************************************************************/
SL_RBIT(uint32_t value)330 __STATIC_INLINE uint32_t SL_RBIT(uint32_t value)
331 {
332 uint32_t result;
333
334 #if defined(__CORTEX_M) && (__CORTEX_M >= 0x03U)
335 result = __RBIT(value);
336 #else
337 int32_t s = 4 * 8 - 1;
338
339 result = value;
340 for (value >>= 1U; value != 0U; value >>= 1U) {
341 result <<= 1U;
342 result |= value & 1U;
343 s--;
344 }
345 result <<= s;
346 #endif
347 return result;
348 }
349
350 /***************************************************************************//**
351 * @brief
352 * Reverse the bits. Use the RBIT instruction if available, else process.
353 *
354 * @param[in] value
355 * 16-bit data value to reverse.
356 *
357 * @return
358 * A 16-bit reversed value.
359 ******************************************************************************/
SL_RBIT16(uint16_t value)360 __STATIC_INLINE uint16_t SL_RBIT16(uint16_t value)
361 {
362 return (uint16_t)(SL_RBIT(value) >> 16);
363 }
364
365 /***************************************************************************//**
366 * @brief
367 * Reverse the bits. Use the RBIT instruction if available, else process.
368 *
369 * @param[in] value
370 * 8-bit data value to reverse.
371 *
372 * @return
373 * A 8-bit reversed value.
374 ******************************************************************************/
SL_RBIT8(uint8_t value)375 __STATIC_INLINE uint8_t SL_RBIT8(uint8_t value)
376 {
377 return (uint8_t)(SL_RBIT(value) >> 24);
378 }
379
380 /***************************************************************************//**
381 * @brief
382 * Convert logarithm of 2 to division factor.
383 *
384 * @param[in] log2
385 * Logarithm of 2.
386 *
387 * @return
388 * Dividend.
389 ******************************************************************************/
SL_Log2ToDiv(uint32_t log2)390 __STATIC_INLINE uint32_t SL_Log2ToDiv(uint32_t log2)
391 {
392 EFM_ASSERT(log2 < 32U);
393 return 1UL << log2;
394 }
395
396 /***************************************************************************//**
397 * @brief
398 * Count the number of bits that are set to 1 in a 32-bit bitfield.
399 *
400 * @param[in] bitfield
401 * 32-bit bitfield.
402 *
403 * @return
404 * The number of bits that are set to 1 in the bitfield.
405 ******************************************************************************/
SL_POPCOUNT32(uint32_t bitfield)406 __STATIC_INLINE uint32_t SL_POPCOUNT32(uint32_t bitfield)
407 {
408 bitfield = bitfield - ((bitfield >> 1) & 0x55555555);
409 bitfield = (bitfield & 0x33333333) + ((bitfield >> 2) & 0x33333333);
410 bitfield = (bitfield + (bitfield >> 4)) & 0x0F0F0F0F;
411 return (bitfield * 0x01010101) >> 24;
412 }
413
414 /** @} (end addtogroup common) */
415
416 #ifdef __cplusplus
417 }
418 #endif
419
420 #endif /* SL_COMMON_H */
421