diff --git a/GCC/AURIX_TC3xx/LICENSE b/GCC/AURIX_TC3xx/LICENSE new file mode 100644 index 000000000..5be4db413 --- /dev/null +++ b/GCC/AURIX_TC3xx/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2023 Infineon Technologies AG. All rights reserved. + IMPORTANT NOTICE +Use of this file is subject to the terms of use agreed between (i) you or the company in which ordinary course of +business you are acting and (ii) Infineon Technologies AG or its licensees. If and as long as no such terms of use +are agreed, use of this file is subject to following: + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and +accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, +and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the +Software is furnished to do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including the above license grant, this restriction +and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all +derivative works of the Software, unless such copies or derivative works are solely in the form of +machine-executable object code generated by a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +SPDX-License-Identifier: BSL-1.0 diff --git a/GCC/AURIX_TC3xx/README.md b/GCC/AURIX_TC3xx/README.md new file mode 100644 index 000000000..a13dd4fac --- /dev/null +++ b/GCC/AURIX_TC3xx/README.md @@ -0,0 +1,67 @@ +# Overview + +This directory contains the FreeRTOS port for the Infineon AURIX™ TC3xx family of MCUs equipped with the TriCore™ core. + +The port is placed under the `GCC/` folder because the compiler used — **tricore-gcc**, bundled with [AURIX™ Development Studio (ADS)](https://www.infineon.com/design-resources/platforms/aurix-software-tools/aurix-tools/aurix-development-studio) — is a GCC-based toolchain and exposes the standard `__GNUC__` preprocessor macro. + +## Tool Dependencies + +- [AURIX™ Development Studio (ADS)](https://www.infineon.com/design-resources/platforms/aurix-software-tools/aurix-tools/aurix-development-studio) — includes **tricore-gcc** and an integrated debugger. Please install via the [Infineon Developer Center Launcher](https://www.infineon.com/cms/en/design-support/tools/utilities/infineon-developer-center-idc-launcher/) + +## How To Use This Port + +Add `port.c` and `portmacro.h` from this directory to the application's FreeRTOS portable layer, and add this directory to the compiler include path so the FreeRTOS kernel can include `portmacro.h`. + +The application must provide a `FreeRTOSConfig.h` that defines the TCxxx-specific options listed below. It must also provide the ADS-L/iLLD trap hook configuration described in the System Call Trap Integration section so `portYIELD()` can reach `vPortSyscallHandler()`. + +Supported demos for TC375 are available in `/FreeRTOS-Partner-Supported-Demos/AURIX_TC375_ADS`. + +## Required FreeRTOSConfig.h Options + +In addition to the standard FreeRTOS kernel configuration options such as `configCPU_CLOCK_HZ`, `configTICK_RATE_HZ`, `configMAX_PRIORITIES`, `configMINIMAL_STACK_SIZE`, and `configTOTAL_HEAP_SIZE`, an application that uses this port must define the TCxxx-specific options below in `FreeRTOSConfig.h`. The companion demo provides example values for TC375 CPU0. + +| Macro | Purpose | +| --- | --- | +| `configSTM` | Base address of the per-CPU STM register block used for the tick timer. | +| `configSTM_SRC` | Address of the STM service request register used by the tick interrupt. | +| `configSTM_CLOCK_HZ` | STM input clock frequency used to calculate the tick compare interval. | +| `configCONTEXT_SRC` | Address of the service request register used for software-triggered context switches. | +| `configCPU_NR` | TriCore CPU number used in SRC TOS fields and in the generated `.intvec_tc_` section names. | +| `configCONTEXT_INTERRUPT_PRIORITY` | Interrupt priority for the context-switch service request. | +| `configTIMER_INTERRUPT_PRIORITY` | Interrupt priority for the STM tick service request (must not be higher than `configCONTEXT_INTERRUPT_PRIORITY`). | +| `configMAX_API_CALL_INTERRUPT_PRIORITY` | CCPN mask threshold used by critical sections and FromISR API masking. | +| `configSYSCALL_CALL_DEPTH` | Call depth used when saving and restoring context from `vPortSyscallYield()`. | +| `configPROVIDE_SYSCALL_TRAP` | Set to `0` when the ADS-L/iLLD trap table dispatches the syscall trap (see below); set to `1` to let the port emit its own class 6 trap vector. | + +The following TCxxx-specific options are optional or have port-provided defaults: + +| Macro | Purpose | +| --- | --- | +| `configCPU_STM_DEBUG` | Optional debug assert for missed STM ticks; undefined or `0` disables the check. | +| `configTICK_STM_DEBUG` | Optional STM debug-control setup during tick timer initialization; undefined or `0` disables it. | +| `configYIELD_SYSCALL_ID` | Syscall ID used by `portYIELD()`; defaults to `0` when not defined. | + +## System Call Trap Integration + +`portYIELD()` uses the TriCore `syscall` instruction with `configYIELD_SYSCALL_ID` (default `0`). The syscall enters the TriCore system-call trap class (class 6 / SYS); the trap identification number (TIN) is passed to `vPortSyscallHandler()` and is matched against `configYIELD_SYSCALL_ID`. + +The TC3xx GCC port does not emit its own trap-vector entry for `vPortSyscallHandler()`. In an ADS/iLLD project, the startup code sets the Base Trap Vector register (BTV) from the linker-provided `__TRAPTAB_CPUx` symbols, for example `Libraries/Infra/Ssw/TC3xx/Tricore/Ifx_Ssw_Tc0.c` writes `CPU_BTV` from `__TRAPTAB(0)`. The linker script (`Lcf_Gnuc_Tricore_Tc.lsl`) places the iLLD trap table sections, for example `.traptab_cpu0`, at those addresses. The system-call trap table entry in `Libraries/iLLD/TC3xx/Tricore/Cpu/Trap/IfxCpu_Trap.c` unconditionally invokes the `IFX_CFG_CPU_TRAP_SYSCALL_CPUx_HOOK()` macros; when the application does not override them they resolve to an empty default provided by the iLLD header. + +For a CPU0-only FreeRTOS integration using the iLLD trap handler, declare `vPortSyscallHandler()` and route the CPU0 syscall hook to it in `Configurations/Ifx_Cfg.h`: + +```c +extern int vPortSyscallHandler( unsigned char id ); +#define IFX_CFG_CPU_TRAP_SYSCALL_CPU0_HOOK( t ) vPortSyscallHandler( t.tId ) +``` + +No separate `Configurations/Ifx_Cfg_Trap.h` and no `IFX_CFG_EXTEND_TRAP_HOOKS` define are required on TC3xx — the syscall hook macro is picked up directly by `IfxCpu_Trap.c` regardless. + +The `Configurations` files used by the companion demo can be found from [ Infineon AURIX Code Examples - Configurations](https://www.infineon.com/design-resources/platforms/aurix-software-tools/aurix-tools/aurix-development-studio). + +## Test Coverage + +This port has been verified against the qualification checklist in the [FreeRTOS Third-Party Template README](https://github.com/FreeRTOS/FreeRTOS/blob/main/FreeRTOS/Demo/ThirdParty/Template/README.md). All required tests execute continuously without reporting an error on TC375 CPU0. + +## Support + +- For support queries, please open an issue on the [FreeRTOS-Kernel-Partner-Supported-Ports](https://github.com/FreeRTOS/FreeRTOS-Kernel-Partner-Supported-Ports/issues) repository diff --git a/GCC/AURIX_TC3xx/port.c b/GCC/AURIX_TC3xx/port.c new file mode 100644 index 000000000..ec52400a8 --- /dev/null +++ b/GCC/AURIX_TC3xx/port.c @@ -0,0 +1,486 @@ +/* + * \copyright Copyright (c) 2023 Infineon Technologies AG. All rights reserved. + * + * + * IMPORTANT NOTICE + * + * + * Use of this file is subject to the terms of use agreed between (i) you or + * the company in which ordinary course of business you are acting and (ii) + * Infineon Technologies AG or its licensees. If and as long as no such + * terms of use are agreed, use of this file is subject to following: + * + * Boost Software License - Version 1.0 - August 17th, 2003 + * + * Permission is hereby granted, free of charge, to any person or + * organization obtaining a copy of the software and accompanying + * documentation covered by this license (the "Software") to use, reproduce, + * display, distribute, execute, and transmit the Software, and to prepare + * derivative works of the Software, and to permit third-parties to whom the + * Software is furnished to do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, must + * be included in all copies of the Software, in whole or in part, and all + * derivative works of the Software, unless such copies or derivative works are + * solely in the form of machine-executable object code generated by a source + * language processor. + * + * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * SPDX-License-Identifier: BSL-1.0 + */ + +#include +#include +#include + +#include "FreeRTOS.h" +#include "task.h" + +/* Prgoram status word macros */ +#define portINITIAL_SYSTEM_PSW \ + ( 0x000008FFUL ) /* Supervisor Mode, MPU Register Set 0 and Call Depth Counting disabled. */ + +/* Context save area macros */ +#define portCSA_FCX_MASK ( 0x000FFFFFUL ) +#define portINITIAL_LOWER_PCXI ( 0x00300000UL ) /* Set UL to upper and PIE to 1 */ +#define portINITIAL_UPPER_PCXI ( 0x00200000UL ) /* Set UL to lower and PIE to 1 */ +#define portNUM_WORDS_IN_CSA ( 16 ) + +extern volatile unsigned long * pxCurrentTCB; + +/* Tick and context switch config */ +#define portTICK_COUNT ( configSTM_CLOCK_HZ / configTICK_RATE_HZ ) + +/* Register defines */ +static volatile uint32_t *const pxStm = configSTM; +static volatile uint32_t *const pxStmSrc = configSTM_SRC; +static volatile uint32_t *const pxContextSrc = configCONTEXT_SRC; +#define portSTM_TIM0 0x10 +#define portSTM_CMP0 0x30 +#define portSTM_COMCON 0x38 +#define portSTM_ICR 0x3C +#define portSTM_ISCR 0x40 +#define portSTM_OCS 0xE8 + +#define portSTM_CMCON_MSTART0_OFF 8 +#define portSTM_CMCON_MSIZE0_OFF 0 +#define portSTM_ICR_CMP0EN_OFF 0 +#define portSTM_ICR_CMP0OS_OFF 2 +#define portSTM_ISCR_CMP0IRR_OFF 0 + +static inline void vPortStartFirstTask( void ); +static inline void vPortInitContextSrc( void ); +static inline void vPortInitTickTimer( void ); + +static inline void __attribute__( ( always_inline ) ) vPortLoadContext( unsigned char ucCallDepth ); +static inline void __attribute__( ( always_inline ) ) vPortSaveContext( unsigned char ucCallDepth ); + +static inline uint32_t * __attribute__( ( always_inline ) ) pxPortCsaToAddress( uint32_t xCsa ); + +static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; + +/* FreeRTOS required functions */ +BaseType_t xPortStartScheduler( void ) +{ + vPortInitTickTimer(); + vPortInitContextSrc(); + vPortStartFirstTask(); + + return 0; +} + +void vPortEndScheduler() +{ + pxStmSrc[ 0 ] &= ~( 1 << portSRC_SRCR_SRE_OFF ); + pxContextSrc[ 0 ] &= ~( 1 << portSRC_SRCR_SRE_OFF ); +} + +StackType_t *pxPortInitialiseStack( StackType_t * pxTopOfStack, + TaskFunction_t pxCode, + void * pvParameters ) +{ + uint32_t xLowerCsa = 0, xUpperCsa = 0; + uint32_t * pxUpperCSA = NULL; + uint32_t * pxLowerCSA = NULL; + + /* Have to disable interrupts here because the CSAs are going to be + * manipulated. */ + _disable(); + { + /* DSync to ensure that buffering is not a problem. */ + _dsync(); + + /* Consume two free CSAs. */ + xLowerCsa = _mfcr( portCPU_FCX ); + pxLowerCSA = pxPortCsaToAddress( xLowerCsa ); + + if( pxLowerCSA != NULL ) + { + /* The Lower Links to the Upper. */ + xUpperCsa = pxLowerCSA[ 0 ]; + pxUpperCSA = pxPortCsaToAddress( pxLowerCSA[ 0 ] ); + } + + /* Check that we have successfully reserved two CSAs. */ + if( ( pxLowerCSA != NULL ) && ( pxUpperCSA != NULL ) ) + { + /* Remove the two consumed CSAs from the free CSA list. */ + _mtcr( portCPU_FCX, pxUpperCSA[ 0 ] ); + _isync(); + } + else + { + /* Simply trigger a context list depletion trap. */ + __asm( "\tsvlcx" ); + } + } + _enable(); + + /* Upper Context. */ + memset( pxUpperCSA, 0, portNUM_WORDS_IN_CSA * sizeof( uint32_t ) ); + pxUpperCSA[ 2 ] = ( uint32_t ) pxTopOfStack; /* A10; Stack Return aka Stack Pointer */ + pxUpperCSA[ 1 ] = portINITIAL_SYSTEM_PSW; /* PSW */ + pxUpperCSA[ 0 ] = portINITIAL_UPPER_PCXI; + + /* Lower Context. */ + memset( pxLowerCSA, 0, portNUM_WORDS_IN_CSA * sizeof( uint32_t ) ); + pxLowerCSA[ 8 ] = ( uint32_t ) pvParameters; /* A4; Address Type Parameter Register */ + pxLowerCSA[ 1 ] = ( uint32_t ) pxCode; /* A11; Return Address aka RA */ + pxLowerCSA[ 0 ] = portINITIAL_LOWER_PCXI | xUpperCsa; /* PCXI pointing to the Upper context. */ + + /* Initialize the uxCriticalNesting. */ + pxTopOfStack--; + *pxTopOfStack = 0; + /* Save the link to the CSA to the top of stack. */ + pxTopOfStack--; + *pxTopOfStack = xLowerCsa; + + return pxTopOfStack; +} + +void __attribute__( ( interrupt_handler ) ) vPortSystemContextHandler() +{ + /* Disable interrupts to protect section*/ + _disable(); + + /* Do a save, switch, execute */ + vPortSaveContext( 0 ); + vTaskSwitchContext(); + vPortLoadContext( 0 ); + + _enable(); +} + +#define STR( x ) # x +#define XSTR( s ) STR( s ) +__asm__ ( + " .pushsection .intvec_tc" XSTR( configCPU_NR ) "_" XSTR( configCONTEXT_INTERRUPT_PRIORITY ) ",\"ax\",@progbits\n" + " .align 5\n" + " __intvec_entry_" XSTR( configCONTEXT_INTERRUPT_PRIORITY ) ":\n" + " svlcx\n" + " movh.a %a14, hi:vPortSystemContextHandler\n" + " lea %a14, [%a14]lo:vPortSystemContextHandler\n" + " ji %a14\n" + " .org 32\n" + " .popsection\n" ); + +void __attribute__( ( interrupt_handler ) ) vPortSystemTickHandler() +{ + unsigned long ulSavedInterruptMask; + BaseType_t xYieldRequired; + + /* Increment compare value by tick count */ + pxStm[ portSTM_CMP0 >> 2 ] = pxStm[ portSTM_CMP0 >> 2 ] + portTICK_COUNT; + pxStm[ portSTM_ISCR >> 2 ] |= ( 1 << portSTM_ISCR_CMP0IRR_OFF ); + + /* Check for possible tick drop. + * If the time is beyond the compare value, the next tick will need a complete + * wrap around. The tick count isn't accruate any more. Increase the tick count + * or adapt to execute xTaskIncrementTick multiple times depending on the + * counts missed. */ + #if configCPU_STM_DEBUG != 0 + configASSERT( ( pxStm[ portSTM_CMP0 >> 2 ] - pxStm[ portSTM_TIM0 >> 2 ] ) <= portTICK_COUNT ); + #endif + + /* Kernel API calls require Critical Sections. */ + ulSavedInterruptMask = portSET_INTERRUPT_MASK_FROM_ISR(); + { + /* Increment the Tick. */ + xYieldRequired = xTaskIncrementTick(); + } + portCLEAR_INTERRUPT_MASK_FROM_ISR( ulSavedInterruptMask ); + + portYIELD_FROM_ISR( xYieldRequired ); +} + +__asm__ ( + " .pushsection .intvec_tc" XSTR( configCPU_NR ) "_" XSTR( configTIMER_INTERRUPT_PRIORITY ) ",\"ax\",@progbits\n" + " .align 5\n" + " __intvec_entry_" XSTR( configTIMER_INTERRUPT_PRIORITY ) ":\n" + " svlcx\n" + " movh.a %a14, hi:vPortSystemTickHandler\n" + " lea %a14, [%a14]lo:vPortSystemTickHandler\n" + " ji %a14\n" + " .org 32\n" + " .popsection\n" ); + +void __attribute__( ( noinline ) ) vPortSyscallYield( void ); + +int vPortSyscallHandler( unsigned char id ) +{ + switch( id ) + { + case 0: + vPortSyscallYield(); + break; + + default: + break; + } + + return 0; +} + +void vPortInitTickTimer() +{ + pxStm[ portSTM_COMCON >> 2 ] = + ( 0 << portSTM_CMCON_MSTART0_OFF ) | ( 31 << portSTM_CMCON_MSIZE0_OFF ); + pxStm[ portSTM_ICR >> 2 ] &= ~( 1 << portSTM_ICR_CMP0OS_OFF ); + pxStmSrc[ 0 ] = ( ( configCPU_NR > 0 ? + configCPU_NR + 1 : configCPU_NR ) << portSRC_SRCR_TOS_OFF ) | + ( ( configTIMER_INTERRUPT_PRIORITY ) << portSRC_SRCR_SRPN_OFF ); + pxStmSrc[ 0 ] |= ( 1 << portSRC_SRCR_SRE_OFF ); + pxStm[ portSTM_CMP0 >> 2 ] = pxStm[ portSTM_TIM0 >> 2 ]; + pxStm[ portSTM_ISCR >> 2 ] |= ( 1 << portSTM_ISCR_CMP0IRR_OFF ); + pxStm[ portSTM_ICR >> 2 ] |= ( 1 << portSTM_ICR_CMP0EN_OFF ); + pxStm[ portSTM_CMP0 >> 2 ] = pxStm[ portSTM_TIM0 >> 2 ] + portTICK_COUNT; + #if configTICK_STM_DEBUG != 0 + pxStm[ portSTM_OCS >> 2 ] = 0x12000000; + #endif +} + +void vPortInitContextSrc() +{ + pxContextSrc[ 0 ] = + ( ( configCPU_NR > 0 ? + configCPU_NR + 1 : configCPU_NR ) << portSRC_SRCR_TOS_OFF ) | + ( ( configCONTEXT_INTERRUPT_PRIORITY ) << portSRC_SRCR_SRPN_OFF ); + pxContextSrc[ 0 ] |= ( 1 << portSRC_SRCR_SRE_OFF ); +} + +void vPortStartFirstTask() +{ + /* Disable interrupts */ + _disable(); + + vPortLoadContext( 0 ); + + /* Reset the call stack counting, to avoid trap on rfe */ + unsigned long ulPsw = _mfcr( portCPU_PSW ); + + ulPsw &= ~( portCPU_PSW_CSC_MSK ); + _mtcr( portCPU_PSW, ulPsw ); + _isync(); + + /* Load the lower context and upper context through rfe to enable irqs */ + __asm( "\trslcx" ); + __asm( "\trfe" ); + _nop(); + _nop(); + _nop(); +} + +void vPortLoadContext( unsigned char ucCallDepth ) +{ + uint32_t ** ppxTopOfStack; + uint32_t uxLowerCSA; + + /* Dsync is required for save CSA access */ + _dsync(); + + /* Load the new CSA id from the stack and update the stack pointer */ + ppxTopOfStack = ( uint32_t ** ) pxCurrentTCB; + uxLowerCSA = **ppxTopOfStack; + ( *ppxTopOfStack )++; + uxCriticalNesting = **ppxTopOfStack; + ( *ppxTopOfStack )++; + + /* Store the lower context directly if inside the syscall or interrupt, + * else replace the lower context in the call stack. */ + if( !ucCallDepth ) + { + /* Update the link register */ + _mtcr( portCPU_PCXI, uxLowerCSA ); + _isync(); + } + else + { + /* Update previous lower context */ + uint32_t * pxCSA = pxPortCsaToAddress( _mfcr( portCPU_PCXI ) ); + int i; + + for(i = 0; i < ucCallDepth - 1; i++) + { + pxCSA = pxPortCsaToAddress( pxCSA[ 0 ] ); + } + + pxCSA[ 0 ] = uxLowerCSA; + } +} + +void vPortSaveContext( unsigned char ucCallDepth ) +{ + uint32_t ** ppxTopOfStack; + uint32_t * pxLowerCSA, * pxUpperCSA; + uint32_t uxLowerCSA; + + /* Dsync is required for save CSA access */ + _dsync(); + + /* Get the current context information. */ + uxLowerCSA = _mfcr( portCPU_PCXI ); + + /* If this function is used inside a function from the syscall or interrupt, + * load the correct context from the call stack */ + if( ucCallDepth ) + { + uint32_t * pxCSA = pxPortCsaToAddress( uxLowerCSA ); + int i; + + for(i = 0; i < ucCallDepth - 1; i++) + { + pxCSA = pxPortCsaToAddress( pxCSA[ 0 ] ); + } + + uxLowerCSA = pxCSA[ 0 ]; + } + + pxLowerCSA = pxPortCsaToAddress( uxLowerCSA ); + pxUpperCSA = pxPortCsaToAddress( pxLowerCSA[ 0 ] ); + + /* Load the stack pointer */ + ppxTopOfStack = ( uint32_t ** ) pxCurrentTCB; + /* Update the stack info in the TCB */ + *ppxTopOfStack = ( uint32_t * ) pxUpperCSA[ 2 ]; + /* Place ucNestedContext */ + ( *ppxTopOfStack )--; + **ppxTopOfStack = uxCriticalNesting; + /* Place the lower CSA id on the stack */ + ( *ppxTopOfStack )--; + **ppxTopOfStack = uxLowerCSA; +} + +void vPortSyscallYield() +{ + /* Do a save, switch, execute */ + vPortSaveContext( configSYSCALL_CALL_DEPTH ); + vTaskSwitchContext(); + vPortLoadContext( configSYSCALL_CALL_DEPTH ); +} + +uint32_t * pxPortCsaToAddress( uint32_t xCsa ) +{ + uint32_t pxCsa; + + __asm ( "extr.u %0, %1, 16, 4\n" + "sh %0, %0, 28\n" + "insert %0, %0, %1, 6, 16\n" : "=&d" ( pxCsa ) : "d" ( xCsa ) ); + /*pxCsa = (_extr_u(xCsa, 16, 4) << 28); */ + /*pxCsa = _insert(pxCsa, xCsa, 6, 16); */ + return ( uint32_t * ) pxCsa; +} + +void vPortEnterCritical( void ) +{ + portDISABLE_INTERRUPTS(); + uxCriticalNesting++; + + /* This is not the interrupt safe version of the enter critical function so + * assert() if it is being called from an interrupt context. Only API + * functions that end in "FromISR" can be used in an interrupt. Only assert if + * the critical nesting count is 1 to protect against recursive calls if the + * assert function also uses a critical section. */ + if( uxCriticalNesting == 1 ) + { + portASSERT_IF_IN_ISR(); + } +} + +void vPortExitCritical( void ) +{ + configASSERT( uxCriticalNesting ); + uxCriticalNesting--; + + if( uxCriticalNesting == 0 ) + { + portENABLE_INTERRUPTS(); + } +} + +/* + * When a task is deleted, it is yielded permanently until the IDLE task + * has an opportunity to reclaim the memory that that task was using. + * Typically, the memory used by a task is the TCB and Stack but in the + * TriCore this includes the CSAs that were consumed as part of the Call + * Stack. These CSAs can only be returned to the Globally Free Pool when + * they are not part of the current Call Stack, hence, delaying the + * reclamation until the IDLE task is freeing the task's other resources. + * This function uses the head of the linked list of CSAs (from when the + * task yielded for the last time) and finds the tail (the very bottom of + * the call stack) and inserts this list at the head of the Free list, + * attaching the existing Free List to the tail of the reclaimed call stack. + * + * NOTE: In highly loaded systems the release of used CSAs might be delayed, + * since it is executed es part of the calling tasks, if the deleted task is + * different from the calling tasks, or as part of the idle task, if the deleted + * tasks is the same as the calling task. + */ +void vPortReclaimCSA( unsigned long ** pxTCB ) +{ + uint32_t ulHeadCSA, ulFreeCSA; + uint32_t * pulNextCSA; + + /* The lower context (PCXI value) to return to the task is stored as the + * current element on the stack. Mask off everything in the PCXI register + * other than the address. */ + ulHeadCSA = ( **pxTCB ) & portCSA_FCX_MASK; + + /* Iterate over the CSAs that were consumed as part of the task. */ + for(pulNextCSA = pxPortCsaToAddress( ulHeadCSA ); + ( pulNextCSA[ 0 ] & portCSA_FCX_MASK ) != 0; + pulNextCSA = pxPortCsaToAddress( pulNextCSA[ 0 ] ) ) + { + /* Mask off everything in the PCXI value other than the address. */ + pulNextCSA[ 0 ] &= portCSA_FCX_MASK; + } + + _disable(); + { + /* Look up the current free CSA head. */ + _dsync(); + ulFreeCSA = _mfcr( portCPU_FCX ); + + /* Join the current free onto the tail of what is being reclaimed. */ + pulNextCSA[ 0 ] = ulFreeCSA; + + /* Move the head of the reclaimed into the Free. */ + _mtcr( portCPU_FCX, ulHeadCSA ); + _isync(); + } + _enable(); +} + +void __attribute__( ( noreturn ) ) vPortLoopForever( void ) +{ + while( 1 ) + { + } +} diff --git a/GCC/AURIX_TC3xx/portmacro.h b/GCC/AURIX_TC3xx/portmacro.h new file mode 100644 index 000000000..bb88372a7 --- /dev/null +++ b/GCC/AURIX_TC3xx/portmacro.h @@ -0,0 +1,195 @@ +/* + * \copyright Copyright (c) 2023 Infineon Technologies AG. All rights reserved. + * + * + * IMPORTANT NOTICE + * + * + * Use of this file is subject to the terms of use agreed between (i) you or + * the company in which ordinary course of business you are acting and (ii) + * Infineon Technologies AG or its licensees. If and as long as no such + * terms of use are agreed, use of this file is subject to following: + * + * Boost Software License - Version 1.0 - August 17th, 2003 + * + * Permission is hereby granted, free of charge, to any person or + * organization obtaining a copy of the software and accompanying + * documentation covered by this license (the "Software") to use, reproduce, + * display, distribute, execute, and transmit the Software, and to prepare + * derivative works of the Software, and to permit third-parties to whom the + * Software is furnished to do so, all subject to the following: + * + * The copyright notices in the Software and this entire statement, including + * the above license grant, this restriction and the following disclaimer, must + * be included in all copies of the Software, in whole or in part, and all + * derivative works of the Software, unless such copies or derivative works are + * solely in the form of machine-executable object code generated by a source + * language processor. + * + * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT + * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * SPDX-License-Identifier: BSL-1.0 + */ + +#ifndef PORTMACRO_H +#define PORTMACRO_H + +#ifdef __cplusplus + extern "C" +#endif + +#include "FreeRTOSConfig.h" +#include + +#define portCPU_PSW 0xFE04 +#define portCPU_PSW_IS_OFF ( 9 ) +#define portCPU_PSW_CSC_MSK ( 0x7F ) +#define portCPU_ICR 0xFE2C +#define portCPU_ICR_CCPN_OFF ( 0 ) +#define portCPU_ICR_CCPN_MSK ( 0x000000FFUL ) +#define portCPU_FCX 0xFE38 +#define portCPU_PCXI 0xFE00 +#define portCPU_CORE_ID 0xFE1C + +/* Register defintions */ +#define portSRC_SRCR_SRPN_OFF 0 +#define portSRC_SRCR_SRE_OFF 10 +#define portSRC_SRCR_TOS_OFF 11 +#define portSRC_SRCR_SRR_OFF 24 +#define portSRC_SRCR_SETR_OFF 26 + +/* Type definitions. */ +#define portCHAR char +#define portSHORT short +#define portLONG long +#define portFLOAT float +#define portDOUBLE double +#define portSTACK_TYPE uint32_t +#define portBASE_TYPE long +#define portPOINTER_SIZE_TYPE uintptr_t + +typedef portSTACK_TYPE StackType_t; +typedef long BaseType_t; +typedef unsigned long UBaseType_t; + +#if ( configUSE_16_BIT_TICKS == 1 ) + typedef unsigned short TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffff +#else + typedef unsigned int TickType_t __attribute__( ( aligned( 4 ) ) ); + #define portMAX_DELAY ( TickType_t ) 0xffffffffUL +#endif + +/* FreeRTOS parameters */ +#define portTICK_TYPE_IS_ATOMIC 1 +#define portSTACK_GROWTH ( -1 ) +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#define portBYTE_ALIGNMENT 8 +#define portCRITICAL_NESTING_IN_TCB 0 + +/* Attributes */ +#define portDONT_DISCARD __attribute__( ( used ) ) +#define portNORETURN __attribute__( ( noreturn ) ) + +/* Instructions */ +#define portNOP() _nop() +#define portMEMORY_BARRIER() _dsync() + +/* Critical section management */ +extern void vPortEnterCritical( void ); +extern void vPortExitCritical( void ); +#define portENTER_CRITICAL() vPortEnterCritical() +#define portEXIT_CRITICAL() vPortExitCritical() +#define portENABLE_INTERRUPTS() vPortSetCCPN( 0 ); +#define portDISABLE_INTERRUPTS() vPortSetCCPN( configMAX_API_CALL_INTERRUPT_PRIORITY ) +#define portASSERT_IF_IN_ISR() configASSERT( ( _mfcr( portCPU_PSW ) & ( 1 << portCPU_PSW_IS_OFF ) ) == 0 ) +#define portCLEAR_INTERRUPT_MASK_FROM_ISR( ulSavedMaskValue ) vPortSetICR( ulSavedMaskValue ) +#define portSET_INTERRUPT_MASK_FROM_ISR() xPortSetCCPN( configMAX_API_CALL_INTERRUPT_PRIORITY ) + + +#ifndef configYIELD_SYSCALL_ID + #define configYIELD_SYSCALL_ID 0 +#endif + +#define portYIELD() _syscall( configYIELD_SYSCALL_ID ) +#define portYIELD_FROM_ISR( xHigherPriorityTaskWoken ) \ + { \ + const uint32_t xTrigger = ( ( *configCONTEXT_SRC >> portSRC_SRCR_SRR_OFF ) & 0x1 ) != 1 && ( xHigherPriorityTaskWoken != 0 ); \ + *configCONTEXT_SRC |= ( xTrigger << portSRC_SRCR_SETR_OFF ); \ + \ + /* Wait until write request completes to trigger IRQ */ \ + _dsync(); \ + _isync(); \ + } + + +#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION + #define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#endif + +#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 ) + +/* Check the configuration. */ + #if ( configMAX_PRIORITIES > 32 ) + #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 difference priorities as tasks that share a priority will time slice. + #endif + +/* Store/clear the ready priorities in a bit map. */ + #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) ) + #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ) + + #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ( ( uint32_t ) __builtin_clz( ( uxReadyPriorities ) ) ) ) + +#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + +/* Function prototypes */ +#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) + +/* TCB handling */ +extern void vPortReclaimCSA( unsigned long ** pxTCB ); +#define portCLEAN_UP_TCB( pxTCB ) vPortReclaimCSA( ( unsigned long ** ) ( pxTCB ) ) + + +/* ICR & CCPN modifying functions to enable and disable interrupts. + * Only interrupts with a priority lower than + */ +static inline void __attribute__( ( used, always_inline ) ) vPortSetCCPN( unsigned char ucCCPN ) +{ + _disable(); + _mtcr( portCPU_ICR, ( _mfcr( portCPU_ICR ) & ~portCPU_ICR_CCPN_MSK ) | ( ucCCPN & portCPU_ICR_CCPN_MSK ) ); + _isync(); + _enable(); +} + +static inline void __attribute__( ( used, always_inline ) ) vPortSetICR( portBASE_TYPE ulICR ) +{ + _disable(); + _mtcr( portCPU_ICR, ( unsigned int ) ulICR ); + _isync(); + _enable(); +} + +static inline portBASE_TYPE __attribute__( ( used, always_inline ) ) xPortSetCCPN( unsigned char ucCCPN ) +{ + uint32_t xICR; + + _disable(); + xICR = _mfcr( portCPU_ICR ); + _mtcr( portCPU_ICR, ( xICR & ~portCPU_ICR_CCPN_MSK ) | ( ucCCPN & portCPU_ICR_CCPN_MSK ) ); + _isync(); + _enable(); + return ( portBASE_TYPE ) xICR; +} + +#ifdef __cplusplus +} +#endif + +#endif /* PORTMACRO_H */