From 963abe6c4833e7c969279b537c103d7a0bdd5116 Mon Sep 17 00:00:00 2001 From: Laukik Hase Date: Wed, 12 Oct 2022 02:57:32 +0530 Subject: [PATCH] Updated ESP32 port-layer to ESP-IDF `v4.4.2` (#572) * Xtensa_ESP32: Added esp-idf v4.4.2 specific changes * Xtensa_ESP32: Updated SPDX license identifiers --- .../include/FreeRTOSConfig_arch.h | 134 +++++++ .../GCC/Xtensa_ESP32/include/port_systick.h | 20 + .../GCC/Xtensa_ESP32/include/portmacro.h | 159 ++++---- .../GCC/Xtensa_ESP32/include/xtensa_api.h | 111 +----- .../GCC/Xtensa_ESP32/include/xtensa_context.h | 371 +----------------- .../GCC/Xtensa_ESP32/include/xtensa_rtos.h | 6 +- portable/ThirdParty/GCC/Xtensa_ESP32/port.c | 249 +++++++----- .../ThirdParty/GCC/Xtensa_ESP32/port_common.c | 159 ++++++++ .../GCC/Xtensa_ESP32/port_systick.c | 174 ++++++++ .../ThirdParty/GCC/Xtensa_ESP32/portasm.S | 14 +- .../ThirdParty/GCC/Xtensa_ESP32/xtensa_init.c | 33 +- .../ThirdParty/GCC/Xtensa_ESP32/xtensa_intr.c | 190 --------- .../GCC/Xtensa_ESP32/xtensa_intr_asm.S | 232 ----------- .../GCC/Xtensa_ESP32/xtensa_vector_defaults.S | 76 +++- .../GCC/Xtensa_ESP32/xtensa_vectors.S | 22 +- 15 files changed, 854 insertions(+), 1096 deletions(-) create mode 100644 portable/ThirdParty/GCC/Xtensa_ESP32/include/FreeRTOSConfig_arch.h create mode 100644 portable/ThirdParty/GCC/Xtensa_ESP32/include/port_systick.h create mode 100644 portable/ThirdParty/GCC/Xtensa_ESP32/port_common.c create mode 100644 portable/ThirdParty/GCC/Xtensa_ESP32/port_systick.c delete mode 100644 portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_intr.c delete mode 100644 portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_intr_asm.S diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/include/FreeRTOSConfig_arch.h b/portable/ThirdParty/GCC/Xtensa_ESP32/include/FreeRTOSConfig_arch.h new file mode 100644 index 000000000..cbc46d5fe --- /dev/null +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/include/FreeRTOSConfig_arch.h @@ -0,0 +1,134 @@ +/* + * SPDX-FileCopyrightText: 2022 Amazon.com, Inc. or its affiliates + * + * SPDX-License-Identifier: MIT + * + * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + */ +/* + * FreeRTOS Kernel V10.4.3 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. If you wish to use our Amazon + * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_XTENSA_H +#define FREERTOS_CONFIG_XTENSA_H + +#include "sdkconfig.h" + +/* enable use of optimized task selection by the scheduler */ +#if defined (CONFIG_FREERTOS_OPTIMIZED_SCHEDULER) && !defined(configUSE_PORT_OPTIMISED_TASK_SELECTION) +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#endif + +#define XT_USE_THREAD_SAFE_CLIB 0 +#undef XT_USE_SWPRI + +#if CONFIG_FREERTOS_CORETIMER_0 +#define XT_TIMER_INDEX 0 +#elif CONFIG_FREERTOS_CORETIMER_1 +#define XT_TIMER_INDEX 1 +#endif + +#ifndef __ASSEMBLER__ +/** + * This function is defined to provide a deprecation warning whenever + * XT_CLOCK_FREQ macro is used. + * Update the code to use esp_clk_cpu_freq function instead. + * @return current CPU clock frequency, in Hz + */ +int xt_clock_freq(void) __attribute__((deprecated)); + +#define XT_CLOCK_FREQ (xt_clock_freq()) + +#endif // __ASSEMBLER__ + +/* Required for configuration-dependent settings */ +#include + +/* configASSERT behaviour */ +#ifndef __ASSEMBLER__ +#include +#include "esp_rom_sys.h" +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/ets_sys.h" // will be removed in idf v5.0 +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/ets_sys.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/rom/ets_sys.h" +#endif +#endif // __ASSEMBLER__ + +// If CONFIG_FREERTOS_ASSERT_DISABLE is set then configASSERT is defined empty later in FreeRTOS.h and the macro +// configASSERT_DEFINED remains unset (meaning some warnings are avoided) +#ifdef configASSERT +#undef configASSERT +#if defined(CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE) +#define configASSERT(a) if (unlikely(!(a))) { \ + esp_rom_printf("%s:%d (%s)- assert failed!\n", __FILE__, __LINE__, \ + __FUNCTION__); \ + } +#elif defined(CONFIG_FREERTOS_ASSERT_FAIL_ABORT) +#define configASSERT(a) assert(a) +#endif +#endif + +#if CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION +#define UNTESTED_FUNCTION() { esp_rom_printf("Untested FreeRTOS function %s\r\n", __FUNCTION__); configASSERT(false); } while(0) +#else +#define UNTESTED_FUNCTION() +#endif + +#define configXT_BOARD 1 /* Board mode */ +#define configXT_SIMULATOR 0 + +/* The maximum interrupt priority from which FreeRTOS.org API functions can + be called. Only API functions that end in ...FromISR() can be used within + interrupts. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY XCHAL_EXCM_LEVEL + +/* Stack alignment, architecture specifc. Must be a power of two. */ +#define configSTACK_ALIGNMENT 16 + + +/* The Xtensa port uses a separate interrupt stack. Adjust the stack size + * to suit the needs of your specific application. + * Size needs to be aligned to the stack increment, since the location of + * the stack for the 2nd CPU will be calculated using configISR_STACK_SIZE. + */ +#ifndef configISR_STACK_SIZE +#define configISR_STACK_SIZE ((CONFIG_FREERTOS_ISR_STACKSIZE + configSTACK_ALIGNMENT - 1) & (~(configSTACK_ALIGNMENT - 1))) +#endif + +#ifndef __ASSEMBLER__ +#if CONFIG_APPTRACE_SV_ENABLE +extern uint32_t port_switch_flag[]; +#define os_task_switch_is_pended(_cpu_) (port_switch_flag[_cpu_]) +#else +#define os_task_switch_is_pended(_cpu_) (false) +#endif +#endif + +#endif // FREERTOS_CONFIG_XTENSA_H diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/include/port_systick.h b/portable/ThirdParty/GCC/Xtensa_ESP32/include/port_systick.h new file mode 100644 index 000000000..18b47f315 --- /dev/null +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/include/port_systick.h @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Set up the SysTick interrupt + */ +void vPortSetupTimer(void); + +#ifdef __cplusplus +} +#endif diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/include/portmacro.h b/portable/ThirdParty/GCC/Xtensa_ESP32/include/portmacro.h index 7a3c1acd9..392196c8e 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/include/portmacro.h +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/include/portmacro.h @@ -74,12 +74,20 @@ #include #include /* required for XSHAL_CLIB */ #include + #include "soc/spinlock.h" #include "esp_timer.h" /* required for FreeRTOS run time stats */ #include "esp_system.h" #include "esp_idf_version.h" + #include "esp_heap_caps.h" + /* TODO: Resolve build warnings generated due to this header inclusion */ + #include "hal/cpu_hal.h" - #include + /* TODO: These includes are not directly used in this file. They are kept into to prevent a breaking change. Remove these. */ + #include + #include + + #include "soc/cpu.h" #include "soc/soc_memory_layout.h" #if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)) #include "soc/compare_set.h" @@ -127,54 +135,12 @@ #include "esp_attr.h" /* "mux" data structure (spinlock) */ - typedef struct - { - /* owner field values: - * 0 - Uninitialized (invalid) - * portMUX_FREE_VAL - Mux is free, can be locked by either CPU - * CORE_ID_REGVAL_PRO / CORE_ID_REGVAL_APP - Mux is locked to the particular core - * - * Any value other than portMUX_FREE_VAL, CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP indicates corruption - */ - uint32_t owner; - - /* count field: - * If mux is unlocked, count should be zero. - * If mux is locked, count is non-zero & represents the number of recursive locks on the mux. - */ - uint32_t count; - #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG - const char * lastLockedFn; - int lastLockedLine; - #endif - } portMUX_TYPE; - - #define portMUX_FREE_VAL 0xB33FFFFF - -/* Special constants for vPortCPUAcquireMutexTimeout() */ - #define portMUX_NO_TIMEOUT ( -1 ) /* When passed for 'timeout_cycles', spin forever if necessary */ - #define portMUX_TRY_LOCK 0 /* Try to acquire the spinlock a single time only */ - -/* Keep this in sync with the portMUX_TYPE struct definition please. */ - #ifndef CONFIG_FREERTOS_PORTMUX_DEBUG - #define portMUX_INITIALIZER_UNLOCKED \ - { \ - .owner = portMUX_FREE_VAL, \ - .count = 0, \ - } - #else - #define portMUX_INITIALIZER_UNLOCKED \ - { \ - .owner = portMUX_FREE_VAL, \ - .count = 0, \ - .lastLockedFn = "(never locked)", \ - .lastLockedLine = -1 \ - } - #endif /* ifndef CONFIG_FREERTOS_PORTMUX_DEBUG */ - - - #define portASSERT_IF_IN_ISR() vPortAssertIfInISR() - void vPortAssertIfInISR(); + typedef spinlock_t portMUX_TYPE; /**< Spinlock type used by FreeRTOS critical sections */ + #define portMUX_INITIALIZER_UNLOCKED SPINLOCK_INITIALIZER /**< Spinlock initializer */ + #define portMUX_FREE_VAL SPINLOCK_FREE /**< Spinlock is free. [refactor-todo] check if this is still required */ + #define portMUX_NO_TIMEOUT SPINLOCK_WAIT_FOREVER /**< When passed for 'timeout_cycles', spin forever if necessary. [refactor-todo] check if this is still required */ + #define portMUX_TRY_LOCK SPINLOCK_NO_WAIT /**< Try to acquire the spinlock a single time only. [refactor-todo] check if this is still required */ + #define portMUX_INITIALIZE(mux) spinlock_initialize(mux) /*< Initialize a spinlock to its unlocked state */ #define portCRITICAL_NESTING_IN_TCB 1 @@ -200,7 +166,7 @@ * This all assumes that interrupts are either entirely disabled or enabled. Interrupt priority levels * will break this scheme. * - * Remark: For the ESP32, portENTER_CRITICAL and portENTER_CRITICAL_ISR both alias vTaskEnterCritical, meaning + * Remark: For the ESP32, portENTER_CRITICAL and portENTER_CRITICAL_ISR both alias vPortEnterCritical, meaning * that either function can be called both from ISR as well as task context. This is not standard FreeRTOS * behaviour; please keep this in mind if you need any compatibility with other FreeRTOS implementations. */ @@ -255,6 +221,8 @@ } \ } while( 0 ) + #define portASSERT_IF_IN_ISR() vPortAssertIfInISR() + void vPortAssertIfInISR(void); /* Critical section management. NW-TODO: replace XTOS_SET_INTLEVEL with more efficient version, if any? */ /* These cannot be nested. They should be used with a lot of care and cannot be called from interrupt level. */ @@ -266,18 +234,22 @@ /* Cleaner solution allows nested interrupts disabling and restoring via local registers or stack. */ /* They can be called from interrupts too. */ /* WARNING: Only applies to current CPU. See notes above. */ - static inline unsigned portENTER_CRITICAL_NESTED() + static inline UBaseType_t __attribute__( ( always_inline ) ) xPortSetInterruptMaskFromISR( void ) { - unsigned state = XTOS_SET_INTLEVEL( XCHAL_EXCM_LEVEL ); - + UBaseType_t prev_int_level = XTOS_SET_INTLEVEL( XCHAL_EXCM_LEVEL ); portbenchmarkINTERRUPT_DISABLE(); - return state; + return prev_int_level; + } + + static inline void __attribute__( ( always_inline ) ) vPortClearInterruptMaskFromISR( UBaseType_t prev_level ) + { + portbenchmarkINTERRUPT_RESTORE( prev_level ); + XTOS_RESTORE_JUST_INTLEVEL( prev_level ); } - #define portEXIT_CRITICAL_NESTED( state ) do { portbenchmarkINTERRUPT_RESTORE( state ); XTOS_RESTORE_JUST_INTLEVEL( state ); } while( 0 ) /* These FreeRTOS versions are similar to the nested versions above */ - #define portSET_INTERRUPT_MASK_FROM_ISR() portENTER_CRITICAL_NESTED() - #define portCLEAR_INTERRUPT_MASK_FROM_ISR( state ) portEXIT_CRITICAL_NESTED( state ) + #define portSET_INTERRUPT_MASK_FROM_ISR() xPortSetInterruptMaskFromISR() + #define portCLEAR_INTERRUPT_MASK_FROM_ISR( prev_level ) vPortClearInterruptMaskFromISR( prev_level ) /*Because the ROM routines don't necessarily handle a stack in external RAM correctly, we force */ /*the stack memory to always be internal. */ @@ -352,7 +324,7 @@ #else static inline void uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set) { - #if defined(CONFIG_ESP32_SPIRAM_SUPPORT) + #if defined(CONFIG_SPIRAM) compare_and_set_extram(addr, compare, set); #endif } @@ -374,18 +346,47 @@ #ifdef CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER /* Coarse resolution time (us) */ - #define portALT_GET_RUN_TIME_COUNTER_VALUE( x ) x = ( uint32_t ) esp_timer_get_time() + #define portALT_GET_RUN_TIME_COUNTER_VALUE( x ) do { x = ( uint32_t )esp_timer_get_time(); } while( 0 ) #endif /* Kernel utilities. */ void vPortYield( void ); + void vPortEvaluateYieldFromISR( int argc, ... ); void _frxt_setup_switch( void ); - #define portYIELD() vPortYield() - #define portYIELD_FROM_ISR() { traceISR_EXIT_TO_SCHEDULER(); _frxt_setup_switch(); } +/* Macro to count number of arguments of a __VA_ARGS__ used to support portYIELD_FROM_ISR with, + * or without arguments. The macro counts only 0 or 1 arguments. + * + * In the future, we want to switch to C++20. We also want to become compatible with clang. + * Hence, we provide two versions of the following macros which are using variadic arguments. + * The first one is using the GNU extension ##__VA_ARGS__. The second one is using the C++20 feature __VA_OPT__(,). + * This allows users to compile their code with standard C++20 enabled instead of the GNU extension. + * Below C++20, we haven't found any good alternative to using ##__VA_ARGS__. + */ + #if defined( __cplusplus ) && ( __cplusplus > 201703L ) + #define portGET_ARGUMENT_COUNT(...) portGET_ARGUMENT_COUNT_INNER( 0 __VA_OPT__(,) __VA_ARGS__, 1 , 0 ) + #else + #define portGET_ARGUMENT_COUNT(...) portGET_ARGUMENT_COUNT_INNER( 0, ##__VA_ARGS__, 1, 0 ) + #endif + #define portGET_ARGUMENT_COUNT_INNER( zero, one, count, ... ) count - static inline uint32_t xPortGetCoreID(); + _Static_assert( portGET_ARGUMENT_COUNT() == 0, "portGET_ARGUMENT_COUNT() result does not match for 0 arguments" ); + _Static_assert( portGET_ARGUMENT_COUNT( 1 ) == 1, "portGET_ARGUMENT_COUNT() result does not match for 1 argument" ); + + #define portYIELD() vPortYield() + +/* The macro below could be used when passing a single argument, or without any argument, + * it was developed to support both usages of portYIELD inside of an ISR. Any other usage form + * might result in undesired behaviour + */ + #if defined( __cplusplus ) && ( __cplusplus > 201703L ) + #define portYIELD_FROM_ISR(...) vPortEvaluateYieldFromISR( portGET_ARGUMENT_COUNT( __VA_ARGS__ ) __VA_OPT__( , ) __VA_ARGS__ ) + #else + #define portYIELD_FROM_ISR(...) vPortEvaluateYieldFromISR( portGET_ARGUMENT_COUNT( __VA_ARGS__ ), ##__VA_ARGS__ ) + #endif + + static inline BaseType_t xPortGetCoreID(); /*-----------------------------------------------------------*/ @@ -428,10 +429,11 @@ #endif void vApplicationSleep( TickType_t xExpectedIdleTime ); - void vPortSetStackWatchpoint( void* pxStackStart ); #define portSUPPRESS_TICKS_AND_SLEEP( idleTime ) vApplicationSleep( idleTime ) + void _xt_coproc_release( volatile void * coproc_sa_base ); + /*-----------------------------------------------------------*/ #if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)) @@ -458,10 +460,6 @@ /*-----------------------------------------------------------*/ - - void _xt_coproc_release( volatile void * coproc_sa_base ); - - /* * Map to the memory management routines required for the port. * @@ -520,20 +518,31 @@ #endif /* Multi-core: get current core ID */ - static inline uint32_t IRAM_ATTR xPortGetCoreID() + static inline BaseType_t IRAM_ATTR xPortGetCoreID() { - int id; - - asm ( - "rsr.prid %0\n" - " extui %0,%0,13,1" - : "=r" ( id ) ); - return id; + return ( uint32_t )cpu_hal_get_core_id(); } /* Get tick rate per second */ uint32_t xPortGetTickRateHz( void ); + static inline bool IRAM_ATTR xPortCanYield(void) + { + uint32_t ps_reg = 0; + + //Get the current value of PS (processor status) register + RSR(PS, ps_reg); + + /* + * intlevel = (ps_reg & 0xf); + * excm = (ps_reg >> 4) & 0x1; + * CINTLEVEL is max(excm * EXCMLEVEL, INTLEVEL), where EXCMLEVEL is 3. + * However, just return true, only intlevel is zero. + */ + + return ((ps_reg & PS_INTLEVEL_MASK) == 0); + } + /* porttrace */ #if configUSE_TRACE_FACILITY_2 #include "porttrace.h" diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/include/xtensa_api.h b/portable/ThirdParty/GCC/Xtensa_ESP32/include/xtensa_api.h index aeade0453..aaa8ccd45 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/include/xtensa_api.h +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/include/xtensa_api.h @@ -27,113 +27,4 @@ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - -/****************************************************************************** -* Xtensa-specific API for RTOS ports. -******************************************************************************/ - -#ifndef __XTENSA_API_H__ -#define __XTENSA_API_H__ - -#include - -#include "xtensa_context.h" - - -/* Typedef for C-callable interrupt handler function */ -typedef void (* xt_handler)( void * ); - -/* Typedef for C-callable exception handler function */ -typedef void (* xt_exc_handler)( XtExcFrame * ); - - -/* - * ------------------------------------------------------------------------------- - * Call this function to set a handler for the specified exception. The handler - * will be installed on the core that calls this function. - * - * n - Exception number (type) - * f - Handler function address, NULL to uninstall handler. - * - * The handler will be passed a pointer to the exception frame, which is created - * on the stack of the thread that caused the exception. - * - * If the handler returns, the thread context will be restored and the faulting - * instruction will be retried. Any values in the exception frame that are - * modified by the handler will be restored as part of the context. For details - * of the exception frame structure see xtensa_context.h. - * ------------------------------------------------------------------------------- - */ -extern xt_exc_handler xt_set_exception_handler( int n, - xt_exc_handler f ); - - -/* - * ------------------------------------------------------------------------------- - * Call this function to set a handler for the specified interrupt. The handler - * will be installed on the core that calls this function. - * - * n - Interrupt number. - * f - Handler function address, NULL to uninstall handler. - * arg - Argument to be passed to handler. - * ------------------------------------------------------------------------------- - */ -extern xt_handler xt_set_interrupt_handler( int n, - xt_handler f, - void * arg ); - - -/* - * ------------------------------------------------------------------------------- - * Call this function to enable the specified interrupts on the core that runs - * this code. - * - * mask - Bit mask of interrupts to be enabled. - * ------------------------------------------------------------------------------- - */ -extern void xt_ints_on( unsigned int mask ); - - -/* - * ------------------------------------------------------------------------------- - * Call this function to disable the specified interrupts on the core that runs - * this code. - * - * mask - Bit mask of interrupts to be disabled. - * ------------------------------------------------------------------------------- - */ -extern void xt_ints_off( unsigned int mask ); - - -/* - * ------------------------------------------------------------------------------- - * Call this function to set the specified (s/w) interrupt. - * ------------------------------------------------------------------------------- - */ -static inline void xt_set_intset( unsigned int arg ) -{ - xthal_set_intset( arg ); -} - - -/* - * ------------------------------------------------------------------------------- - * Call this function to clear the specified (s/w or edge-triggered) - * interrupt. - * ------------------------------------------------------------------------------- - */ -static inline void xt_set_intclear( unsigned int arg ) -{ - xthal_set_intclear( arg ); -} - -/* - * ------------------------------------------------------------------------------- - * Call this function to get handler's argument for the specified interrupt. - * - * n - Interrupt number. - * ------------------------------------------------------------------------------- - */ -extern void * xt_get_interrupt_handler_arg( int n ); - -#endif /* __XTENSA_API_H__ */ +#include diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/include/xtensa_context.h b/portable/ThirdParty/GCC/Xtensa_ESP32/include/xtensa_context.h index 100165065..fc24748c4 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/include/xtensa_context.h +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/include/xtensa_context.h @@ -27,373 +27,4 @@ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - -/******************************************************************************* - - XTENSA CONTEXT FRAMES AND MACROS FOR RTOS ASSEMBLER SOURCES - -This header contains definitions and macros for use primarily by Xtensa -RTOS assembly coded source files. It includes and uses the Xtensa hardware -abstraction layer (HAL) to deal with config specifics. It may also be -included in C source files. - -!! Supports only Xtensa Exception Architecture 2 (XEA2). XEA1 not supported. !! - -NOTE: The Xtensa architecture requires stack pointer alignment to 16 bytes. - -*******************************************************************************/ - -#ifndef XTENSA_CONTEXT_H -#define XTENSA_CONTEXT_H - -#ifdef __ASSEMBLER__ -#include -#endif - -#include -#include -#include -#include -#include - - -/* Align a value up to nearest n-byte boundary, where n is a power of 2. */ -#define ALIGNUP(n, val) (((val) + (n)-1) & -(n)) - - -/* -------------------------------------------------------------------------------- - Macros that help define structures for both C and assembler. -------------------------------------------------------------------------------- -*/ - -#ifdef STRUCT_BEGIN -#undef STRUCT_BEGIN -#undef STRUCT_FIELD -#undef STRUCT_AFIELD -#undef STRUCT_END -#endif - -#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) - -#define STRUCT_BEGIN .pushsection .text; .struct 0 -#define STRUCT_FIELD(ctype,size,asname,name) asname: .space size -#define STRUCT_AFIELD(ctype,size,asname,name,n) asname: .space (size)*(n) -#define STRUCT_END(sname) sname##Size:; .popsection - -#else - -#define STRUCT_BEGIN typedef struct { -#define STRUCT_FIELD(ctype,size,asname,name) ctype name; -#define STRUCT_AFIELD(ctype,size,asname,name,n) ctype name[n]; -#define STRUCT_END(sname) } sname; - -#endif //_ASMLANGUAGE || __ASSEMBLER__ - - -/* -------------------------------------------------------------------------------- - INTERRUPT/EXCEPTION STACK FRAME FOR A THREAD OR NESTED INTERRUPT - - A stack frame of this structure is allocated for any interrupt or exception. - It goes on the current stack. If the RTOS has a system stack for handling - interrupts, every thread stack must allow space for just one interrupt stack - frame, then nested interrupt stack frames go on the system stack. - - The frame includes basic registers (explicit) and "extra" registers introduced - by user TIE or the use of the MAC16 option in the user's Xtensa config. - The frame size is minimized by omitting regs not applicable to user's config. - - For Windowed ABI, this stack frame includes the interruptee's base save area, - another base save area to manage gcc nested functions, and a little temporary - space to help manage the spilling of the register windows. -------------------------------------------------------------------------------- -*/ - -STRUCT_BEGIN -STRUCT_FIELD (long, 4, XT_STK_EXIT, exit) /* exit point for dispatch */ -STRUCT_FIELD (long, 4, XT_STK_PC, pc) /* return PC */ -STRUCT_FIELD (long, 4, XT_STK_PS, ps) /* return PS */ -STRUCT_FIELD (long, 4, XT_STK_A0, a0) -STRUCT_FIELD (long, 4, XT_STK_A1, a1) /* stack pointer before interrupt */ -STRUCT_FIELD (long, 4, XT_STK_A2, a2) -STRUCT_FIELD (long, 4, XT_STK_A3, a3) -STRUCT_FIELD (long, 4, XT_STK_A4, a4) -STRUCT_FIELD (long, 4, XT_STK_A5, a5) -STRUCT_FIELD (long, 4, XT_STK_A6, a6) -STRUCT_FIELD (long, 4, XT_STK_A7, a7) -STRUCT_FIELD (long, 4, XT_STK_A8, a8) -STRUCT_FIELD (long, 4, XT_STK_A9, a9) -STRUCT_FIELD (long, 4, XT_STK_A10, a10) -STRUCT_FIELD (long, 4, XT_STK_A11, a11) -STRUCT_FIELD (long, 4, XT_STK_A12, a12) -STRUCT_FIELD (long, 4, XT_STK_A13, a13) -STRUCT_FIELD (long, 4, XT_STK_A14, a14) -STRUCT_FIELD (long, 4, XT_STK_A15, a15) -STRUCT_FIELD (long, 4, XT_STK_SAR, sar) -STRUCT_FIELD (long, 4, XT_STK_EXCCAUSE, exccause) -STRUCT_FIELD (long, 4, XT_STK_EXCVADDR, excvaddr) -#if XCHAL_HAVE_LOOPS -STRUCT_FIELD (long, 4, XT_STK_LBEG, lbeg) -STRUCT_FIELD (long, 4, XT_STK_LEND, lend) -STRUCT_FIELD (long, 4, XT_STK_LCOUNT, lcount) -#endif -#ifndef __XTENSA_CALL0_ABI__ -/* Temporary space for saving stuff during window spill */ -STRUCT_FIELD (long, 4, XT_STK_TMP0, tmp0) -STRUCT_FIELD (long, 4, XT_STK_TMP1, tmp1) -STRUCT_FIELD (long, 4, XT_STK_TMP2, tmp2) -#endif -#ifdef XT_USE_SWPRI -/* Storage for virtual priority mask */ -STRUCT_FIELD (long, 4, XT_STK_VPRI, vpri) -#endif -#ifdef XT_USE_OVLY -/* Storage for overlay state */ -STRUCT_FIELD (long, 4, XT_STK_OVLY, ovly) -#endif -STRUCT_END(XtExcFrame) - -#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__) -#define XT_STK_NEXT1 XtExcFrameSize -#else -#define XT_STK_NEXT1 sizeof(XtExcFrame) -#endif - -/* Allocate extra storage if needed */ -#if XCHAL_EXTRA_SA_SIZE != 0 - -#if XCHAL_EXTRA_SA_ALIGN <= 16 -#define XT_STK_EXTRA ALIGNUP(XCHAL_EXTRA_SA_ALIGN, XT_STK_NEXT1) -#else -/* If need more alignment than stack, add space for dynamic alignment */ -#define XT_STK_EXTRA (ALIGNUP(XCHAL_EXTRA_SA_ALIGN, XT_STK_NEXT1) + XCHAL_EXTRA_SA_ALIGN) -#endif -#define XT_STK_NEXT2 (XT_STK_EXTRA + XCHAL_EXTRA_SA_SIZE) - -#else - -#define XT_STK_NEXT2 XT_STK_NEXT1 - -#endif - -/* -------------------------------------------------------------------------------- - This is the frame size. Add space for 4 registers (interruptee's base save - area) and some space for gcc nested functions if any. -------------------------------------------------------------------------------- -*/ -#define XT_STK_FRMSZ (ALIGNUP(0x10, XT_STK_NEXT2) + 0x20) - - -/* -------------------------------------------------------------------------------- - SOLICITED STACK FRAME FOR A THREAD - - A stack frame of this structure is allocated whenever a thread enters the - RTOS kernel intentionally (and synchronously) to submit to thread scheduling. - It goes on the current thread's stack. - - The solicited frame only includes registers that are required to be preserved - by the callee according to the compiler's ABI conventions, some space to save - the return address for returning to the caller, and the caller's PS register. - - For Windowed ABI, this stack frame includes the caller's base save area. - - Note on XT_SOL_EXIT field: - It is necessary to distinguish a solicited from an interrupt stack frame. - This field corresponds to XT_STK_EXIT in the interrupt stack frame and is - always at the same offset (0). It can be written with a code (usually 0) - to distinguish a solicted frame from an interrupt frame. An RTOS port may - opt to ignore this field if it has another way of distinguishing frames. -------------------------------------------------------------------------------- -*/ - -STRUCT_BEGIN -#ifdef __XTENSA_CALL0_ABI__ -STRUCT_FIELD (long, 4, XT_SOL_EXIT, exit) -STRUCT_FIELD (long, 4, XT_SOL_PC, pc) -STRUCT_FIELD (long, 4, XT_SOL_PS, ps) -STRUCT_FIELD (long, 4, XT_SOL_NEXT, next) -STRUCT_FIELD (long, 4, XT_SOL_A12, a12) /* should be on 16-byte alignment */ -STRUCT_FIELD (long, 4, XT_SOL_A13, a13) -STRUCT_FIELD (long, 4, XT_SOL_A14, a14) -STRUCT_FIELD (long, 4, XT_SOL_A15, a15) -#else -STRUCT_FIELD (long, 4, XT_SOL_EXIT, exit) -STRUCT_FIELD (long, 4, XT_SOL_PC, pc) -STRUCT_FIELD (long, 4, XT_SOL_PS, ps) -STRUCT_FIELD (long, 4, XT_SOL_NEXT, next) -STRUCT_FIELD (long, 4, XT_SOL_A0, a0) /* should be on 16-byte alignment */ -STRUCT_FIELD (long, 4, XT_SOL_A1, a1) -STRUCT_FIELD (long, 4, XT_SOL_A2, a2) -STRUCT_FIELD (long, 4, XT_SOL_A3, a3) -#endif -STRUCT_END(XtSolFrame) - -/* Size of solicited stack frame */ -#define XT_SOL_FRMSZ ALIGNUP(0x10, XtSolFrameSize) - - -/* -------------------------------------------------------------------------------- - CO-PROCESSOR STATE SAVE AREA FOR A THREAD - - The RTOS must provide an area per thread to save the state of co-processors - when that thread does not have control. Co-processors are context-switched - lazily (on demand) only when a new thread uses a co-processor instruction, - otherwise a thread retains ownership of the co-processor even when it loses - control of the processor. An Xtensa co-processor exception is triggered when - any co-processor instruction is executed by a thread that is not the owner, - and the context switch of that co-processor is then peformed by the handler. - Ownership represents which thread's state is currently in the co-processor. - - Co-processors may not be used by interrupt or exception handlers. If an - co-processor instruction is executed by an interrupt or exception handler, - the co-processor exception handler will trigger a kernel panic and freeze. - This restriction is introduced to reduce the overhead of saving and restoring - co-processor state (which can be quite large) and in particular remove that - overhead from interrupt handlers. - - The co-processor state save area may be in any convenient per-thread location - such as in the thread control block or above the thread stack area. It need - not be in the interrupt stack frame since interrupts don't use co-processors. - - Along with the save area for each co-processor, two bitmasks with flags per - co-processor (laid out as in the CPENABLE reg) help manage context-switching - co-processors as efficiently as possible: - - XT_CPENABLE - The contents of a non-running thread's CPENABLE register. - It represents the co-processors owned (and whose state is still needed) - by the thread. When a thread is preempted, its CPENABLE is saved here. - When a thread solicits a context-swtich, its CPENABLE is cleared - the - compiler has saved the (caller-saved) co-proc state if it needs to. - When a non-running thread loses ownership of a CP, its bit is cleared. - When a thread runs, it's XT_CPENABLE is loaded into the CPENABLE reg. - Avoids co-processor exceptions when no change of ownership is needed. - - XT_CPSTORED - A bitmask with the same layout as CPENABLE, a bit per co-processor. - Indicates whether the state of each co-processor is saved in the state - save area. When a thread enters the kernel, only the state of co-procs - still enabled in CPENABLE is saved. When the co-processor exception - handler assigns ownership of a co-processor to a thread, it restores - the saved state only if this bit is set, and clears this bit. - - XT_CP_CS_ST - A bitmask with the same layout as CPENABLE, a bit per co-processor. - Indicates whether callee-saved state is saved in the state save area. - Callee-saved state is saved by itself on a solicited context switch, - and restored when needed by the coprocessor exception handler. - Unsolicited switches will cause the entire coprocessor to be saved - when necessary. - - XT_CP_ASA - Pointer to the aligned save area. Allows it to be aligned more than - the overall save area (which might only be stack-aligned or TCB-aligned). - Especially relevant for Xtensa cores configured with a very large data - path that requires alignment greater than 16 bytes (ABI stack alignment). -------------------------------------------------------------------------------- -*/ - -#if XCHAL_CP_NUM > 0 - -/* Offsets of each coprocessor save area within the 'aligned save area': */ -#define XT_CP0_SA 0 -#define XT_CP1_SA ALIGNUP(XCHAL_CP1_SA_ALIGN, XT_CP0_SA + XCHAL_CP0_SA_SIZE) -#define XT_CP2_SA ALIGNUP(XCHAL_CP2_SA_ALIGN, XT_CP1_SA + XCHAL_CP1_SA_SIZE) -#define XT_CP3_SA ALIGNUP(XCHAL_CP3_SA_ALIGN, XT_CP2_SA + XCHAL_CP2_SA_SIZE) -#define XT_CP4_SA ALIGNUP(XCHAL_CP4_SA_ALIGN, XT_CP3_SA + XCHAL_CP3_SA_SIZE) -#define XT_CP5_SA ALIGNUP(XCHAL_CP5_SA_ALIGN, XT_CP4_SA + XCHAL_CP4_SA_SIZE) -#define XT_CP6_SA ALIGNUP(XCHAL_CP6_SA_ALIGN, XT_CP5_SA + XCHAL_CP5_SA_SIZE) -#define XT_CP7_SA ALIGNUP(XCHAL_CP7_SA_ALIGN, XT_CP6_SA + XCHAL_CP6_SA_SIZE) -#define XT_CP_SA_SIZE ALIGNUP(16, XT_CP7_SA + XCHAL_CP7_SA_SIZE) - -/* Offsets within the overall save area: */ -#define XT_CPENABLE 0 /* (2 bytes) coprocessors active for this thread */ -#define XT_CPSTORED 2 /* (2 bytes) coprocessors saved for this thread */ -#define XT_CP_CS_ST 4 /* (2 bytes) coprocessor callee-saved regs stored for this thread */ -#define XT_CP_ASA 8 /* (4 bytes) ptr to aligned save area */ -/* Overall size allows for dynamic alignment: */ -#define XT_CP_SIZE (12 + XT_CP_SA_SIZE + XCHAL_TOTAL_SA_ALIGN) -#else -#define XT_CP_SIZE 0 -#endif - - -/* - Macro to get the current core ID. Only uses the reg given as an argument. - Reading PRID on the ESP32 gives us 0xCDCD on the PRO processor (0) - and 0xABAB on the APP CPU (1). We can distinguish between the two by checking - bit 13: it's 1 on the APP and 0 on the PRO processor. -*/ -#ifdef __ASSEMBLER__ - .macro getcoreid reg - rsr.prid \reg - extui \reg,\reg,13,1 - .endm -#endif - -#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0)) -#define CORE_ID_PRO 0xCDCD -#define CORE_ID_APP 0xABAB -#else -#define CORE_ID_REGVAL_PRO 0xCDCD -#define CORE_ID_REGVAL_APP 0xABAB - -/* Included for compatibility, recommend using CORE_ID_REGVAL_PRO instead */ -#define CORE_ID_PRO CORE_ID_REGVAL_PRO - -/* Included for compatibility, recommend using CORE_ID_REGVAL_APP instead */ -#define CORE_ID_APP CORE_ID_REGVAL_APP -#endif - -/* -------------------------------------------------------------------------------- - MACROS TO HANDLE ABI SPECIFICS OF FUNCTION ENTRY AND RETURN - - Convenient where the frame size requirements are the same for both ABIs. - ENTRY(sz), RET(sz) are for framed functions (have locals or make calls). - ENTRY0, RET0 are for frameless functions (no locals, no calls). - - where size = size of stack frame in bytes (must be >0 and aligned to 16). - For framed functions the frame is created and the return address saved at - base of frame (Call0 ABI) or as determined by hardware (Windowed ABI). - For frameless functions, there is no frame and return address remains in a0. - Note: Because CPP macros expand to a single line, macros requiring multi-line - expansions are implemented as assembler macros. -------------------------------------------------------------------------------- -*/ - -#ifdef __ASSEMBLER__ -#ifdef __XTENSA_CALL0_ABI__ - /* Call0 */ - #define ENTRY(sz) entry1 sz - .macro entry1 size=0x10 - addi sp, sp, -\size - s32i a0, sp, 0 - .endm - #define ENTRY0 - #define RET(sz) ret1 sz - .macro ret1 size=0x10 - l32i a0, sp, 0 - addi sp, sp, \size - ret - .endm - #define RET0 ret -#else - /* Windowed */ - #define ENTRY(sz) entry sp, sz - #define ENTRY0 entry sp, 0x10 - #define RET(sz) retw - #define RET0 retw -#endif -#endif - - - - - -#endif /* XTENSA_CONTEXT_H */ - +#include diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/include/xtensa_rtos.h b/portable/ThirdParty/GCC/Xtensa_ESP32/include/xtensa_rtos.h index fde7fccdd..4fe4483dd 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/include/xtensa_rtos.h +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/include/xtensa_rtos.h @@ -59,7 +59,7 @@ #include #include - +#include "sdkconfig.h" /* * Include any RTOS specific definitions that are needed by this header. */ @@ -154,7 +154,9 @@ * RTOS may optionally define XT_TICK_PER_SEC in its own way (eg. macro). */ /* void XT_RTOS_TIMER_INT(void) */ -#define XT_RTOS_TIMER_INT _frxt_timer_int +#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT +#define XT_RTOS_TIMER_INT _frxt_timer_int +#endif #define XT_TICK_PER_SEC configTICK_RATE_HZ /* diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/port.c b/portable/ThirdParty/GCC/Xtensa_ESP32/port.c index 767559150..00674744e 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/port.c +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/port.c @@ -1,5 +1,6 @@ /* * SPDX-FileCopyrightText: 2020 Amazon.com, Inc. or its affiliates + * SPDX-FileCopyrightText: 2015-2019 Cadence Design Systems, Inc. * * SPDX-License-Identifier: MIT * @@ -32,32 +33,31 @@ * * 1 tab == 4 spaces! */ - -/******************************************************************************* - * // Copyright (c) 2003-2015 Cadence Design Systems, Inc. - * // - * // Permission is hereby granted, free of charge, to any person obtaining - * // a copy of this software and associated documentation files (the - * // "Software"), to deal in the Software without restriction, including - * // without limitation the rights to use, copy, modify, merge, publish, - * // distribute, sublicense, and/or sell copies of the Software, and to - * // permit persons to whom the Software is furnished to do so, subject to - * // the following conditions: - * // - * // The above copyright notice and this permission notice shall be included - * // in all copies or substantial portions of the Software. - * // - * // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * ----------------------------------------------------------------------------- +/* + * Copyright (c) 2015-2019 Cadence Design Systems, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include +#include #include #include "xtensa_rtos.h" @@ -68,7 +68,9 @@ #include "esp_panic.h" #include "esp_crosscore_int.h" #else -#if CONFIG_IDF_TARGET_ESP32S2 +#if CONFIG_IDF_TARGET_ESP32S3 + #include "esp32s3/rom/ets_sys.h" +#elif CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/rom/ets_sys.h" #elif CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/ets_sys.h" @@ -87,23 +89,16 @@ #include "esp_intr_alloc.h" -/* Defined in portasm.h */ -extern void _frxt_tick_timer_init( void ); +#include "port_systick.h" /* Defined in xtensa_context.S */ extern void _xt_coproc_init( void ); - -#if CONFIG_FREERTOS_CORETIMER_0 - #define SYSTICK_INTR_ID ( ETS_INTERNAL_TIMER0_INTR_SOURCE + ETS_INTERNAL_INTR_SOURCE_OFF ) -#endif -#if CONFIG_FREERTOS_CORETIMER_1 - #define SYSTICK_INTR_ID ( ETS_INTERNAL_TIMER1_INTR_SOURCE + ETS_INTERNAL_INTR_SOURCE_OFF ) -#endif +_Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_AFFINITY value"); /*-----------------------------------------------------------*/ -unsigned port_xSchedulerRunning[ portNUM_PROCESSORS ] = { 0 }; /* Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting */ +extern volatile int port_xSchedulerRunning[portNUM_PROCESSORS]; unsigned port_interruptNesting[ portNUM_PROCESSORS ] = { 0 }; /* Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit */ /*-----------------------------------------------------------*/ @@ -148,8 +143,28 @@ void _xt_user_exit( void ); uint32_t * p; #endif + uint32_t * threadptr; + void * task_thread_local_start; + extern int _thread_local_start, _thread_local_end, _flash_rodata_start, _flash_rodata_align; + + /* TODO: check that TLS area fits the stack */ + uint32_t thread_local_sz = ( uint8_t * ) &_thread_local_end - ( uint8_t * ) &_thread_local_start; + + thread_local_sz = ALIGNUP( 0x10, thread_local_sz ); + + /* Initialize task's stack so that we have the following structure at the top: + + ----LOW ADDRESSES ----------------------------------------HIGH ADDRESSES---------- + task stack | interrupt stack frame | thread local vars | co-processor save area | + ---------------------------------------------------------------------------------- + | | + SP pxTopOfStack + + All parts are aligned to 16 byte boundary. + */ + /* Create interrupt stack frame aligned to 16 byte boundary */ - sp = ( StackType_t * ) ( ( ( UBaseType_t ) pxTopOfStack - XT_CP_SIZE - XT_STK_FRMSZ ) & ~0xf ); + sp = ( StackType_t * ) ( ( ( UBaseType_t ) pxTopOfStack - XT_CP_SIZE - thread_local_sz - XT_STK_FRMSZ ) & ~0xf ); /* Clear the entire frame (do not use memset() because we don't depend on C library) */ for( tp = sp; tp <= pxTopOfStack; ++tp ) @@ -195,6 +210,24 @@ void _xt_user_exit( void ); frame->vpri = 0xFFFFFFFF; #endif + /* Init threadptr register and set up TLS run-time area. */ + task_thread_local_start = ( void * ) ( ( ( uint32_t ) pxTopOfStack - XT_CP_SIZE - thread_local_sz ) & ~0xf ); + memcpy( task_thread_local_start, &_thread_local_start, thread_local_sz ); + threadptr = ( uint32_t * ) ( sp + XT_STK_EXTRA ); + + /* Calculate THREADPTR value. + * The generated code will add THREADPTR value to a constant value determined at link time, + * to get the address of the TLS variable. + * The constant value is calculated by the linker as follows + * (search for 'tpoff' in elf32-xtensa.c in BFD): + * offset = address - tls_section_vma + align_up(TCB_SIZE, tls_section_alignment) + * where TCB_SIZE is hardcoded to 8. + */ + const uint32_t tls_section_alignment = ( uint32_t ) &_flash_rodata_align; /* ALIGN value of .flash.rodata section */ + const uint32_t tcb_size = 8; /* Unrelated to FreeRTOS, this is the constant from BFD */ + const uint32_t base = ( tcb_size + tls_section_alignment - 1 ) & ( ~( tls_section_alignment - 1 ) ); + *threadptr = ( uint32_t ) task_thread_local_start - ( ( uint32_t ) &_thread_local_start - ( uint32_t ) &_flash_rodata_start ) - base; + #if XCHAL_CP_NUM > 0 /* Init the coprocessor save area (see xtensa_context.h) */ @@ -217,12 +250,14 @@ void vPortEndScheduler( void ) { /* It is unlikely that the Xtensa port will get stopped. If required simply * disable the tick interrupt here. */ + abort(); } /*-----------------------------------------------------------*/ BaseType_t xPortStartScheduler( void ) { + portDISABLE_INTERRUPTS(); /* Interrupts are disabled at this point and stack contains PS with enabled interrupts when task context is restored */ #if XCHAL_CP_NUM > 0 @@ -230,11 +265,21 @@ BaseType_t xPortStartScheduler( void ) _xt_coproc_init(); #endif - /* Init the tick divisor value */ - _xt_tick_divisor_init(); + /* Setup the hardware to generate the tick */ + vPortSetupTimer(); - /* Setup the hardware to generate the tick. */ - _frxt_tick_timer_init(); + /* NOTE: For ESP32-S3, vPortSetupTimer allocates an interrupt for the + * systimer which is used as the source for FreeRTOS systick. + * + * The behaviour of portEXIT_CRITICAL is different in FreeRTOS and ESP-IDF - + * the former enables the interrupts no matter what the state was at the beginning + * of the call while the latter restores the interrupt state to what was at the + * beginning of the call. + * + * This resulted in the interrupts being enabled before the _frxt_dispatch call, + * who was unable to switch context to the queued tasks. + */ + portDISABLE_INTERRUPTS(); port_xSchedulerRunning[ xPortGetCoreID() ] = 1; @@ -244,38 +289,9 @@ BaseType_t xPortStartScheduler( void ) /* Should not get here. */ return pdTRUE; } + /*-----------------------------------------------------------*/ -BaseType_t xPortSysTickHandler( void ) -{ - BaseType_t ret; - unsigned interruptMask; - - portbenchmarkIntLatency(); - traceISR_ENTER( SYSTICK_INTR_ID ); - - /* Interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY must be - * disabled before calling xTaskIncrementTick as it access the - * kernel lists. */ - interruptMask = portSET_INTERRUPT_MASK_FROM_ISR(); - { - ret = xTaskIncrementTick(); - } - portCLEAR_INTERRUPT_MASK_FROM_ISR( interruptMask ); - - if( ret != pdFALSE ) - { - portYIELD_FROM_ISR(); - } - else - { - traceISR_EXIT(); - } - - return ret; -} - - void vPortYieldOtherCore( BaseType_t coreid ) { esp_crosscore_int_send_yield( coreid ); @@ -297,7 +313,6 @@ void vPortYieldOtherCore( BaseType_t coreid ) xMPUSettings->coproc_area = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) xMPUSettings->coproc_area ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); xMPUSettings->coproc_area = ( StackType_t * ) ( ( ( uint32_t ) xMPUSettings->coproc_area - XT_CP_SIZE ) & ~0xf ); - /* NOTE: we cannot initialize the coprocessor save area here because FreeRTOS is going to * clear the stack area after we return. This is done in pxPortInitialiseStack(). */ @@ -321,9 +336,9 @@ BaseType_t xPortInIsrContext() unsigned int irqStatus; BaseType_t ret; - irqStatus = portENTER_CRITICAL_NESTED(); + irqStatus = portSET_INTERRUPT_MASK_FROM_ISR(); ret = ( port_interruptNesting[ xPortGetCoreID() ] != 0 ); - portEXIT_CRITICAL_NESTED( irqStatus ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus ); return ret; } @@ -336,11 +351,39 @@ BaseType_t IRAM_ATTR xPortInterruptedFromISRContext() return( port_interruptNesting[ xPortGetCoreID() ] != 0 ); } +void IRAM_ATTR vPortEvaluateYieldFromISR( int argc, ... ) +{ + BaseType_t xYield; + va_list ap; + va_start( ap, argc ); + + if( argc ) + { + xYield = ( BaseType_t )va_arg( ap, int ); + va_end( ap ); + } + else + { + //it is a empty parameter vPortYieldFromISR macro call: + va_end( ap ); + traceISR_EXIT_TO_SCHEDULER(); + _frxt_setup_switch(); + return; + } + + //Yield exists, so need evaluate it first then switch: + if( xYield == pdTRUE ) + { + traceISR_EXIT_TO_SCHEDULER(); + _frxt_setup_switch(); + } +} + void vPortAssertIfInISR() { if( xPortInIsrContext() ) { - ets_printf( "core=%d port_interruptNesting=%d\n\n", xPortGetCoreID(), port_interruptNesting[ xPortGetCoreID() ] ); + esp_rom_printf( "core=%d port_interruptNesting=%d\n\n", xPortGetCoreID(), port_interruptNesting[ xPortGetCoreID() ] ); } configASSERT( !xPortInIsrContext() ); @@ -352,7 +395,7 @@ void vPortAssertIfInISR() void vPortCPUInitializeMutex( portMUX_TYPE * mux ) { #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG - ets_printf( "Initializing mux %p\n", mux ); + esp_rom_printf( "Initializing mux %p\n", mux ); mux->lastLockedFn = "(never locked)"; mux->lastLockedLine = -1; #endif @@ -370,10 +413,10 @@ void vPortCPUInitializeMutex( portMUX_TYPE * mux ) const char * fnName, int line ) { - unsigned int irqStatus = portENTER_CRITICAL_NESTED(); + unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR(); vPortCPUAcquireMutexIntsDisabled( mux, portMUX_NO_TIMEOUT, fnName, line ); - portEXIT_CRITICAL_NESTED( irqStatus ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus ); } bool vPortCPUAcquireMutexTimeout( portMUX_TYPE * mux, @@ -381,29 +424,29 @@ void vPortCPUInitializeMutex( portMUX_TYPE * mux ) const char * fnName, int line ) { - unsigned int irqStatus = portENTER_CRITICAL_NESTED(); + unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR(); bool result = vPortCPUAcquireMutexIntsDisabled( mux, timeout_cycles, fnName, line ); - portEXIT_CRITICAL_NESTED( irqStatus ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus ); return result; } #else /* ifdef CONFIG_FREERTOS_PORTMUX_DEBUG */ void vPortCPUAcquireMutex( portMUX_TYPE * mux ) { - unsigned int irqStatus = portENTER_CRITICAL_NESTED(); + unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR(); vPortCPUAcquireMutexIntsDisabled( mux, portMUX_NO_TIMEOUT ); - portEXIT_CRITICAL_NESTED( irqStatus ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus ); } bool vPortCPUAcquireMutexTimeout( portMUX_TYPE * mux, int timeout_cycles ) { - unsigned int irqStatus = portENTER_CRITICAL_NESTED(); + unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR(); bool result = vPortCPUAcquireMutexIntsDisabled( mux, timeout_cycles ); - portEXIT_CRITICAL_NESTED( irqStatus ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus ); return result; } #endif /* ifdef CONFIG_FREERTOS_PORTMUX_DEBUG */ @@ -419,21 +462,24 @@ void vPortCPUInitializeMutex( portMUX_TYPE * mux ) const char * fnName, int line ) { - unsigned int irqStatus = portENTER_CRITICAL_NESTED(); + unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR(); vPortCPUReleaseMutexIntsDisabled( mux, fnName, line ); - portEXIT_CRITICAL_NESTED( irqStatus ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus ); } #else void vPortCPUReleaseMutex( portMUX_TYPE * mux ) { - unsigned int irqStatus = portENTER_CRITICAL_NESTED(); + unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR(); vPortCPUReleaseMutexIntsDisabled( mux ); - portEXIT_CRITICAL_NESTED( irqStatus ); + portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus ); } #endif /* ifdef CONFIG_FREERTOS_PORTMUX_DEBUG */ +#define STACK_WATCH_AREA_SIZE ( 32 ) +#define STACK_WATCH_POINT_NUMBER ( SOC_CPU_WATCHPOINTS_NUM - 1 ) + void vPortSetStackWatchpoint( void * pxStackStart ) { /*Set watchpoint 1 to watch the last 32 bytes of the stack. */ @@ -445,7 +491,7 @@ void vPortSetStackWatchpoint( void * pxStackStart ) int addr = ( int ) pxStackStart; addr = ( addr + 31 ) & ( ~31 ); - esp_set_watchpoint( 1, ( char * ) addr, 32, ESP_WATCHPOINT_STORE ); + esp_cpu_set_watchpoint( STACK_WATCH_POINT_NUMBER, (char*)addr, 32, ESP_WATCHPOINT_STORE ); } #if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0)) @@ -463,7 +509,7 @@ void vPortSetStackWatchpoint( void * pxStackStart ) { uint32_t prev; - uint32_t oldlevel = portENTER_CRITICAL_NESTED(); + uint32_t oldlevel = portSET_INTERRUPT_MASK_FROM_ISR(); #ifdef CONFIG_FREERTOS_PORTMUX_DEBUG vPortCPUAcquireMutexIntsDisabled( &extram_mux, portMUX_NO_TIMEOUT, __FUNCTION__, __LINE__ ); @@ -484,7 +530,7 @@ void vPortSetStackWatchpoint( void * pxStackStart ) vPortCPUReleaseMutexIntsDisabled( &extram_mux ); #endif - portEXIT_CRITICAL_NESTED(oldlevel); + portCLEAR_INTERRUPT_MASK_FROM_ISR(oldlevel); } #endif //defined(CONFIG_SPIRAM_SUPPORT) @@ -495,3 +541,28 @@ uint32_t xPortGetTickRateHz( void ) { return ( uint32_t ) configTICK_RATE_HZ; } + +// For now, running FreeRTOS on one core and a bare metal on the other (or other OSes) +// is not supported. For now CONFIG_FREERTOS_UNICORE and CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE +// should mirror each other's values. +// +// And since this should be true, we can just check for CONFIG_FREERTOS_UNICORE. +#if CONFIG_FREERTOS_UNICORE != CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + #error "FreeRTOS and system configuration mismatch regarding the use of multiple cores." +#endif + +extern void esp_startup_start_app_common(void); + +void esp_startup_start_app(void) +{ +#if !CONFIG_ESP_INT_WDT +#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX + assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!"); +#endif +#endif + + esp_startup_start_app_common(); + + ESP_LOGI("cpu_start", "Starting scheduler on PRO CPU."); + vTaskStartScheduler(); +} diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/port_common.c b/portable/ThirdParty/GCC/Xtensa_ESP32/port_common.c new file mode 100644 index 000000000..11f119bcd --- /dev/null +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/port_common.c @@ -0,0 +1,159 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "FreeRTOS.h" +#include "task.h" +#include "portmacro.h" +#include "esp_system.h" +#include "esp_heap_caps_init.h" +#include "esp_int_wdt.h" +#include "esp_task_wdt.h" +#include "esp_task.h" +#include "esp_private/crosscore_int.h" +#include "esp_private/startup_internal.h" /* Required by g_spiram_ok. [refactor-todo] for g_spiram_ok */ +#include "esp_log.h" +#include "soc/soc_memory_types.h" +#include "soc/dport_access.h" +#include "sdkconfig.h" +#include "esp_freertos_hooks.h" + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/spiram.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/spiram.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/spiram.h" +#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2 +// SPIRAM is not supported on ESP32-C3 +#endif + +#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL +static const char* TAG = "cpu_start"; +#endif + +/* Architecture-agnostic parts of the FreeRTOS ESP-IDF port layer can go here. + * + * The actual call flow will be to call esp_startup_start_app() in /port.c, + * which will then call esp_startup_start_app_common() + */ + +// Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting +volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; + +// For now, running FreeRTOS on one core and a bare metal on the other (or other OSes) +// is not supported. For now CONFIG_FREERTOS_UNICORE and CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE +// should mirror each other's values. +// +// And since this should be true, we can just check for CONFIG_FREERTOS_UNICORE. +#if CONFIG_FREERTOS_UNICORE != CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + #error "FreeRTOS and system configuration mismatch regarding the use of multiple cores." +#endif + +static void main_task(void* args); + +#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME +void esp_gdbstub_init(void); +#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME + +extern void app_main(void); + +void esp_startup_start_app_common(void) +{ +#if CONFIG_ESP_INT_WDT + esp_int_wdt_init(); + //Initialize the interrupt watch dog for CPU0. + esp_int_wdt_cpu_init(); +#endif + + esp_crosscore_int_init(); + +#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME + esp_gdbstub_init(); +#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME + + portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", + ESP_TASK_MAIN_STACK, NULL, + ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE); + assert(res == pdTRUE); + (void)res; +} + +#if !CONFIG_FREERTOS_UNICORE +static volatile bool s_other_cpu_startup_done = false; +static bool other_cpu_startup_idle_hook_cb(void) +{ + s_other_cpu_startup_done = true; + return true; +} +#endif + +static void main_task(void* args) +{ +#if !CONFIG_FREERTOS_UNICORE + // Wait for FreeRTOS initialization to finish on other core, before replacing its startup stack + esp_register_freertos_idle_hook_for_cpu(other_cpu_startup_idle_hook_cb, !xPortGetCoreID()); + while (!s_other_cpu_startup_done) { + ; + } + esp_deregister_freertos_idle_hook_for_cpu(other_cpu_startup_idle_hook_cb, !xPortGetCoreID()); +#endif + + // [refactor-todo] check if there is a way to move the following block to esp_system startup + heap_caps_enable_nonos_stack_heaps(); + + // Now we have startup stack RAM available for heap, enable any DMA pool memory +#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL + if (g_spiram_ok) { + esp_err_t r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL); + if (r != ESP_OK) { + ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r); + abort(); + } + } +#endif + + //Initialize task wdt if configured to do so +#ifdef CONFIG_ESP_TASK_WDT_PANIC + ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true)); +#elif CONFIG_ESP_TASK_WDT + ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false)); +#endif + + //Add IDLE 0 to task wdt +#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 + TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); + if(idle_0 != NULL){ + ESP_ERROR_CHECK(esp_task_wdt_add(idle_0)); + } +#endif + //Add IDLE 1 to task wdt +#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 + TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); + if(idle_1 != NULL){ + ESP_ERROR_CHECK(esp_task_wdt_add(idle_1)); + } +#endif + + app_main(); + vTaskDelete(NULL); +} + +// -------------------- Heap Related ----------------------- + +bool xPortCheckValidTCBMem(const void *ptr) +{ + return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr); +} + +bool xPortcheckValidStackMem(const void *ptr) +{ +#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY + return esp_ptr_byte_accessible(ptr); +#else + return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr); +#endif +} diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/port_systick.c b/portable/ThirdParty/GCC/Xtensa_ESP32/port_systick.c new file mode 100644 index 000000000..a9f437c61 --- /dev/null +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/port_systick.c @@ -0,0 +1,174 @@ +/* + * SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "soc/cpu.h" +#include "FreeRTOS.h" +#include "task.h" +#include "esp_intr_alloc.h" +#include "esp_err.h" +#include "esp_log.h" +#include "sdkconfig.h" +#ifdef CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER +#include "soc/periph_defs.h" +#include "soc/system_reg.h" +#include "hal/systimer_hal.h" +#include "hal/systimer_ll.h" +#endif + +#ifdef CONFIG_PM_TRACE +#include "esp_private/pm_trace.h" +#endif //CONFIG_PM_TRACE + +BaseType_t xPortSysTickHandler(void); + +#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT +extern void _frxt_tick_timer_init(void); +extern void _xt_tick_divisor_init(void); + +#ifdef CONFIG_FREERTOS_CORETIMER_0 + #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF) +#endif +#ifdef CONFIG_FREERTOS_CORETIMER_1 + #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF) +#endif + +/** + * @brief Initialize CCONT timer to generate the tick interrupt + * + */ +void vPortSetupTimer(void) +{ + /* Init the tick divisor value */ + _xt_tick_divisor_init(); + + _frxt_tick_timer_init(); +} + + +#elif CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER + +_Static_assert(SOC_CPU_CORES_NUM <= SOC_SYSTIMER_ALARM_NUM - 1, "the number of cores must match the number of core alarms in SYSTIMER"); + +void SysTickIsrHandler(void *arg); + +static uint32_t s_handled_systicks[portNUM_PROCESSORS] = { 0 }; + +#define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE) + +/** + * @brief Set up the systimer peripheral to generate the tick interrupt + * + * Both timer alarms are configured in periodic mode. + * It is done at the same time so SysTicks for both CPUs occur at the same time or very close. + * Shifts a time of triggering interrupts for core 0 and core 1. + */ +void vPortSetupTimer(void) +{ + unsigned cpuid = xPortGetCoreID(); +#ifdef CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 + const unsigned level = ESP_INTR_FLAG_LEVEL3; +#else + const unsigned level = ESP_INTR_FLAG_LEVEL1; +#endif + /* Systimer HAL layer object */ + static systimer_hal_context_t systimer_hal; + /* set system timer interrupt vector */ + ESP_ERROR_CHECK(esp_intr_alloc(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE + cpuid, ESP_INTR_FLAG_IRAM | level, SysTickIsrHandler, &systimer_hal, NULL)); + + if (cpuid == 0) { + systimer_hal_init(&systimer_hal); + systimer_ll_set_counter_value(systimer_hal.dev, SYSTIMER_LL_COUNTER_OS_TICK, 0); + systimer_ll_apply_counter_value(systimer_hal.dev, SYSTIMER_LL_COUNTER_OS_TICK); + + for (cpuid = 0; cpuid < SOC_CPU_CORES_NUM; cpuid++) { + systimer_hal_counter_can_stall_by_cpu(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, cpuid, false); + } + + for (cpuid = 0; cpuid < portNUM_PROCESSORS; ++cpuid) { + uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid; + + /* configure the timer */ + systimer_hal_connect_alarm_counter(&systimer_hal, alarm_id, SYSTIMER_LL_COUNTER_OS_TICK); + systimer_hal_set_alarm_period(&systimer_hal, alarm_id, 1000000UL / CONFIG_FREERTOS_HZ); + systimer_hal_select_alarm_mode(&systimer_hal, alarm_id, SYSTIMER_ALARM_MODE_PERIOD); + systimer_hal_counter_can_stall_by_cpu(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, cpuid, true); + if (cpuid == 0) { + systimer_hal_enable_alarm_int(&systimer_hal, alarm_id); + systimer_hal_enable_counter(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK); +#ifndef CONFIG_FREERTOS_UNICORE + // SysTick of core 0 and core 1 are shifted by half of period + systimer_hal_counter_value_advance(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, 1000000UL / CONFIG_FREERTOS_HZ / 2); +#endif + } + } + } else { + uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid; + systimer_hal_enable_alarm_int(&systimer_hal, alarm_id); + } +} + +/** + * @brief Systimer interrupt handler. + * + * The Systimer interrupt for SysTick works in periodic mode no need to calc the next alarm. + * If a timer interrupt is ever serviced more than one tick late, it is necessary to process multiple ticks. + */ +IRAM_ATTR void SysTickIsrHandler(void *arg) +{ + uint32_t cpuid = xPortGetCoreID(); + systimer_hal_context_t *systimer_hal = (systimer_hal_context_t *)arg; +#ifdef CONFIG_PM_TRACE + ESP_PM_TRACE_ENTER(TICK, cpuid); +#endif + + uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid; + do { + systimer_ll_clear_alarm_int(systimer_hal->dev, alarm_id); + + uint32_t diff = systimer_hal_get_counter_value(systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK) / systimer_ll_get_alarm_period(systimer_hal->dev, alarm_id) - s_handled_systicks[cpuid]; + if (diff > 0) { + if (s_handled_systicks[cpuid] == 0) { + s_handled_systicks[cpuid] = diff; + diff = 1; + } else { + s_handled_systicks[cpuid] += diff; + } + + do { + xPortSysTickHandler(); + } while (--diff); + } + } while (systimer_ll_is_alarm_int_fired(systimer_hal->dev, alarm_id)); + +#ifdef CONFIG_PM_TRACE + ESP_PM_TRACE_EXIT(TICK, cpuid); +#endif +} + +#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT + +/** + * @brief Handler of SysTick + * + * The function is called from: + * - _frxt_timer_int for xtensa with CONFIG_FREERTOS_SYSTICK_USES_CCOUNT + * - SysTickIsrHandler for xtensa with CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER + * - SysTickIsrHandler for riscv + */ +BaseType_t xPortSysTickHandler(void) +{ + portbenchmarkIntLatency(); + traceISR_ENTER(SYSTICK_INTR_ID); + BaseType_t ret = xTaskIncrementTick(); + if(ret != pdFALSE) { + portYIELD_FROM_ISR(); + } else { + traceISR_EXIT(); + } + return ret; +} diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/portasm.S b/portable/ThirdParty/GCC/Xtensa_ESP32/portasm.S index 27c4ff19c..c7f653857 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/portasm.S +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/portasm.S @@ -282,6 +282,7 @@ _frxt_int_exit: * ********************************************************************************************************** */ +#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT .globl _frxt_timer_int .type _frxt_timer_int,@function .align 4 @@ -333,7 +334,7 @@ _frxt_timer_int: s32i a3, sp, 8 #endif - /* Call the FreeRTOS tick handler (see port.c). */ + /* Call the FreeRTOS tick handler (see port_systick.c). */ #ifdef __XTENSA_CALL0_ABI__ call0 xPortSysTickHandler #else @@ -359,6 +360,7 @@ _frxt_timer_int: #endif // CONFIG_PM_TRACE RET(16) +#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT /* ********************************************************************************************************** @@ -370,6 +372,7 @@ _frxt_timer_int: * ********************************************************************************************************** */ +#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT .globl _frxt_tick_timer_init .type _frxt_tick_timer_init,@function .align 4 @@ -402,6 +405,7 @@ _frxt_tick_timer_init: #endif RET(16) +#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT /* ********************************************************************************************************** @@ -456,6 +460,10 @@ _frxt_dispatch: .L_frxt_dispatch_sol: /* Solicited stack frame. Restore minimal context and return from vPortYield(). */ + #if XCHAL_HAVE_THREADPTR + l32i a2, sp, XT_SOL_THREADPTR + wur.threadptr a2 + #endif l32i a3, sp, XT_SOL_PS #ifdef __XTENSA_CALL0_ABI__ l32i a12, sp, XT_SOL_A12 @@ -543,6 +551,10 @@ vPortYield: rsr a2, PS s32i a0, sp, XT_SOL_PC s32i a2, sp, XT_SOL_PS + #if XCHAL_HAVE_THREADPTR + rur.threadptr a2 + s32i a2, sp, XT_SOL_THREADPTR + #endif #ifdef __XTENSA_CALL0_ABI__ s32i a12, sp, XT_SOL_A12 /* save callee-saved registers */ s32i a13, sp, XT_SOL_A13 diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_init.c b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_init.c index 837dfbc3f..e7275c623 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_init.c +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_init.c @@ -39,34 +39,37 @@ #ifdef XT_BOARD - #include +#include "xtensa/xtbsp.h" #endif -#include "xtensa_rtos.h" +#include "xtensa_rtos.h" +#include "sdkconfig.h" #include "esp_idf_version.h" #if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0)) #include "esp_clk.h" #else -#if CONFIG_IDF_TARGET_ESP32S2 -#include "esp32s2/clk.h" -#elif CONFIG_IDF_TARGET_ESP32 -#include "esp32/clk.h" +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/clk.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/clk.h" +#elif CONFIG_IDF_TARGET_ESP32S3 +#include "esp32s3/clk.h" #endif #endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) */ #ifdef XT_RTOS_TIMER_INT - unsigned _xt_tick_divisor = 0; /* cached number of cycles per tick */ +unsigned _xt_tick_divisor = 0; /* cached number of cycles per tick */ - void _xt_tick_divisor_init( void ) - { - _xt_tick_divisor = esp_clk_cpu_freq() / XT_TICK_PER_SEC; - } +void _xt_tick_divisor_init(void) +{ + _xt_tick_divisor = esp_clk_cpu_freq() / XT_TICK_PER_SEC; +} /* Deprecated, to be removed */ - int xt_clock_freq( void ) - { - return esp_clk_cpu_freq(); - } +int xt_clock_freq(void) +{ + return esp_clk_cpu_freq(); +} #endif /* XT_RTOS_TIMER_INT */ diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_intr.c b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_intr.c deleted file mode 100644 index d1882e4b0..000000000 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_intr.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2019 Cadence Design Systems, Inc. - * - * SPDX-License-Identifier: MIT - * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD - */ -/* - * Copyright (c) 2015-2019 Cadence Design Systems, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/****************************************************************************** -* Xtensa-specific interrupt and exception functions for RTOS ports. -* Also see xtensa_intr_asm.S. -******************************************************************************/ - -#include - -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/xtensa_api.h" -#include "freertos/portable.h" -#include "esp_idf_version.h" - -#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0)) -#include "rom/ets_sys.h" -#else -#if CONFIG_IDF_TARGET_ESP32S2 -#include "esp32s2/rom/ets_sys.h" -#elif CONFIG_IDF_TARGET_ESP32 -#include "esp32/rom/ets_sys.h" -#endif -#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) */ - -#if XCHAL_HAVE_EXCEPTIONS - -/* Handler table is in xtensa_intr_asm.S */ - - extern xt_exc_handler _xt_exception_table[ XCHAL_EXCCAUSE_NUM * portNUM_PROCESSORS ]; - - -/* - * Default handler for unhandled exceptions. - * CHANGED: We do this in panic.c now - */ - -/*void xt_unhandled_exception(XtExcFrame *frame) */ -/*{ */ - /*exit(-1); */ -/*} */ - extern void xt_unhandled_exception( XtExcFrame * frame ); - - -/* - * This function registers a handler for the specified exception. - * The function returns the address of the previous handler. - * On error, it returns 0. - */ - xt_exc_handler xt_set_exception_handler( int n, - xt_exc_handler f ) - { - xt_exc_handler old; - - if( ( n < 0 ) || ( n >= XCHAL_EXCCAUSE_NUM ) ) - { - return 0; /* invalid exception number */ - } - - /* Convert exception number to _xt_exception_table name */ - n = n * portNUM_PROCESSORS + xPortGetCoreID(); - old = _xt_exception_table[ n ]; - - if( f ) - { - _xt_exception_table[ n ] = f; - } - else - { - _xt_exception_table[ n ] = &xt_unhandled_exception; - } - - return( ( old == &xt_unhandled_exception ) ? 0 : old ); - } - -#endif /* if XCHAL_HAVE_EXCEPTIONS */ - -#if XCHAL_HAVE_INTERRUPTS - -/* Handler table is in xtensa_intr_asm.S */ - - typedef struct xt_handler_table_entry - { - void * handler; - void * arg; - } xt_handler_table_entry; - - extern xt_handler_table_entry _xt_interrupt_table[ XCHAL_NUM_INTERRUPTS * portNUM_PROCESSORS ]; - - -/* - * Default handler for unhandled interrupts. - */ - void xt_unhandled_interrupt( void * arg ) - { - ets_printf( "Unhandled interrupt %d on cpu %d!\n", ( int ) arg, xPortGetCoreID() ); - } - - -/* - * This function registers a handler for the specified interrupt. The "arg" - * parameter specifies the argument to be passed to the handler when it is - * invoked. The function returns the address of the previous handler. - * On error, it returns 0. - */ - xt_handler xt_set_interrupt_handler( int n, - xt_handler f, - void * arg ) - { - xt_handler_table_entry * entry; - xt_handler old; - - if( ( n < 0 ) || ( n >= XCHAL_NUM_INTERRUPTS ) ) - { - return 0; /* invalid interrupt number */ - } - - if( Xthal_intlevel[ n ] > XCHAL_EXCM_LEVEL ) - { - return 0; /* priority level too high to safely handle in C */ - } - - /* Convert exception number to _xt_exception_table name */ - n = n * portNUM_PROCESSORS + xPortGetCoreID(); - - entry = _xt_interrupt_table + n; - old = entry->handler; - - if( f ) - { - entry->handler = f; - entry->arg = arg; - } - else - { - entry->handler = &xt_unhandled_interrupt; - entry->arg = ( void * ) n; - } - - return( ( old == &xt_unhandled_interrupt ) ? 0 : old ); - } - - #if CONFIG_SYSVIEW_ENABLE - void * xt_get_interrupt_handler_arg( int n ) - { - xt_handler_table_entry * entry; - - if( ( n < 0 ) || ( n >= XCHAL_NUM_INTERRUPTS ) ) - { - return 0; /* invalid interrupt number */ - } - - /* Convert exception number to _xt_exception_table name */ - n = n * portNUM_PROCESSORS + xPortGetCoreID(); - - entry = _xt_interrupt_table + n; - return entry->arg; - } - #endif /* if CONFIG_SYSVIEW_ENABLE */ - -#endif /* XCHAL_HAVE_INTERRUPTS */ diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_intr_asm.S b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_intr_asm.S deleted file mode 100644 index 879721291..000000000 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_intr_asm.S +++ /dev/null @@ -1,232 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2019 Cadence Design Systems, Inc. - * - * SPDX-License-Identifier: MIT - * - * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD - */ -/* - * Copyright (c) 2015-2019 Cadence Design Systems, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/****************************************************************************** - Xtensa interrupt handling data and assembly routines. - Also see xtensa_intr.c and xtensa_vectors.S. -******************************************************************************/ - -#include -#include - -#include "xtensa_context.h" -#include "FreeRTOSConfig.h" - -#if XCHAL_HAVE_INTERRUPTS - -/* -------------------------------------------------------------------------------- - INTENABLE virtualization information. -------------------------------------------------------------------------------- -*/ - - -#if XT_USE_SWPRI -/* Warning - this is not multicore-compatible. */ - .data - .global _xt_intdata - .align 8 -_xt_intdata: - .global _xt_intenable - .type _xt_intenable,@object - .size _xt_intenable,4 - .global _xt_vpri_mask - .type _xt_vpri_mask,@object - .size _xt_vpri_mask,4 - -_xt_intenable: .word 0 /* Virtual INTENABLE */ -_xt_vpri_mask: .word 0xFFFFFFFF /* Virtual priority mask */ -#endif - -/* -------------------------------------------------------------------------------- - Table of C-callable interrupt handlers for each interrupt. Note that not all - slots can be filled, because interrupts at level > EXCM_LEVEL will not be - dispatched to a C handler by default. - - Stored as: - int 0 cpu 0 - int 0 cpu 1 - ... - int 0 cpu n - int 1 cpu 0 - int 1 cpu 1 - etc -------------------------------------------------------------------------------- -*/ - - .data - .global _xt_interrupt_table - .align 8 - -_xt_interrupt_table: - - .set i, 0 - .rept XCHAL_NUM_INTERRUPTS*portNUM_PROCESSORS - .word xt_unhandled_interrupt /* handler address */ - .word i /* handler arg (default: intnum) */ - .set i, i+1 - .endr - -#endif /* XCHAL_HAVE_INTERRUPTS */ - - -#if XCHAL_HAVE_EXCEPTIONS - -/* -------------------------------------------------------------------------------- - Table of C-callable exception handlers for each exception. Note that not all - slots will be active, because some exceptions (e.g. coprocessor exceptions) - are always handled by the OS and cannot be hooked by user handlers. - - Stored as: - exc 0 cpu 0 - exc 0 cpu 1 - ... - exc 0 cpu n - exc 1 cpu 0 - exc 1 cpu 1 - etc -------------------------------------------------------------------------------- -*/ - - .data - .global _xt_exception_table - .align 4 - -_xt_exception_table: - .rept XCHAL_EXCCAUSE_NUM * portNUM_PROCESSORS - .word xt_unhandled_exception /* handler address */ - .endr - -#endif - - -/* -------------------------------------------------------------------------------- - unsigned int xt_ints_on ( unsigned int mask ) - - Enables a set of interrupts. Does not simply set INTENABLE directly, but - computes it as a function of the current virtual priority if XT_USE_SWPRI is - enabled. - Can be called from interrupt handlers. -------------------------------------------------------------------------------- -*/ - - .text - .align 4 - .global xt_ints_on - .type xt_ints_on,@function - -xt_ints_on: - - ENTRY0 - -#if XCHAL_HAVE_INTERRUPTS -#if XT_USE_SWPRI - movi a3, 0 - movi a4, _xt_intdata - xsr a3, INTENABLE /* Disables all interrupts */ - rsync - l32i a3, a4, 0 /* a3 = _xt_intenable */ - l32i a6, a4, 4 /* a6 = _xt_vpri_mask */ - or a5, a3, a2 /* a5 = _xt_intenable | mask */ - s32i a5, a4, 0 /* _xt_intenable |= mask */ - and a5, a5, a6 /* a5 = _xt_intenable & _xt_vpri_mask */ - wsr a5, INTENABLE /* Reenable interrupts */ - mov a2, a3 /* Previous mask */ -#else - movi a3, 0 - xsr a3, INTENABLE /* Disables all interrupts */ - rsync - or a2, a3, a2 /* set bits in mask */ - wsr a2, INTENABLE /* Re-enable ints */ - rsync - mov a2, a3 /* return prev mask */ -#endif -#else - movi a2, 0 /* Return zero */ -#endif - RET0 - - .size xt_ints_on, . - xt_ints_on - - -/* -------------------------------------------------------------------------------- - unsigned int xt_ints_off ( unsigned int mask ) - - Disables a set of interrupts. Does not simply set INTENABLE directly, - but computes it as a function of the current virtual priority if XT_USE_SWPRI is - enabled. - Can be called from interrupt handlers. -------------------------------------------------------------------------------- -*/ - - .text - .align 4 - .global xt_ints_off - .type xt_ints_off,@function - -xt_ints_off: - - ENTRY0 -#if XCHAL_HAVE_INTERRUPTS -#if XT_USE_SWPRI - movi a3, 0 - movi a4, _xt_intdata - xsr a3, INTENABLE /* Disables all interrupts */ - rsync - l32i a3, a4, 0 /* a3 = _xt_intenable */ - l32i a6, a4, 4 /* a6 = _xt_vpri_mask */ - or a5, a3, a2 /* a5 = _xt_intenable | mask */ - xor a5, a5, a2 /* a5 = _xt_intenable & ~mask */ - s32i a5, a4, 0 /* _xt_intenable &= ~mask */ - and a5, a5, a6 /* a5 = _xt_intenable & _xt_vpri_mask */ - wsr a5, INTENABLE /* Reenable interrupts */ - mov a2, a3 /* Previous mask */ -#else - movi a4, 0 - xsr a4, INTENABLE /* Disables all interrupts */ - rsync - or a3, a4, a2 /* set bits in mask */ - xor a3, a3, a2 /* invert bits in mask set in mask, essentially clearing them */ - wsr a3, INTENABLE /* Re-enable ints */ - rsync - mov a2, a4 /* return prev mask */ -#endif -#else - movi a2, 0 /* return zero */ -#endif - RET0 - - .size xt_ints_off, . - xt_ints_off - - diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vector_defaults.S b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vector_defaults.S index 39327779e..a016e02d9 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vector_defaults.S +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vector_defaults.S @@ -29,6 +29,21 @@ The default behaviour is to just exit the interrupt or call the panic handler on .align 4 _xt_debugexception: +#if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI) +#define XT_DEBUGCAUSE_DI (5) + getcoreid a0 +#if (CONFIG_BTDM_CTRL_PINNED_TO_CORE == PRO_CPU_NUM) + beqz a0, 1f +#else + bnez a0, 1f +#endif + + rsr a0, DEBUGCAUSE + extui a0, a0, XT_DEBUGCAUSE_DI, 1 + bnez a0, _xt_debug_di_exc +1: +#endif //(CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI) + movi a0,PANIC_RSN_DEBUGEXCEPTION wsr a0,EXCCAUSE /* _xt_panic assumes a level 1 exception. As we're @@ -41,6 +56,66 @@ _xt_debugexception: call0 _xt_panic /* does not return */ rfi XCHAL_DEBUGLEVEL +#if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI) + .align 4 +_xt_debug_di_exc: + + /* + The delay time can be calculated by the following formula: + T = ceil(0.25 + max(t1, t2)) us + + t1 = 80 / f1, t2 = (1 + 14/N) * 20 / f2 + + f1: PSRAM access frequency, unit: MHz. + f2: Flash access frequency, unit: MHz. + + When flash is slow/fast read, N = 1. + When flash is DOUT/DIO read, N = 2. + When flash is QOUT/QIO read, N = 4. + + And after testing, when CPU frequency is 240 MHz, it will take 1us to loop 27 times. + */ +#if defined(CONFIG_ESPTOOLPY_FLASHMODE_QIO) || defined(CONFIG_ESPTOOLPY_FLASHMODE_QOUT) + +# if defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_80M) + movi a0, 54 +# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_40M) + movi a0, 81 +# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_40M) && defined(CONFIG_SPIRAM_SPEED_40M) + movi a0, 81 +# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_26M) && defined(CONFIG_SPIRAM_SPEED_40M) + movi a0, 108 +# else + movi a0, 135 +# endif + +#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_DIO) || defined(CONFIG_ESPTOOLPY_FLASHMODE_DOUT) + +# if defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_80M) + movi a0, 81 +# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_40M) + movi a0, 81 +# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_40M) && defined(CONFIG_SPIRAM_SPEED_40M) + movi a0, 135 +# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_26M) && defined(CONFIG_SPIRAM_SPEED_40M) + movi a0, 189 +# else + movi a0, 243 +# endif + +#else + movi a0, 243 +#endif + +1: addi a0, a0, -1 /* delay_us(N) */ + .rept 4 + nop + .endr + bnez a0, 1b + + rsr a0, EXCSAVE+XCHAL_DEBUGLEVEL + rfi XCHAL_DEBUGLEVEL +#endif //(CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI) #endif /* Debug exception */ @@ -158,4 +233,3 @@ _xt_nmi: rfi XCHAL_NMILEVEL #endif /* NMI */ - diff --git a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vectors.S b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vectors.S index a431758d4..3a0a9569d 100644 --- a/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vectors.S +++ b/portable/ThirdParty/GCC/Xtensa_ESP32/xtensa_vectors.S @@ -306,9 +306,13 @@ rsil a3, \level - 1 /* lower interrupt level by 1 */ #endif + #ifdef XT_RTOS_TIMER_INT movi a3, XT_TIMER_INTEN /* a3 = timer interrupt bit */ wsr a4, INTCLEAR /* clear sw or edge-triggered interrupt */ beq a3, a4, 7f /* if timer interrupt then skip table */ + #else + wsr a4, INTCLEAR /* clear sw or edge-triggered interrupt */ + #endif // XT_RTOS_TIMER_INT find_ms_setbit a3, a4, a3, 0 /* a3 = interrupt number */ @@ -332,7 +336,7 @@ #else j .L_xt_user_int_&level& /* check for more interrupts */ #endif - + #ifdef XT_RTOS_TIMER_INT 7: .ifeq XT_TIMER_INTPRI - \level @@ -352,6 +356,7 @@ call4 XT_RTOS_TIMER_INT #endif .endif + #endif // XT_RTOS_TIMER_INT #ifdef XT_USE_SWPRI j 8f @@ -377,7 +382,7 @@ .endm - +#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0)) /* -------------------------------------------------------------------------------- Panic handler. @@ -460,14 +465,12 @@ panic_print_hex_ok: s32i a5,a3,0 ret - +#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */ .section .rodata, "a" .align 4 - - /* -------------------------------------------------------------------------------- Hooks to dynamically install handlers for exceptions and interrupts. @@ -737,11 +740,11 @@ _xt_user_exc: rsr a0, EXCSAVE_1 /* save interruptee's a0 */ s32i a0, sp, XT_STK_A0 - /* Set up PS for C, reenable hi-pri interrupts, and clear EXCM. */ + /* Set up PS for C, reenable debug and NMI interrupts, and clear EXCM. */ #ifdef __XTENSA_CALL0_ABI__ - movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM + movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM #else - movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE + movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM | PS_WOE #endif wsr a0, PS @@ -2062,6 +2065,3 @@ _WindowUnderflow12: .type call_user_start,@function .align 4 .literal_position - - -