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 #if !defined(__STATIC_INLINE)
39 #if !defined(__unix__) && defined(__arm__)
40 /* Compiler agnostic definitions */
41 #include "cmsis_compiler.h"
42 #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
43 #define __STATIC_INLINE static inline
44 #else
45 #warning Please provide a macro for your compiler and architecture
46 #define __STATIC_INLINE static
47 #endif
48 #endif
49
50 #ifdef __cplusplus
51 extern "C" {
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 µVision 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](../../emlib/api).
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 Round n up to closest interval of i. */
76 #define SL_CEILING(n, i) ((((n) + (i) - 1U) / (i)) * (i))
77
78 /** @brief Round n down to closest interval of i. */
79 #define SL_FLOOR(n, i) ((n / i) * i)
80
81 /** @brief Stringify X */
82 #define STRINGIZE(X) #X
83
84 #if !defined(__GNUC__)
85 /* Not GCC compilers */
86
87 /** @brief Macro for getting minimum value. */
88 #define SL_MIN(a, b) ((a) < (b) ? (a) : (b))
89
90 /** @brief Macro for getting maximum value. */
91 #define SL_MAX(a, b) ((a) > (b) ? (a) : (b))
92
93 /** @brief Macros for handling packed structures. */
94 #define SL_PACK_START(X) _Pragma(STRINGIZE(pack(X)))
95 #define SL_PACK_END() _Pragma("pack()")
96 #define SL_ATTRIBUTE_PACKED
97
98 #if defined(__CC_ARM)
99 /** @brief MDK-ARM compiler: Macros for handling aligned structures. */
100 #define SL_ALIGN(X) __align(X)
101
102 /** MDK-ARM compiler: Macro for handling weak symbols. */
103 #define SL_WEAK __attribute__ ((weak))
104
105 /** MDK-ARM compiler: Macro for handling non-returning functions. */
106 #define SL_NORETURN __attribute__ ((noreturn))
107
108 /** MDK-ARM compiler: Macro for handling section placement */
109 #define SL_ATTRIBUTE_SECTION(X) __attribute__ ((section(X)))
110 #endif
111
112 #if defined(__ICCARM__)
113
114 #if (__VER__ >= 8000000)
115 /** @brief Obsoleted macro from version 8.00 and on . */
116 #define _STD_BEGIN
117 /** @brief Obsoleted macro from version 8.00 and on . */
118 #define _STD_END
119 #endif
120
121 /** @brief IAR Embedded Workbench: Macros for handling aligned structures. */
122 #define SL_ALIGN(X) _Pragma(STRINGIZE(data_alignment = X))
123
124 /** @brief IAR Embedded Workbench: Macros for handling weak symbols. */
125 #define SL_WEAK __weak
126
127 /** @brief IAR Embedded Workbench: Macro for handling non-returning functions. */
128 #define SL_NORETURN __noreturn
129
130 /* *INDENT-OFF* */
131 /** IAR Embedded Workbench: Macro for handling section placement */
132 #define SL_ATTRIBUTE_SECTION(X) @ X
133 #endif
134 /* *INDENT-ON* */
135
136 #define SL_ATTRIBUTE_ALIGN(X)
137
138 /** @brief Macro for notifying the compiler of an intended
139 * switch case fallthrough. */
140 #define SL_FALLTHROUGH
141
142 /** @brief A macro for notifying the compiler to ignore type limit check. */
143 #define SL_IGNORE_TYPE_LIMIT_BEGIN
144 #define SL_IGNORE_TYPE_LIMIT_END
145
146 #else // !defined(__GNUC__)
147 /* GCC compilers */
148
149 /** @brief A macro for getting the minimum value. No side-effects, a and b are evaluated one time only. */
150 #define SL_MIN(a, b) __extension__({ __typeof__(a)_a = (a); __typeof__(b)_b = (b); _a < _b ? _a : _b; })
151
152 /** @brief A macro for getting the maximum value. No side-effects, a and b are evaluated one time only. */
153 #define SL_MAX(a, b) __extension__({ __typeof__(a)_a = (a); __typeof__(b)_b = (b); _a > _b ? _a : _b; })
154
155 /** @brief A GCC style macro for handling packed structures. */
156 #define SL_ATTRIBUTE_PACKED __attribute__ ((packed))
157
158 /** @brief A macro for handling packed structures.
159 * @n Use this macro before the structure definition.
160 * @n X denotes the maximum alignment of structure members. X is not supported with
161 * GCC. GCC always uses 1 byte maximum alignment.
162 */
163 #define SL_PACK_START(x)
164
165 /** @brief A macro for handling packed structures.
166 * @n Use this macro after the structure definition.
167 * @n With GCC, add SL_ATTRIBUTE_PACKED after the closing curly braces of the structure
168 * definition.
169 */
170 #define SL_PACK_END()
171
172 /** @brief GCC style macro for aligning a variable. */
173 #define SL_ATTRIBUTE_ALIGN(X) __attribute__ ((aligned(X)))
174
175 /** @brief A macro for aligning a variable.
176 * @n Use this macro before the variable definition.
177 * @n X denotes the storage alignment value in bytes.
178 * @n To be GCC-compatible, use SL_ATTRIBUTE_ALIGN(X) before the semicolon on normal
179 * variables. Use SL_ATTRIBUTE_ALIGN(X) before the opening curly brace on structure variables.
180 */
181 #define SL_ALIGN(X)
182
183 /** @brief A macro for defining a weak symbol. */
184 #define SL_WEAK __attribute__ ((weak))
185
186 /** @brief A macro for handling non-returning functions. */
187 #define SL_NORETURN __attribute__ ((noreturn))
188
189 /** A macro for placing a variable in a section.
190 * @n Use this macro after the variable definition, before the equal sign or a semicolon.
191 * @n X denotes the section to place the variable in.
192 */
193 #define SL_ATTRIBUTE_SECTION(X) __attribute__ ((section(X)))
194
195 /** @brief A macro for notifying the compiler of an intended
196 * switch case fallthrough. */
197 #if __GNUC__ >= 7
198 #define SL_FALLTHROUGH __attribute__ ((fallthrough));
199 #else
200 #define SL_FALLTHROUGH
201 #endif
202
203 /** @brief A macro for notifying the compiler to ignore type limit check. */
204 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
205 #define SL_IGNORE_TYPE_LIMIT_BEGIN \
206 _Pragma("GCC diagnostic push") \
207 _Pragma("GCC diagnostic ignored \"-Wtype-limits\"")
208 #define SL_IGNORE_TYPE_LIMIT_END \
209 _Pragma("GCC diagnostic pop")
210 #else
211 #define SL_IGNORE_TYPE_LIMIT_BEGIN
212 #define SL_IGNORE_TYPE_LIMIT_END
213 #endif
214
215 #endif // !defined(__GNUC__)
216
217 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
218
219 /** @brief
220 * Macro for marking deprecated functions
221 *
222 * @details
223 * SL_DEPRECATED_API_SDK_<RELEASE> is used to mark functions that are
224 * deprecated and should not be used from a given version of the SDK.
225 * The accompanying SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_<RELEASE>
226 * define can be set to suppress warnings generated when using
227 * deprecated APIs.
228 */
229 #ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_3_0
230 #define SL_DEPRECATED_API_SDK_3_0
231 #else
232 #define SL_DEPRECATED_API_SDK_3_0 __attribute__ ((deprecated))
233 #endif
234
235 #ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_3_2
236 #define SL_DEPRECATED_API_SDK_3_2
237 #else
238 #define SL_DEPRECATED_API_SDK_3_2 __attribute__ ((deprecated))
239 #endif
240
241 #ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_3_3
242 #define SL_DEPRECATED_API_SDK_3_3
243 #else
244 #define SL_DEPRECATED_API_SDK_3_3 __attribute__ ((deprecated))
245 #endif
246
247 #ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_4_1
248 #define SL_DEPRECATED_API_SDK_4_1
249 #else
250 #define SL_DEPRECATED_API_SDK_4_1 __attribute__ ((deprecated))
251 #endif
252
253 #ifdef SL_SUPPRESS_DEPRECATION_WARNINGS_SDK_4_2
254 #define SL_DEPRECATED_API_SDK_4_2
255 #else
256 #define SL_DEPRECATED_API_SDK_4_2 __attribute__ ((deprecated))
257 #endif
258 /** @endcond */
259
260 /***************************************************************************//**
261 * @brief
262 * Count trailing number of zeros. Use CLZ instruction if available.
263 *
264 * @param[in] value
265 * Data value to check for number of trailing zero bits.
266 *
267 * @return
268 * A number of trailing zeros in value.
269 ******************************************************************************/
SL_CTZ(uint32_t value)270 __STATIC_INLINE uint32_t SL_CTZ(uint32_t value)
271 {
272 #if defined(__CORTEX_M) && (__CORTEX_M >= 3U)
273 return __CLZ(__RBIT(value));
274
275 #else
276 uint32_t zeros;
277 for (zeros = 0; (zeros < 32) && ((value & 0x1) == 0); zeros++, value >>= 1) {
278 ;
279 }
280 return zeros;
281 #endif
282 }
283
284 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
285 /* Deprecated function. New code should use @ref SL_CTZ. */
EFM32_CTZ(uint32_t value)286 __STATIC_INLINE uint32_t EFM32_CTZ(uint32_t value)
287 {
288 return SL_CTZ(value);
289 }
290 /** @endcond */
291
292 /***************************************************************************//**
293 * @brief
294 * Reverse the bits. Use the RBIT instruction if available, else process.
295 *
296 * @param[in] value
297 * Data value to reverse.
298 *
299 * @return
300 * A reversed value.
301 ******************************************************************************/
SL_RBIT(uint32_t value)302 __STATIC_INLINE uint32_t SL_RBIT(uint32_t value)
303 {
304 uint32_t result;
305
306 #if defined(__CORTEX_M) && (__CORTEX_M >= 0x03U)
307 result = __RBIT(value);
308 #else
309 int32_t s = 4 * 8 - 1;
310
311 result = value;
312 for (value >>= 1U; value != 0U; value >>= 1U) {
313 result <<= 1U;
314 result |= value & 1U;
315 s--;
316 }
317 result <<= s;
318 #endif
319 return result;
320 }
321
322 /***************************************************************************//**
323 * @brief
324 * Reverse the bits. Use the RBIT instruction if available, else process.
325 *
326 * @param[in] value
327 * 16-bit data value to reverse.
328 *
329 * @return
330 * A 16-bit reversed value.
331 ******************************************************************************/
SL_RBIT16(uint16_t value)332 __STATIC_INLINE uint16_t SL_RBIT16(uint16_t value)
333 {
334 return (uint16_t)(SL_RBIT(value) >> 16);
335 }
336
337 /***************************************************************************//**
338 * @brief
339 * Reverse the bits. Use the RBIT instruction if available, else process.
340 *
341 * @param[in] value
342 * 8-bit data value to reverse.
343 *
344 * @return
345 * A 8-bit reversed value.
346 ******************************************************************************/
SL_RBIT8(uint8_t value)347 __STATIC_INLINE uint8_t SL_RBIT8(uint8_t value)
348 {
349 return (uint8_t)(SL_RBIT(value) >> 24);
350 }
351
352 /***************************************************************************//**
353 * @brief
354 * Convert logarithm of 2 to division factor.
355 *
356 * @param[in] log2
357 * Logarithm of 2.
358 *
359 * @return
360 * Dividend.
361 ******************************************************************************/
SL_Log2ToDiv(uint32_t log2)362 __STATIC_INLINE uint32_t SL_Log2ToDiv(uint32_t log2)
363 {
364 EFM_ASSERT(log2 < 32U);
365 return 1UL << log2;
366 }
367
368 /** @} (end addtogroup common) */
369
370 #ifdef __cplusplus
371 }
372 #endif
373
374 #endif /* SL_COMMON_H */
375