Arm-2D  
2D Image Processing Library for Cortex-M Processors
arm_2d_utils.h
1/*
2 * Copyright (C) 2010-2022 Arm Limited or its affiliates. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19/* ----------------------------------------------------------------------
20 * Project: Arm-2D Library
21 * Title: arm_2d_utils.h
22 * Description: Public header file for Arm-2D Library
23 *
24 * $Date: 18. July 2022
25 * $Revision: V.1.0.3
26 *
27 * -------------------------------------------------------------------- */
28
29#ifndef __ARM_2D_UTILS_H__
30#define __ARM_2D_UTILS_H__
31
32/*============================ INCLUDES ======================================*/
33
34#if defined(__clang__)
35# pragma clang diagnostic push
36# pragma clang diagnostic ignored "-Wunknown-warning-option"
37# pragma clang diagnostic ignored "-Wreserved-identifier"
38# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
39# pragma clang diagnostic ignored "-Wpadded"
40# pragma clang diagnostic ignored "-Wsign-conversion"
41# pragma clang diagnostic ignored "-Wimplicit-int-conversion"
42# pragma clang diagnostic ignored "-Wdollar-in-identifier-extension"
43# pragma clang diagnostic ignored "-Wundef"
44#elif defined(__IS_COMPILER_GCC__)
45# pragma GCC diagnostic push
46# pragma GCC diagnostic ignored "-Wpedantic"
47# pragma GCC diagnostic ignored "-Wstrict-aliasing"
48#endif
49
50#ifdef __ARM_2D_HAS_USER_HEADER__
51# include __ARM_2D_HAS_USER_HEADER__
52#endif
53
54/*! \note arm-2d relies on CMSIS 5.4.0 and above.
55 */
56#include "cmsis_compiler.h"
57
58#ifdef __cplusplus
59extern "C" {
60#endif
61
62/*!
63 * \addtogroup gKernel 1 Kernel
64 * @{
65 */
66
67/*============================ MACROS ========================================*/
68
69
70/*----------------------------------------------------------------------------*
71 * Environment Detection *
72 *----------------------------------------------------------------------------*/
73
74/* The macros to identify compilers */
75
76/*!
77 * \brief to detect IAR
78 */
79#undef __IS_COMPILER_IAR__
80#if defined(__IAR_SYSTEMS_ICC__)
81# define __IS_COMPILER_IAR__ 1
82#endif
83
84/*!
85 * \brief to detect arm compiler 5
86 *
87 */
88#undef __IS_COMPILER_ARM_COMPILER_5__
89#if ((__ARMCC_VERSION >= 5000000) && (__ARMCC_VERSION < 6000000))
90# define __IS_COMPILER_ARM_COMPILER_5__ 1
91#endif
92
93
94/*!
95 * \brief to detect arm compiler 6
96 *
97 */
98#undef __IS_COMPILER_ARM_COMPILER_6__
99#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
100# define __IS_COMPILER_ARM_COMPILER_6__ 1
101#endif
102
103/*!
104 * \brief to detect arm compilers
105 *
106 */
107#undef __IS_COMPILER_ARM_COMPILER__
108#if defined(__IS_COMPILER_ARM_COMPILER_5__) && __IS_COMPILER_ARM_COMPILER_5__ \
109|| defined(__IS_COMPILER_ARM_COMPILER_6__) && __IS_COMPILER_ARM_COMPILER_6__
110# define __IS_COMPILER_ARM_COMPILER__ 1
111#endif
112
113/*!
114 * \brief to detect clang (llvm)
115 *
116 */
117#undef __IS_COMPILER_LLVM__
118#if defined(__clang__) && !__IS_COMPILER_ARM_COMPILER_6__
119# define __IS_COMPILER_LLVM__ 1
120#else
121
122/*!
123 * \brief to detect gcc
124 *
125 */
126# undef __IS_COMPILER_GCC__
127# if defined(__GNUC__) && !( defined(__IS_COMPILER_ARM_COMPILER__) \
128 || defined(__IS_COMPILER_LLVM__) \
129 || defined(__IS_COMPILER_IAR__))
130# define __IS_COMPILER_GCC__ 1
131# endif
132
133#endif
134
135
136
137/*----------------------------------------------------------------------------*
138 * OOC and Private Protection *
139 *----------------------------------------------------------------------------*/
140/* minimal support for OOPC */
141#undef __implement_ex
142#undef __implement
143#undef implement
144#undef implement_ex
145#undef inherit
146#undef inherit_ex
147
148#define __implement_ex(__type, __name) \
149 union { \
150 __type __name; \
151 __type; \
152 }
153
154#define __inherit_ex(__type, __name) \
155 __type __name \
156
157#define __implement(__type) __implement_ex( __type, \
158 use_as__##__type)
159
160#define __inherit(__type) __inherit_ex(__type,use_as__##__type)
161
162#define implement(__type) __implement(__type)
163#define implement_ex(__type, __name) __implement_ex(__type, __name)
164
165#define inherit(__type) __inherit(__type)
166#define inherit_ex(__type, __name) __inherit_ex(__type, __name)
167
168
169/*----------------------------------------------------------------------------*
170 * Misc *
171 *----------------------------------------------------------------------------*/
172
173#ifndef ARM_2D_UNUSED
174# define ARM_2D_UNUSED(__VAR) (void)(__VAR)
175#endif
176
177#ifndef ARM_TEST_BITS
178# define ARM_TEST_BITS(__VALUE, __BITS) ((__BITS) == ((__VALUE) & (__BITS)))
179#endif
180
181#ifndef dimof
182# define dimof(__array) (sizeof(__array)/sizeof(__array[0]))
183#endif
184
185#ifndef offsetof
186# define offsetof(__type, __member) \
187 ((uintptr_t)&(((__type *)NULL)->__member))
188#endif
189
190#define __ARM_TO_STRING(__STR) #__STR
191#define ARM_TO_STRING(__STR) __ARM_TO_STRING(__STR)
192
193#define __ARM_VA_NUM_ARGS_IMPL( _0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12, \
194 _13,_14,_15,_16,__N,...) __N
195
196/*!
197 * \brief A macro to count the number of parameters
198 *
199 * \note if GNU extension is not supported or enabled, the following express will
200 * be false: (__ARM_VA_NUM_ARGS() != 0)
201 * This might cause problems when in this library.
202 */
203#define __ARM_VA_NUM_ARGS(...) \
204 __ARM_VA_NUM_ARGS_IMPL( 0,##__VA_ARGS__,16,15,14,13,12,11,10,9, \
205 8,7,6,5,4,3,2,1,0)
206
207/*!
208 * \brief detect whether GNU extension is enabled in compilation or not
209 */
210#if __ARM_VA_NUM_ARGS() != 0
211# warning Please enable GNU extensions, it is required by the Arm-2D.
212#endif
213
214#ifndef ARM_2D_INVOKE
215/*!
216 * \brief A macro to safely invode a function pointer
217 *
218 * \param[in] __FUNC_PTR the target function pointer
219 * \param[in] ... an optional parameter list
220 */
221# define ARM_2D_INVOKE(__FUNC_PTR, ...) \
222 do { \
223 if (NULL != (__FUNC_PTR)) { \
224 (*(__FUNC_PTR))(__VA_ARGS__); \
225 } \
226 } while(0)
227#endif
228
229#define __ARM_CONNECT2(__A, __B) __A##__B
230#define __ARM_CONNECT2_ALT(__A, __B) __A##__B
231#define __ARM_CONNECT3(__A, __B, __C) __A##__B##__C
232#define __ARM_CONNECT4(__A, __B, __C, __D) __A##__B##__C##__D
233#define __ARM_CONNECT5(__A, __B, __C, __D, __E) __A##__B##__C##__D##__E
234#define __ARM_CONNECT6(__A, __B, __C, __D, __E, __F) \
235 __A##__B##__C##__D##__E##__F
236#define __ARM_CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
237 __A##__B##__C##__D##__E##__F##__G
238#define __ARM_CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
239 __A##__B##__C##__D##__E##__F##__G##__H
240#define __ARM_CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
241 __A##__B##__C##__D##__E##__F##__G##__H##__I
242
243#define ARM_CONNECT2(__A, __B) __ARM_CONNECT2(__A, __B)
244#define ARM_CONNECT2_ALT(__A, __B) __ARM_CONNECT2_ALT(__A, __B)
245#define ARM_CONNECT3(__A, __B, __C) __ARM_CONNECT3(__A, __B, __C)
246#define ARM_CONNECT4(__A, __B, __C, __D) __ARM_CONNECT4(__A, __B, __C, __D)
247#define ARM_CONNECT5(__A, __B, __C, __D, __E) \
248 __ARM_CONNECT5(__A, __B, __C, __D, __E)
249#define ARM_CONNECT6(__A, __B, __C, __D, __E, __F) \
250 __ARM_CONNECT6(__A, __B, __C, __D, __E, __F)
251#define ARM_CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
252 __ARM_CONNECT7(__A, __B, __C, __D, __E, __F, __G)
253#define ARM_CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
254 __ARM_CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H)
255#define ARM_CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
256 __ARM_CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I)
257
258#define arm_connect(...) \
259 ARM_CONNECT2_ALT(ARM_CONNECT, __ARM_VA_NUM_ARGS(__VA_ARGS__)) \
260 (__VA_ARGS__)
261
262#define ARM_CONNECT(...) arm_connect(__VA_ARGS__)
263
264#define __ARM_USING1(__declare) \
265 for (__declare, *ARM_CONNECT3(__ARM_USING_, __LINE__,_ptr) = NULL; \
266 ARM_CONNECT3(__ARM_USING_, __LINE__,_ptr)++ == NULL; \
267 )
268
269#define __ARM_USING2(__declare, __on_leave_expr) \
270 for (__declare, *ARM_CONNECT3(__ARM_USING_, __LINE__,_ptr) = NULL; \
271 ARM_CONNECT3(__ARM_USING_, __LINE__,_ptr)++ == NULL; \
272 __on_leave_expr \
273 )
274
275#define __ARM_USING3(__declare, __on_enter_expr, __on_leave_expr) \
276 for (__declare, *ARM_CONNECT3(__ARM_USING_, __LINE__,_ptr) = NULL; \
277 ARM_CONNECT3(__ARM_USING_, __LINE__,_ptr)++ == NULL ? \
278 ((__on_enter_expr),1) : 0; \
279 __on_leave_expr \
280 )
281
282#define __ARM_USING4(__dcl1, __dcl2, __on_enter_expr, __on_leave_expr) \
283 for (__dcl1,__dcl2,*ARM_CONNECT3(__ARM_USING_, __LINE__,_ptr)= NULL;\
284 ARM_CONNECT3(__ARM_USING_, __LINE__,_ptr)++ == NULL ? \
285 ((__on_enter_expr),1) : 0; \
286 __on_leave_expr \
287 )
288
289#define arm_using(...) \
290 ARM_CONNECT2(__ARM_USING, __ARM_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
291
292
293#define __ARM_WITH2(__type, __addr) \
294 ARM_USING(__type *_p=(__addr))
295#define __ARM_WITH3(__type, __addr, __item) \
296 ARM_USING(__type *_p=(__addr), *__item = _p, _p=_p, )
297
298#define arm_with(...) \
299 ARM_CONNECT2(__ARM_WITH, __ARM_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
300
301#define ARM_FOREACH2(__type, __array) \
302 arm_using(__type *_ = __array) \
303 for ( uint_fast32_t ARM_CONNECT2(count,__LINE__) = dimof(__array);\
304 ARM_CONNECT2(count,__LINE__) > 0; \
305 _++, ARM_CONNECT2(count,__LINE__)-- \
306 )
307
308#define ARM_FOREACH3(__type, __array, __item) \
309 arm_using(__type *_ = __array, *__item = _, _ = _, ) \
310 for ( uint_fast32_t ARM_CONNECT2(count,__LINE__) = dimof(__array);\
311 ARM_CONNECT2(count,__LINE__) > 0; \
312 _++, __item = _, ARM_CONNECT2(count,__LINE__)-- \
313 )
314
315#define ARM_FOREACH4(__type, __array, __count, __item) \
316 arm_using(__type *_ = __array, *__item = _, _ = _, ) \
317 for ( uint_fast32_t ARM_CONNECT2(count,__LINE__) = (__count); \
318 ARM_CONNECT2(count,__LINE__) > 0; \
319 _++, __item = _, ARM_CONNECT2(count,__LINE__)-- \
320 )
321
322#define arm_foreach(...) \
323 ARM_CONNECT2(ARM_FOREACH, __ARM_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
324
325
326#ifndef ARM_NONNULL
327# if defined(__IS_COMPILER_ARM_COMPILER_5__) ||\
328 defined(__IS_COMPILER_ARM_COMPILER_6__) ||\
329 defined(__IS_COMPILER_GCC__) ||\
330 defined(__IS_COMPILER_LLVM__)
331# define ARM_NONNULL(...) __attribute__((nonnull(__VA_ARGS__)))
332# else
333# define ARM_NONNULL(...)
334# endif
335#endif
336
337#ifndef ARM_NOINIT
338# if defined(__IS_COMPILER_ARM_COMPILER_5__)
339# define ARM_NOINIT __attribute__(( section( ".bss.noinit"),zero_init))
340# elif defined(__IS_COMPILER_ARM_COMPILER_6__)
341# define ARM_NOINIT __attribute__(( section( ".bss.noinit")))
342# elif defined(__IS_COMPILER_IAR__)
343# define ARM_NOINIT __no_init
344# elif defined(__IS_COMPILER_GCC__) || defined(__IS_COMPILER_LLVM__)
345# define ARM_NOINIT __attribute__(( section( ".bss.noinit")))
346# else
347# define ARM_NOINIT
348# endif
349#endif
350
351
352#ifndef ARM_ALIGN
353# define __ARM_ALIGN(__N) __attribute__((aligned(__N)))
354# define ARM_ALIGN(__N) __ARM_ALIGN(__N)
355#endif
356
357
358#ifndef __RESTRICT
359# define __RESTRICT __restrict
360#endif
361
362#ifndef __OVERRIDE_WEAK
363# define __OVERRIDE_WEAK
364#endif
365
366/*!
367 * \brief A macro to generate a safe name, usually used in macro template as the
368 * name of local variables
369 *
370 */
371#define ARM_2D_SAFE_NAME(...) ARM_CONNECT(__,__LINE__,##__VA_ARGS__)
372#define arm_2d_safe_name(...) ARM_2D_SAFE_NAME(__VA_ARGS__)
373
374#undef arm_irq_safe
375
376/*!
377 * \brief a decoration to make the immediate following code irq-safe
378 *
379 * \code
380 arm_irq_safe {
381 // code inside the brackets are IRQ safe
382 ...
383 }
384
385 // the printf is IRQ safe
386 arm_irq_safe printf("IRQ safe printf\n");
387
388 \endcode
389 */
390#define arm_irq_safe \
391 arm_using( uint32_t ARM_2D_SAFE_NAME(temp) = \
392 ({uint32_t temp=__get_PRIMASK();__disable_irq();temp;}),\
393 __set_PRIMASK(ARM_2D_SAFE_NAME(temp)))
394
395
396#undef ARM_2D_WRAP_FUNC
397#undef __ARM_2D_WRAP_FUNC
398#undef ARM_2D_ORIG_FUNC
399#undef __ARM_2D_ORIG_FUNC
400
401#if defined(__IS_COMPILER_ARM_COMPILER_6__)
402# define __ARM_2D_WRAP_FUNC(__FUNC) $Sub$$##__FUNC
403# define __ARM_2D_ORIG_FUNC(__FUNC) $Super$$## __FUNC
404#else
405# define __ARM_2D_WRAP_FUNC(x) __wrap_ ## x
406# define __ARM_2D_ORIG_FUNC(x) __real_ ## x
407#endif
408
409#define ARM_2D_WRAP_FUNC(__FUNC) __ARM_2D_WRAP_FUNC(__FUNC)
410#define ARM_2D_ORIG_FUNC(__FUNC) __ARM_2D_ORIG_FUNC(__FUNC)
411
412/*----------------------------------------------------------------------------*
413 * List Operations *
414 *----------------------------------------------------------------------------*/
415
416/* ALL the parameters passed to following macros must be pointer variables. */
417
418#define __ARM_LIST_STACK_PUSH(__P_TOP, __P_NODE) \
419 do { \
420 ((__arm_slist_node_t *)(__P_NODE))->ptNext = \
421 (__arm_slist_node_t *)(__P_TOP); \
422 (*(__arm_slist_node_t **)&(__P_TOP)) = \
423 (__arm_slist_node_t *)(__P_NODE); \
424 } while(0)
425#define ARM_LIST_STACK_PUSH(__P_TOP, __P_NODE) \
426 __ARM_LIST_STACK_PUSH((__P_TOP), (__P_NODE))
427#define ARM_LIST_INSERT_AFTER(__P_TARGET, __P_NODE) \
428 __ARM_LIST_STACK_PUSH((__P_TARGET), (__P_NODE))
429
430#define __ARM_LIST_STACK_POP(__P_TOP, __P_NODE) \
431 do { \
432 (*(__arm_slist_node_t **)&(__P_NODE)) = \
433 (__arm_slist_node_t *)(__P_TOP); \
434 if (NULL != (__P_TOP)) { \
435 (*(__arm_slist_node_t **)&(__P_TOP)) = \
436 ((__arm_slist_node_t *)(__P_NODE))->ptNext; \
437 ((__arm_slist_node_t *)(__P_NODE))->ptNext = NULL; \
438 } \
439 } while(0)
440#define ARM_LIST_STACK_POP(__P_TOP, __P_NODE) \
441 __ARM_LIST_STACK_POP((__P_TOP), (__P_NODE))
442#define ARM_LIST_REMOVE_AFTER(__P_TARGET, __P_NODE) \
443 ARM_LIST_STACK_POP((__P_TARGET), (__P_NODE))
444
445
446#define __ARM_LIST_QUEUE_ENQUEUE(__HEAD, __TAIL, __ITEM) \
447 do { \
448 if (NULL == (__TAIL)) { \
449 (*((__arm_slist_node_t **)&(__TAIL))) = \
450 (__arm_slist_node_t *)(__ITEM); \
451 (*((__arm_slist_node_t **)&(__HEAD))) = \
452 (__arm_slist_node_t *)(__ITEM); \
453 } else { \
454 ((__arm_slist_node_t *)(__TAIL))->ptNext = \
455 (__arm_slist_node_t *)(__ITEM); \
456 (*(__arm_slist_node_t **)&(__TAIL)) = \
457 (__arm_slist_node_t *)(__ITEM); \
458 } \
459 ((__arm_slist_node_t *)(__ITEM))->ptNext = NULL; \
460 } while(0)
461#define ARM_LIST_QUEUE_ENQUEUE(__HEAD, __TAIL, __ITEM) \
462 __ARM_LIST_QUEUE_ENQUEUE((__HEAD), (__TAIL), (__ITEM))
463
464#define __ARM_LIST_QUEUE_DEQUEUE(__HEAD, __TAIL, __ITEM) \
465 do { \
466 (*(__arm_slist_node_t **)&(__ITEM)) = (__arm_slist_node_t *)(__HEAD); \
467 if (NULL != (__HEAD)) { \
468 (*(__arm_slist_node_t **)&(__HEAD)) = \
469 ((__arm_slist_node_t *)(__HEAD))->ptNext; \
470 if (NULL == (__HEAD)) { \
471 (__TAIL) = NULL; \
472 } \
473 } \
474 } while(0)
475
476#define ARM_LIST_QUEUE_DEQUEUE(__HEAD, __TAIL, __ITEM) \
477 __ARM_LIST_QUEUE_DEQUEUE((__HEAD), (__TAIL), (__ITEM))
478
479#define __ARM_LIST_QUEUE_PEEK(__HEAD, __TAIL, __ITEM) \
480 do { \
481 (*(__arm_slist_node_t **)&(__ITEM)) = (__arm_slist_node_t *)(__HEAD); \
482 } while(0)
483#define ARM_LIST_QUEUE_PEEK(__HEAD, __TAIL, __ITEM) \
484 __ARM_LIST_QUEUE_PEEK((__HEAD), (__TAIL), (__ITEM)) \
485
486/*----------------------------------------------------------------------------*
487 * Definition Template *
488 *----------------------------------------------------------------------------*/
489
490#define __def_low_lv_io(__NAME, __SW, ...) \
491const __arm_2d_low_level_io_t LOW_LEVEL_IO##__NAME = { \
492 .SW = (__arm_2d_io_func_t *)&(__SW), \
493 .HW = (NULL, ##__VA_ARGS__) \
494}
495#define def_low_lv_io(__NAME, __SW, ...) \
496 __def_low_lv_io(__NAME, __SW, ##__VA_ARGS__)
497
498
499#define __ref_low_lv_io(__NAME) &LOW_LEVEL_IO##__NAME
500#define ref_low_lv_io(__NAME) __ref_low_lv_io(__NAME)
501
502/*============================ TYPES =========================================*/
503
504/*!
505 * \brief a type for generic list
506 *
507 * \note to avoid using container_of() operand, please put __arm_slist_node_t
508 * at the beginning of a class/structure
509 */
512 __arm_slist_node_t *ptNext; //!< the next node
513};
514
515
516/*============================ GLOBAL VARIABLES ==============================*/
517/*============================ PROTOTYPES ====================================*/
518
519#if defined(__clang__)
520# pragma clang diagnostic pop
521#elif __IS_COMPILER_ARM_COMPILER_5__
522#elif __IS_COMPILER_GCC__
523# pragma GCC diagnostic pop
524#endif
525
526#ifdef __cplusplus
527}
528#endif
529
530#endif /* end of __ARM_2D_UTILS_H__ */
531
532
533/*! @} */
534
535/*============================ MACROS ========================================*/
536/*----------------------------------------------------------------------------*
537 * Reentrant Macros *
538 *----------------------------------------------------------------------------*/
539
540/* un-define macros */
541#undef ARM_PRIVATE
542
543
544/* redefine macros */
545#if defined(__cplusplus)
546# define ARM_PRIVATE(...) \
547 struct { \
548 __VA_ARGS__ \
549 };
550
551#elif defined(__ARM_2D_IMPL__) || defined(__IS_COMPILER_IAR__)
552
553# define ARM_PRIVATE(...) \
554 struct { \
555 __VA_ARGS__ \
556 } __ALIGNED(__alignof__(struct {__VA_ARGS__}));
557
558#else
559# define ARM_PRIVATE(...) \
560 uint8_t ARM_CONNECT3(chMask,__LINE__,__COUNTER__) \
561 [sizeof(struct {__VA_ARGS__})] \
562 __ALIGNED(__alignof__(struct {__VA_ARGS__}));
563#endif
564
565
566
567
568/* post un-define macros */
569
570#undef __ARM_2D_IMPL__
571