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