xref: /Kernel-v11.0.1/portable/ThirdParty/GCC/Xtensa_ESP32/include/portmacro.h (revision 65c72e485a63577f5d15096d5a53c9dca8822d65)
1 /*
2  * SPDX-FileCopyrightText: 2017 Amazon.com, Inc. or its affiliates
3  * SPDX-FileCopyrightText: 2015-2019 Cadence Design Systems, Inc.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
8  */
9 
10 /*
11  * FreeRTOS Kernel V11.0.1
12  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a copy of
15  * this software and associated documentation files (the "Software"), to deal in
16  * the Software without restriction, including without limitation the rights to
17  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
18  * the Software, and to permit persons to whom the Software is furnished to do so,
19  * subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be included in all
22  * copies or substantial portions of the Software. If you wish to use our Amazon
23  * FreeRTOS name, please do so in a fair use way that does not cause confusion.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
27  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
28  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
29  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31  *
32  * https://www.FreeRTOS.org
33  * https://github.com/FreeRTOS
34  *
35  * 1 tab == 4 spaces!
36  */
37 
38 /*
39  * Copyright (c) 2015-2019 Cadence Design Systems, Inc.
40  *
41  * Permission is hereby granted, free of charge, to any person obtaining
42  * a copy of this software and associated documentation files (the
43  * "Software"), to deal in the Software without restriction, including
44  * without limitation the rights to use, copy, modify, merge, publish,
45  * distribute, sublicense, and/or sell copies of the Software, and to
46  * permit persons to whom the Software is furnished to do so, subject to
47  * the following conditions:
48  *
49  * The above copyright notice and this permission notice shall be included
50  * in all copies or substantial portions of the Software.
51  *
52  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
53  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
54  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
55  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
56  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
57  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
58  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
59  */
60 
61 #ifndef PORTMACRO_H
62 #define PORTMACRO_H
63 
64 /* *INDENT-OFF* */
65 #ifdef __cplusplus
66     extern "C" {
67 #endif
68 /* *INDENT-ON* */
69 
70 #ifndef __ASSEMBLER__
71 
72     #include <stdint.h>
73 
74     #include <xtensa/hal.h>
75     #include <xtensa/config/core.h>
76     #include <xtensa/config/system.h> /* required for XSHAL_CLIB */
77     #include <xtensa/xtruntime.h>
78     #include "soc/spinlock.h"
79     #include "esp_timer.h" /* required for FreeRTOS run time stats */
80     #include "esp_system.h"
81     #include "esp_idf_version.h"
82     #include "esp_heap_caps.h"
83 
84 /* TODO: Resolve build warnings generated due to this header inclusion */
85     #include "hal/cpu_hal.h"
86 
87 /* TODO: These includes are not directly used in this file. They are kept into to prevent a breaking change. Remove these. */
88     #include <limits.h>
89     #include <xtensa/xtensa_api.h>
90 
91     #include "soc/cpu.h"
92     #include "soc/soc_memory_layout.h"
93     #if ( ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 2, 0 ) )
94         #include "soc/compare_set.h"
95     #endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
96 
97 /*#include "xtensa_context.h" */
98 
99 /*-----------------------------------------------------------
100  * Port specific definitions.
101  *
102  * The settings in this file configure FreeRTOS correctly for the
103  * given hardware and compiler.
104  *
105  * These settings should not be altered.
106  *-----------------------------------------------------------
107  */
108 
109 /* Type definitions. */
110 
111     #define portCHAR          int8_t
112     #define portFLOAT         float
113     #define portDOUBLE        double
114     #define portLONG          int32_t
115     #define portSHORT         int16_t
116     #define portSTACK_TYPE    uint8_t
117     #define portBASE_TYPE     int
118 
119     typedef portSTACK_TYPE           StackType_t;
120     typedef portBASE_TYPE            BaseType_t;
121     typedef unsigned portBASE_TYPE   UBaseType_t;
122 
123     #if ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS )
124         typedef uint16_t             TickType_t;
125         #define portMAX_DELAY    ( TickType_t ) 0xffff
126     #elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS )
127         typedef uint32_t             TickType_t;
128         #define portMAX_DELAY    ( TickType_t ) 0xffffffffUL
129     #else
130         #error configTICK_TYPE_WIDTH_IN_BITS set to unsupported tick type width.
131     #endif
132 /*-----------------------------------------------------------*/
133 
134 /* portbenchmark */
135     #include "portbenchmark.h"
136 
137     #include "sdkconfig.h"
138     #include "esp_attr.h"
139 
140 /* "mux" data structure (spinlock) */
141     typedef spinlock_t portMUX_TYPE;                                /**< Spinlock type used by FreeRTOS critical sections */
142     #define portMUX_INITIALIZER_UNLOCKED    SPINLOCK_INITIALIZER    /**< Spinlock initializer */
143     #define portMUX_FREE_VAL                SPINLOCK_FREE           /**< Spinlock is free. [refactor-todo] check if this is still required */
144     #define portMUX_NO_TIMEOUT              SPINLOCK_WAIT_FOREVER   /**< When passed for 'timeout_cycles', spin forever if necessary. [refactor-todo] check if this is still required */
145     #define portMUX_TRY_LOCK                SPINLOCK_NO_WAIT        /**< Try to acquire the spinlock a single time only. [refactor-todo] check if this is still required */
146     #define portMUX_INITIALIZE( mux )    spinlock_initialize( mux ) /*< Initialize a spinlock to its unlocked state */
147 
148     #define portCRITICAL_NESTING_IN_TCB     1
149 
150 /*
151  * Modifications to portENTER_CRITICAL.
152  *
153  * For an introduction, see "Critical Sections & Disabling Interrupts" in docs/api-guides/freertos-smp.rst
154  *
155  * The original portENTER_CRITICAL only disabled the ISRs. This is enough for single-CPU operation: by
156  * disabling the interrupts, there is no task switch so no other tasks can meddle in the data, and because
157  * interrupts are disabled, ISRs can't corrupt data structures either.
158  *
159  * For multiprocessing, things get a bit more hairy. First of all, disabling the interrupts doesn't stop
160  * the tasks or ISRs on the other processors meddling with our CPU. For tasks, this is solved by adding
161  * a spinlock to the portENTER_CRITICAL macro. A task running on the other CPU accessing the same data will
162  * spinlock in the portENTER_CRITICAL code until the first CPU is done.
163  *
164  * For ISRs, we now also need muxes: while portENTER_CRITICAL disabling interrupts will stop ISRs on the same
165  * CPU from meddling with the data, it does not stop interrupts on the other cores from interfering with the
166  * data. For this, we also use a spinlock in the routines called by the ISR, but these spinlocks
167  * do not disable the interrupts (because they already are).
168  *
169  * This all assumes that interrupts are either entirely disabled or enabled. Interrupt priority levels
170  * will break this scheme.
171  *
172  * Remark: For the ESP32, portENTER_CRITICAL and portENTER_CRITICAL_ISR both alias vPortEnterCritical, meaning
173  * that either function can be called both from ISR as well as task context. This is not standard FreeRTOS
174  * behaviour; please keep this in mind if you need any compatibility with other FreeRTOS implementations.
175  */
176     void vPortCPUInitializeMutex( portMUX_TYPE * mux );
177     #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
178         #error CONFIG_FREERTOS_PORTMUX_DEBUG not supported in Amazon FreeRTOS
179     #endif
180 
181     void vTaskExitCritical();
182     void vTaskEnterCritical();
vPortConsumeSpinlockArg(int unused,...)183     static inline void vPortConsumeSpinlockArg( int unused,
184                                                 ... )
185     {
186     }
187 
188 /** @brief Acquire a portmux spinlock with a timeout
189  *
190  * @param mux Pointer to portmux to acquire.
191  * @param timeout_cycles Timeout to spin, in CPU cycles. Pass portMUX_NO_TIMEOUT to wait forever,
192  * portMUX_TRY_LOCK to try a single time to acquire the lock.
193  *
194  * @return true if mutex is successfully acquired, false on timeout.
195  */
196     bool vPortCPUAcquireMutexTimeout( portMUX_TYPE * mux,
197                                       int timeout_cycles );
198     void vPortCPUReleaseMutex( portMUX_TYPE * mux );
199 
200     #define portENTER_CRITICAL( ... )        do { vTaskEnterCritical(); vPortConsumeSpinlockArg( 0, ## __VA_ARGS__ ); } while( 0 )
201     #define portEXIT_CRITICAL( ... )         do { vTaskExitCritical(); vPortConsumeSpinlockArg( 0, ## __VA_ARGS__ ); } while( 0 )
202 
203 
204     #define portENTER_CRITICAL_ISR( mux )    vPortCPUAcquireMutexTimeout( mux, portMUX_NO_TIMEOUT )
205     #define portEXIT_CRITICAL_ISR( mux )     vPortCPUReleaseMutex( mux )
206 
207     #define portENTER_CRITICAL_SAFE( mux ) \
208     do {                                   \
209         if( xPortInIsrContext() ) {        \
210             portENTER_CRITICAL_ISR( mux ); \
211         }                                  \
212         else {                             \
213             portENTER_CRITICAL( mux );     \
214         }                                  \
215     } while( 0 )
216 
217     #define portEXIT_CRITICAL_SAFE( mux ) \
218     do {                                  \
219         if( xPortInIsrContext() ) {       \
220             portEXIT_CRITICAL_ISR( mux ); \
221         }                                 \
222         else {                            \
223             portEXIT_CRITICAL( mux );     \
224         }                                 \
225     } while( 0 )
226 
227     #define portASSERT_IF_IN_ISR()    vPortAssertIfInISR()
228     void vPortAssertIfInISR( void );
229 
230 /* Critical section management. NW-TODO: replace XTOS_SET_INTLEVEL with more efficient version, if any? */
231 /* These cannot be nested. They should be used with a lot of care and cannot be called from interrupt level. */
232 /* */
233 /* Only applies to one CPU. See notes above & below for reasons not to use these. */
234     #define portDISABLE_INTERRUPTS()    do { XTOS_SET_INTLEVEL( XCHAL_EXCM_LEVEL ); portbenchmarkINTERRUPT_DISABLE(); } while( 0 )
235     #define portENABLE_INTERRUPTS()     do { portbenchmarkINTERRUPT_RESTORE( 0 ); XTOS_SET_INTLEVEL( 0 ); } while( 0 )
236 
237 /* Cleaner solution allows nested interrupts disabling and restoring via local registers or stack. */
238 /* They can be called from interrupts too. */
239 /* WARNING: Only applies to current CPU. See notes above. */
xPortSetInterruptMaskFromISR(void)240     static inline UBaseType_t __attribute__( ( always_inline ) ) xPortSetInterruptMaskFromISR( void )
241     {
242         UBaseType_t prev_int_level = XTOS_SET_INTLEVEL( XCHAL_EXCM_LEVEL );
243 
244         portbenchmarkINTERRUPT_DISABLE();
245         return prev_int_level;
246     }
247 
vPortClearInterruptMaskFromISR(UBaseType_t prev_level)248     static inline void __attribute__( ( always_inline ) ) vPortClearInterruptMaskFromISR( UBaseType_t prev_level )
249     {
250         portbenchmarkINTERRUPT_RESTORE( prev_level );
251         XTOS_RESTORE_JUST_INTLEVEL( prev_level );
252     }
253 
254 /* These FreeRTOS versions are similar to the nested versions above */
255     #define portSET_INTERRUPT_MASK_FROM_ISR()                  xPortSetInterruptMaskFromISR()
256     #define portCLEAR_INTERRUPT_MASK_FROM_ISR( prev_level )    vPortClearInterruptMaskFromISR( prev_level )
257 
258 /*Because the ROM routines don't necessarily handle a stack in external RAM correctly, we force */
259 /*the stack memory to always be internal. */
260     #define portTcbMemoryCaps      ( MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT )
261     #define portStackMemoryCaps    ( MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT )
262 
263     #define pvPortMallocTcbMem( size )        heap_caps_malloc( size, portTcbMemoryCaps )
264     #define pvPortMallocStackMem( size )      heap_caps_malloc( size, portStackMemoryCaps )
265 
266 /*xTaskCreateStatic uses these functions to check incoming memory. */
267     #define portVALID_TCB_MEM( ptr )          ( esp_ptr_internal( ptr ) && esp_ptr_byte_accessible( ptr ) )
268     #ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
269         #define portVALID_STACK_MEM( ptr )    esp_ptr_byte_accessible( ptr )
270     #else
271         #define portVALID_STACK_MEM( ptr )    ( esp_ptr_internal( ptr ) && esp_ptr_byte_accessible( ptr ) )
272     #endif
273 
274 /*
275  * Wrapper for the Xtensa compare-and-set instruction. This subroutine will atomically compare
276  * *addr to 'compare'. If *addr == compare, *addr is set to *set. *set is updated with the previous
277  * value of *addr (either 'compare' or some other value.)
278  *
279  * Warning: From the ISA docs: in some (unspecified) cases, the s32c1i instruction may return the
280  * *bitwise inverse* of the old mem if the mem wasn't written. This doesn't seem to happen on the
281  * ESP32 (portMUX assertions would fail).
282  */
uxPortCompareSet(volatile uint32_t * addr,uint32_t compare,uint32_t * set)283     static inline void uxPortCompareSet( volatile uint32_t * addr,
284                                          uint32_t compare,
285                                          uint32_t * set )
286     {
287         #if ( ESP_IDF_VERSION < ESP_IDF_VERSION_VAL( 4, 2, 0 ) )
288             __asm__ __volatile__ (
289                 "WSR       %2,SCOMPARE1 \n"
290                 "S32C1I     %0, %1, 0   \n"
291                 : "=r" ( *set )
292                 : "r" ( addr ), "r" ( compare ), "0" ( *set )
293                 );
294         #else
295             #if ( XCHAL_HAVE_S32C1I > 0 )
296                 __asm__ __volatile__ (
297                     "WSR        %2,SCOMPARE1 \n"
298                     "S32C1I     %0, %1, 0    \n"
299                     : "=r" ( *set )
300                     : "r" ( addr ), "r" ( compare ), "0" ( *set )
301                     );
302             #else
303                 /* No S32C1I, so do this by disabling and re-enabling interrupts (slower) */
304                 uint32_t intlevel, old_value;
305                 __asm__ __volatile__ ( "rsil %0, " XTSTR( XCHAL_EXCM_LEVEL ) "\n"
306                                        : "=r" ( intlevel ) );
307 
308                 old_value = *addr;
309 
310                 if( old_value == compare )
311                 {
312                     *addr = *set;
313                 }
314 
315                 __asm__ __volatile__ ( "memw \n"
316                                        "wsr %0, ps\n"
317                                        : : "r" ( intlevel ) );
318 
319                 *set = old_value;
320             #endif /* if ( XCHAL_HAVE_S32C1I > 0 ) */
321         #endif /* #if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)) */
322     }
323 
324     #if ( ESP_IDF_VERSION < ESP_IDF_VERSION_VAL( 4, 2, 0 ) )
325         void uxPortCompareSetExtram( volatile uint32_t * addr,
326                                      uint32_t compare,
327                                      uint32_t * set );
328     #else
uxPortCompareSetExtram(volatile uint32_t * addr,uint32_t compare,uint32_t * set)329         static inline void uxPortCompareSetExtram( volatile uint32_t * addr,
330                                                    uint32_t compare,
331                                                    uint32_t * set )
332         {
333             #if defined( CONFIG_SPIRAM )
334                 compare_and_set_extram( addr, compare, set );
335             #endif
336         }
337     #endif /* if ( ESP_IDF_VERSION < ESP_IDF_VERSION_VAL( 4, 2, 0 ) ) */
338 
339 /*-----------------------------------------------------------*/
340 
341 /* Architecture specifics. */
342     #define portSTACK_GROWTH      ( -1 )
343     #define portTICK_PERIOD_MS    ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
344     #define portBYTE_ALIGNMENT    4
345     #define portNOP()    XT_NOP()
346 /*-----------------------------------------------------------*/
347 
348 /* Fine resolution time */
349     #define portGET_RUN_TIME_COUNTER_VALUE()    xthal_get_ccount()
350 /*ccount or esp_timer are initialized elsewhere */
351     #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
352 
353     #ifdef CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER
354 /* Coarse resolution time (us) */
355         #define portALT_GET_RUN_TIME_COUNTER_VALUE( x )    do { x = ( uint32_t ) esp_timer_get_time(); } while( 0 )
356     #endif
357 
358 
359 
360 /* Kernel utilities. */
361     void vPortYield( void );
362     void vPortEvaluateYieldFromISR( int argc,
363                                     ... );
364     void _frxt_setup_switch( void );
365 
366 /* Macro to count number of arguments of a __VA_ARGS__ used to support portYIELD_FROM_ISR with,
367  * or without arguments. The macro counts only 0 or 1 arguments.
368  *
369  * In the future, we want to switch to C++20. We also want to become compatible with clang.
370  * Hence, we provide two versions of the following macros which are using variadic arguments.
371  * The first one is using the GNU extension ##__VA_ARGS__. The second one is using the C++20 feature __VA_OPT__(,).
372  * This allows users to compile their code with standard C++20 enabled instead of the GNU extension.
373  * Below C++20, we haven't found any good alternative to using ##__VA_ARGS__.
374  */
375     #if defined( __cplusplus ) && ( __cplusplus > 201703L )
376         #define portGET_ARGUMENT_COUNT( ... )                        portGET_ARGUMENT_COUNT_INNER( 0 __VA_OPT__(, ) __VA_ARGS__, 1, 0 )
377     #else
378         #define portGET_ARGUMENT_COUNT( ... )                        portGET_ARGUMENT_COUNT_INNER( 0, ## __VA_ARGS__, 1, 0 )
379     #endif
380     #define portGET_ARGUMENT_COUNT_INNER( zero, one, count, ... )    count
381 
382     _Static_assert( portGET_ARGUMENT_COUNT() == 0, "portGET_ARGUMENT_COUNT() result does not match for 0 arguments" );
383     _Static_assert( portGET_ARGUMENT_COUNT( 1 ) == 1, "portGET_ARGUMENT_COUNT() result does not match for 1 argument" );
384 
385     #define portYIELD()    vPortYield()
386 
387 /* The macro below could be used when passing a single argument, or without any argument,
388  * it was developed to support both usages of portYIELD inside of an ISR. Any other usage form
389  * might result in undesired behaviour
390  */
391     #if defined( __cplusplus ) && ( __cplusplus > 201703L )
392         #define portYIELD_FROM_ISR( ... )    vPortEvaluateYieldFromISR( portGET_ARGUMENT_COUNT( __VA_ARGS__ ) __VA_OPT__(, ) __VA_ARGS__ )
393     #else
394         #define portYIELD_FROM_ISR( ... )    vPortEvaluateYieldFromISR( portGET_ARGUMENT_COUNT( __VA_ARGS__ ), ## __VA_ARGS__ )
395     #endif
396 
397     static inline BaseType_t xPortGetCoreID();
398 
399 /*-----------------------------------------------------------*/
400 
401 /* Task function macros as described on the FreeRTOS.org WEB site. */
402     #define portTASK_FUNCTION_PROTO( vFunction, pvParameters )    void vFunction( void * pvParameters )
403     #define portTASK_FUNCTION( vFunction, pvParameters )          void vFunction( void * pvParameters )
404 
405 /* When coprocessors are defined, we to maintain a pointer to coprocessors area. */
406 /* We currently use a hack: redefine field xMPU_SETTINGS in TCB block as a structure that can hold: */
407 /* MPU wrappers, coprocessor area pointer, trace code structure, and more if needed. */
408 /* The field is normally used for memory protection. FreeRTOS should create another general purpose field. */
409     typedef struct
410     {
411         #if XCHAL_CP_NUM > 0
412             volatile StackType_t * coproc_area; /* Pointer to coprocessor save area; MUST BE FIRST */
413         #endif
414 
415         #if portUSING_MPU_WRAPPERS
416             /* Define here mpu_settings, which is port dependent */
417             int mpu_setting; /* Just a dummy example here; MPU not ported to Xtensa yet */
418         #endif
419 
420         #if configUSE_TRACE_FACILITY_2
421             struct
422             {
423                 /* Cf. porttraceStamp() */
424                 int taskstamp;      /* Stamp from inside task to see where we are */
425                 int taskstampcount; /* A counter usually incremented when we restart the task's loop */
426             } porttrace;
427         #endif
428     } xMPU_SETTINGS;
429 
430 /* Main hack to use MPU_wrappers even when no MPU is defined (warning: mpu_setting should not be accessed; otherwise move this above xMPU_SETTINGS) */
431     #if ( XCHAL_CP_NUM > 0 || configUSE_TRACE_FACILITY_2 ) && !portUSING_MPU_WRAPPERS /* If MPU wrappers not used, we still need to allocate coproc area */
432         #undef portUSING_MPU_WRAPPERS
433         #define portUSING_MPU_WRAPPERS    1                                           /* Enable it to allocate coproc area */
434         #define MPU_WRAPPERS_H                                                        /* Override mpu_wrapper.h to disable unwanted code */
435         #define PRIVILEGED_FUNCTION
436         #define PRIVILEGED_DATA
437     #endif
438 
439     void vApplicationSleep( TickType_t xExpectedIdleTime );
440 
441     #define portSUPPRESS_TICKS_AND_SLEEP( idleTime )    vApplicationSleep( idleTime )
442 
443     void _xt_coproc_release( volatile void * coproc_sa_base );
444 
445 /*-----------------------------------------------------------*/
446 
447     #if ( ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 2, 0 ) )
448         /* Architecture specific optimisations. */
449 
450         #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
451 
452 /* Check the configuration. */
453             #if ( configMAX_PRIORITIES > 32 )
454                 #error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32.  It is very rare that a system requires more than 10 to 15 different priorities as tasks that share a priority will time slice.
455             #endif
456 
457 /* Store/clear the ready priorities in a bit map. */
458             #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities )    ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
459             #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities )     ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
460 
461 /*-----------------------------------------------------------*/
462 
463             #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities )    uxTopPriority = ( 31 - __builtin_clz( ( uxReadyPriorities ) ) )
464 
465         #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
466 
467     #endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
468 
469 /*-----------------------------------------------------------*/
470 
471 /*
472  * Map to the memory management routines required for the port.
473  *
474  * Note that libc standard malloc/free are also available for
475  * non-FreeRTOS-specific code, and behave the same as
476  * pvPortMalloc()/vPortFree().
477  */
478     #define pvPortMalloc                       heap_caps_malloc_default
479     #define vPortFree                          heap_caps_free
480     #define xPortGetFreeHeapSize               esp_get_free_heap_size
481     #define xPortGetMinimumEverFreeHeapSize    esp_get_minimum_free_heap_size
482 
483     #if ( ESP_IDF_VERSION < ESP_IDF_VERSION_VAL( 4, 2, 0 ) )
484 
485 /*
486  * Send an interrupt to another core in order to make the task running
487  * on it yield for a higher-priority task.
488  */
489 
490         void vPortYieldOtherCore( BaseType_t coreid ) PRIVILEGED_FUNCTION;
491 
492     #endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) */
493 
494 /*
495  * Callback to set a watchpoint on the end of the stack. Called every context switch to change the stack
496  * watchpoint around.
497  */
498     void vPortSetStackWatchpoint( void * pxStackStart );
499 
500 /*
501  * Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs
502  * aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
503  */
504     BaseType_t xPortInIsrContext();
505 
506 
507 /*
508  * This function will be called in High prio ISRs. Returns true if the current core was in ISR context
509  * before calling into high prio ISR context.
510  */
511     BaseType_t xPortInterruptedFromISRContext();
512 
513 /*
514  * The structures and methods of manipulating the MPU are contained within the
515  * port layer.
516  *
517  * Fills the xMPUSettings structure with the memory region information
518  * contained in xRegions.
519  */
520     #if ( portUSING_MPU_WRAPPERS == 1 )
521         struct xMEMORY_REGION;
522         void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
523                                         const struct xMEMORY_REGION * const xRegions,
524                                         StackType_t * pxBottomOfStack,
525                                         uint32_t usStackDepth ) PRIVILEGED_FUNCTION;
526         void vPortReleaseTaskMPUSettings( xMPU_SETTINGS * xMPUSettings );
527     #endif
528 
529 /* Multi-core: get current core ID */
xPortGetCoreID()530     static inline BaseType_t IRAM_ATTR xPortGetCoreID()
531     {
532         return ( uint32_t ) cpu_hal_get_core_id();
533     }
534 
535 /* Get tick rate per second */
536     uint32_t xPortGetTickRateHz( void );
537 
xPortCanYield(void)538     static inline bool IRAM_ATTR xPortCanYield( void )
539     {
540         uint32_t ps_reg = 0;
541 
542         /*Get the current value of PS (processor status) register */
543         RSR( PS, ps_reg );
544 
545         /*
546          * intlevel = (ps_reg & 0xf);
547          * excm  = (ps_reg >> 4) & 0x1;
548          * CINTLEVEL is max(excm * EXCMLEVEL, INTLEVEL), where EXCMLEVEL is 3.
549          * However, just return true, only intlevel is zero.
550          */
551 
552         return( ( ps_reg & PS_INTLEVEL_MASK ) == 0 );
553     }
554 
555 /* porttrace */
556     #if configUSE_TRACE_FACILITY_2
557         #include "porttrace.h"
558     #endif
559 
560 /* configASSERT_2 if requested */
561     #if configASSERT_2
562         #include <stdio.h>
563         void exit( int );
564         #define configASSERT( x )    if( !( x ) ) { porttracePrint( -1 ); printf( "\nAssertion failed in %s:%d\n", __FILE__, __LINE__ ); exit( -1 ); }
565     #endif
566 
567 /* Barriers */
568     #define portMEMORY_BARRIER()    __asm volatile ( "" ::: "memory" )
569 
570 
571 #endif // __ASSEMBLER__
572 
573 /* *INDENT-OFF* */
574 #ifdef __cplusplus
575     }
576 #endif
577 /* *INDENT-ON* */
578 
579 #endif /* PORTMACRO_H */
580