From c963d2400159acc2d06ff8c066a2b8c1738b3a35 Mon Sep 17 00:00:00 2001 From: Rahul Kar <118818625+kar-rahul-aws@users.noreply.github.com> Date: Thu, 8 Aug 2024 21:07:11 +0530 Subject: [PATCH 1/8] Add support for vApplicationFPUSafeIRQHandler (#1113) This PR adds support for vApplicationFPUSafeIRQHandler. The application writer needs to name their IRQ handler as: 1. vApplicationIRQHandler if the IRQ handler does not use FPU registers. 2. vApplicationFPUSafeIRQHandler is the IRQ handler uses FPU registers. When the application uses vApplicationFPUSafeIRQHandler, a default implementation of vApplicationIRQHandler is used which stores FPU registers and then calls vApplicationFPUSafeIRQHandler. --- portable/GCC/ARM_CRx_No_GIC/portASM.S | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/portable/GCC/ARM_CRx_No_GIC/portASM.S b/portable/GCC/ARM_CRx_No_GIC/portASM.S index 9945fc2d996..de9845e0f5b 100644 --- a/portable/GCC/ARM_CRx_No_GIC/portASM.S +++ b/portable/GCC/ARM_CRx_No_GIC/portASM.S @@ -39,6 +39,7 @@ .extern pxCurrentTCB .extern vTaskSwitchContext .extern vApplicationIRQHandler + .extern vApplicationFPUSafeIRQHandler .extern ulPortInterruptNesting .extern ulPortTaskHasFPUContext .extern ulICCEOIR @@ -237,6 +238,50 @@ vApplicationSVCHandler: /*-----------------------------------------------------------*/ +/* If the application provides an implementation of vApplicationIRQHandler(), + * then it will get called directly without saving the FPU registers on + * interrupt entry, and this weak implementation of vApplicationIRQHandler() + * will not get called. + * + * If the application provides its own implementation of + * vApplicationFPUSafeIRQHandler() then this implementation of + * vApplicationIRQHandler() will be called, save the FPU registers, and then + * call vApplicationFPUSafeIRQHandler(). + * + * Therefore, if the application writer wants FPU registers to be saved on + * interrupt entry, their IRQ handler must be called + * vApplicationFPUSafeIRQHandler(), and if the application writer does not want + * FPU registers to be saved on interrupt entry their IRQ handler must be + * called vApplicationIRQHandler(). + */ +.align 4 +.weak vApplicationIRQHandler +.type vApplicationIRQHandler, %function +vApplicationIRQHandler: + PUSH {LR} + + VMRS R1, FPSCR + VPUSH {D0-D7} + PUSH {R1} + + BLX vApplicationFPUSafeIRQHandler + + POP {R0} + VPOP {D0-D7} + VMSR FPSCR, R0 + + POP {PC} + +/*-----------------------------------------------------------*/ + +.align 4 +.weak vApplicationFPUSafeIRQHandler +.type vApplicationFPUSafeIRQHandler, %function +vApplicationFPUSafeIRQHandler: + B vApplicationFPUSafeIRQHandler + +/*-----------------------------------------------------------*/ + /* * UBaseType_t ulPortCountLeadingZeros( UBaseType_t ulBitmap ); * From da3c35aa4832b94774b3f6890e5a2b4627bfc8f8 Mon Sep 17 00:00:00 2001 From: Trong Nguyen <147012384+TrongNguyenR@users.noreply.github.com> Date: Fri, 9 Aug 2024 12:51:21 +0700 Subject: [PATCH 2/8] Add CC-RH port for Renesas F1Kx devices (#1100) Add CC-RH port for Renesas F1Kx devices --- .github/.cSpellWords.txt | 18 +- portable/CCRH/F1Kx/README.md | 46 +++ portable/CCRH/F1Kx/port.c | 734 +++++++++++++++++++++++++++++++++ portable/CCRH/F1Kx/portasm.s | 325 +++++++++++++++ portable/CCRH/F1Kx/portmacro.h | 193 +++++++++ 5 files changed, 1315 insertions(+), 1 deletion(-) create mode 100644 portable/CCRH/F1Kx/README.md create mode 100644 portable/CCRH/F1Kx/port.c create mode 100644 portable/CCRH/F1Kx/portasm.s create mode 100644 portable/CCRH/F1Kx/portmacro.h diff --git a/.github/.cSpellWords.txt b/.github/.cSpellWords.txt index 0ba0be7c5b6..42f9196d7d8 100644 --- a/.github/.cSpellWords.txt +++ b/.github/.cSpellWords.txt @@ -75,6 +75,7 @@ CCNT CCNTR CCPN CCPR +CCRH CDTY CDTYR CFBS @@ -86,6 +87,7 @@ CHSR CICR CISR CKDIV +CKDIVMD CKEY CKGR CKLO @@ -125,6 +127,7 @@ CODR comms COMPA CONFG +coreid coremqtt CORTUS coverity @@ -149,6 +152,7 @@ CPRE cpsid cpsie CPSR +CPUCLK CPUID CRCB crflash @@ -164,6 +168,8 @@ csrs csrw CTCR ctest +CTPC +CTPSW CTRLA CTSIC CUPD @@ -227,6 +233,7 @@ DTREN DTXD DUNITY DVAR +Dxxx EABI ecall ECIT @@ -237,6 +244,7 @@ EEVT eevtedg EEVTEDG EFRHD +EIIC EINT EIPC EIPSW @@ -310,6 +318,7 @@ FNTR FOSC FPCCR FPCSR +FPEPC FPSW FPUL FRDY @@ -338,6 +347,7 @@ GPTA HCLK Hitach HRESP +HTCFG HWHSH HWORD HWRD @@ -353,6 +363,7 @@ ICCR ICCRPR ICCRX ICERST +ICIPI ICSR IDCR IECR @@ -372,6 +383,7 @@ INTTM IODEFINE IORLW IPEN +IPIR IPLB ipsr IPSR @@ -380,8 +392,8 @@ IRET IRXFCS ISRAM ISRR -ISR's ISRS +ISR's ISRTICK isystem ITIF @@ -564,6 +576,7 @@ OSCEN OSCOFF OSCOUNT OSMC +OSTM outpw OVLY OVRE @@ -584,6 +597,7 @@ PCLKSEL PCSR PCXI PDSR +PEID PEIE PENDSV PENDSVCLEAR @@ -799,6 +813,8 @@ SWINTR SWRST SWTRG synchronise +SYNCM +syncm SYSC sysclk Sysclk diff --git a/portable/CCRH/F1Kx/README.md b/portable/CCRH/F1Kx/README.md new file mode 100644 index 00000000000..7583c67aff2 --- /dev/null +++ b/portable/CCRH/F1Kx/README.md @@ -0,0 +1,46 @@ +# RH850/F1K and F1Kx FreeRTOS Port with CC-RH Compiler + +## Introduction + +This repository contains the port of FreeRTOS for Renesas RH850/F1K and F1Kx microcontrollers using the CC-RH compiler. The following sections provide instructions on how to use this port, a link to the test project, and other relevant information. + +## Prerequisites +- Compiler: CC-RH +- FreeRTOS version 11.1.0 + +| Device | FPU | SMP | +|----------|-----|-----| +| F1K | Yes | No | +| F1KM-S1 | Yes | No | +| F1KM-S2 | Yes | No | +| F1KM-S4 | Yes | No | +| F1KH-D8 | Yes | Yes | + +## Link to Test Project + +The test project can be found [here](https://github.com/FreeRTOS/FreeRTOS-Community-Supported-Demos) (`RH850_F1Kx_CCRH`). This project contains example tasks and configurations to help you get started with FreeRTOS on the RH850/F1K and F1Kx. + +## Note + 1. Configure IPIR Interrupt: Ensure that the bit specifying the destination for binding (requesting) an interrupt is enabled (e.g: IBDxxx register of F1KH-D8) (1) + 2. `Channel 0` and address `0xFFFEEC00` are used as default configuration for configIPIR_CHANNEL and configEXCLUSIVE_ADDRESS, in case of resource confliction other channel/address can be used. (2) + 3. The minimal stack size (configMINIMAL_STACK_SIZE) must be included the reserved memory for nested interrupt. This formula can be referred: `(task_context_size) * (1 + configMAX_INT_NESTING) + Stack_depth_of_taskcode` + In which, `task_context_size` is calculated as `36*4bytes = 144bytes` (when FPU enabled) or `34*4bytes = 136` (when FPU disabled), configMAX_INT_NESTING is 02 as default. + 4. `configTIMER_PRESCALE`: This value is required in order to correctly configure clock for `CPUCLK_L`. Refer to Hardware Manual at `Table 44.22` for `option byte`: If the user sets the option byte `CKDIVMD to 1`, then `configTIMER_PRESCALE = 4`. Otherwise, if `CKDIVMD is set to 0`, then `configTIMER_PRESCALE = 2`. + +(1) This is applicable for F1KH-D8 with SMP only. + +(2) This is optional and applicable for SMP only. + +## Other Relevant Information + +- **Documentation:** + - Refer to the official [FreeRTOS documentation](https://www.freertos.org/Documentation/RTOS_book.html) for detailed information on configuring and using FreeRTOS. + - Consult the [RH850 F1K group user manual hardware manual](https://www.renesas.com/us/en/document/mah/rh850f1k-group-users-manual-hardware?r=1170166) for specific details about the microcontroller. + - For more information about Renesas RH850/F1K and F1Kx, please visit [this website](https://www.renesas.com/us/en/products/microcontrollers-microprocessors/rh850-automotive-mcus) + - The CC-RH compiler can be downloaded [here](https://www.renesas.com/us/en/software-tool/c-compiler-package-rh850-family#downloads) + +- **Support:** + - If you encounter any issues or have questions about this port, please open an issue in this repository or contact the maintainer. + +- **Contributing:** + - Contributions to improve this port are welcome. Please fork the repository, make your changes, and submit a pull request. \ No newline at end of file diff --git a/portable/CCRH/F1Kx/port.c b/portable/CCRH/F1Kx/port.c new file mode 100644 index 00000000000..e3d71929d8e --- /dev/null +++ b/portable/CCRH/F1Kx/port.c @@ -0,0 +1,734 @@ +/* + * FreeRTOS Kernel + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * 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. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/* Scheduler includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* This port uses xTaskGetCurrentTaskHandle to get TCB stack, it is required to + * enable this API. */ +#if ( ( INCLUDE_xTaskGetCurrentTaskHandle != 1 ) && ( configNUMBER_OF_CORES == 1 ) ) + #error INCLUDE_xTaskGetCurrentTaskHandle must be set to 1 in single core. +#endif + +/*********************************************************** +* Macro definitions +***********************************************************/ + +/* Hardware specific macros */ +#define portPSW_REGISTER_ID ( 5 ) +#define portFPSR_REGISTER_ID ( 6 ) + +/* PSW.EBV and PSW.CUx bits are kept as current status */ +#define portINITIAL_PSW_MASK ( 0x000f8000 ) +#define portCURRENT_PSW_VALUE ( portSTSR( portPSW_REGISTER_ID ) ) +#define portCURRENT_SR_ZERO_VALUE ( ( StackType_t ) 0x00000000 ) +#define portCURRENT_FPSR_VALUE ( portSTSR( portFPSR_REGISTER_ID ) ) + +/* Mask for FPU configuration bits (FN, PEM, RM, FS) */ +#define portINITIAL_FPSR_MASK ( 0x00ae0000 ) +#define portPSW_ID_MASK ( 0x00000020 ) + +/* Define necessary hardware IO for OSTM timer. OSTM0 is used by default as + * it is common for almost device variants. If it conflicts with application, + * the application shall implement another timer.*/ +#define portOSTM_EIC_ADDR ( 0xFFFFB0A8 ) +#define portOSTM0CMP_ADDR ( 0xFFD70000 ) +#define portOSTM0CTL_ADDR ( 0xFFD70020 ) +#define portOSTM0TS_ADDR ( 0xFFD70014 ) + +#if ( configNUMBER_OF_CORES > 1 ) + +/* IPIR base address, the peripheral is used for Inter-Processor communication + * Hardware supports 4 channels which is offset by 0x0, 0x4, 0x8, 0xC bytes from + * base address. By default, channel 0 is selected. */ + #ifdef configIPIR_CHANNEL + #define portIPIR_BASE_ADDR ( ( 0xFFFEEC80 ) + ( configIPIR_CHANNEL << 2 ) ) + #else + #define portIPIR_BASE_ADDR ( 0xFFFEEC80 ) + #endif + +/* Address used for exclusive control for variable shared between PEs + * (common resources), each CPU cores have independent access path to + * this address. By default, G0MEV0 register is selected*/ + #ifdef configEXCLUSIVE_ADDRESS + #define portMEV_BASE_ADDR configEXCLUSIVE_ADDRESS + #else + #define portMEV_BASE_ADDR ( 0xFFFEEC00 ) + #endif +#endif /* if ( configNUMBER_OF_CORES > 1 ) */ + +/* Macros required to set up the initial stack. */ +#define portSTACK_INITIAL_VALUE_R1 ( ( StackType_t ) 0x01010101 ) +#define portSTACK_INITIAL_VALUE_R2 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x02 ) +#define portSTACK_INITIAL_VALUE_R3 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x03 ) +#define portSTACK_INITIAL_VALUE_R4 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x04 ) +#define portSTACK_INITIAL_VALUE_R5 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x05 ) +#define portSTACK_INITIAL_VALUE_R6 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x06 ) +#define portSTACK_INITIAL_VALUE_R7 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x07 ) +#define portSTACK_INITIAL_VALUE_R8 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x08 ) +#define portSTACK_INITIAL_VALUE_R9 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x09 ) +#define portSTACK_INITIAL_VALUE_R10 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x10 ) +#define portSTACK_INITIAL_VALUE_R11 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x11 ) +#define portSTACK_INITIAL_VALUE_R12 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x12 ) +#define portSTACK_INITIAL_VALUE_R13 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x13 ) +#define portSTACK_INITIAL_VALUE_R14 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x14 ) +#define portSTACK_INITIAL_VALUE_R15 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x15 ) +#define portSTACK_INITIAL_VALUE_R16 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x16 ) +#define portSTACK_INITIAL_VALUE_R17 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x17 ) +#define portSTACK_INITIAL_VALUE_R18 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x18 ) +#define portSTACK_INITIAL_VALUE_R19 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x19 ) +#define portSTACK_INITIAL_VALUE_R20 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x20 ) +#define portSTACK_INITIAL_VALUE_R21 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x21 ) +#define portSTACK_INITIAL_VALUE_R22 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x22 ) +#define portSTACK_INITIAL_VALUE_R23 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x23 ) +#define portSTACK_INITIAL_VALUE_R24 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x24 ) +#define portSTACK_INITIAL_VALUE_R25 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x25 ) +#define portSTACK_INITIAL_VALUE_R26 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x26 ) +#define portSTACK_INITIAL_VALUE_R27 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x27 ) +#define portSTACK_INITIAL_VALUE_R28 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x28 ) +#define portSTACK_INITIAL_VALUE_R29 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x29 ) +#define portSTACK_INITIAL_VALUE_R30 ( ( StackType_t ) portSTACK_INITIAL_VALUE_R1 * 0x30 ) + +/*********************************************************** +* Typedef definitions +***********************************************************/ + +/* OSTM Count Start Trigger Register (OSTMnTS) */ +#define portOSTM_COUNTER_START ( 0x01U ) /* Starts the counter */ + +/* OSTM Count Stop Trigger Register (OSTMnTT) */ +#define portOSTM_COUNTER_STOP ( 0x01U ) /* Stops the counter */ + +/* OSTM Control Register (OSTMnCTL) */ +#define portOSTM_MODE_INTERVAL_TIMER ( 0x00U ) +#define portOSTM_MODE_FREE_RUNNING ( 0x02U ) + +/* Disables or Enable the interrupts when counting starts */ +#define portOSTM_START_INTERRUPT_DISABLE ( 0x00U ) +#define portOSTM_START_INTERRUPT_ENABLE ( 0x01U ) + +/* Interrupt vector method select (TBxxx) */ +#define portINT_DIRECT_VECTOR ( 0x0U ) +#define portINT_TABLE_VECTOR ( 0x1U ) + +/* Interrupt mask (MKxxx) */ +#define portINT_PROCESSING_ENABLED ( 0x0U ) +#define portINT_PROCESSING_DISABLED ( 0x1U ) + +/* Specify 16 interrupt priority levels */ +#define portINT_PRIORITY_HIGHEST ( 0x0000U ) /* Level 0 (highest) */ +#define portINT_PRIORITY_LEVEL1 ( 0x0001U ) /* Level 1 */ +#define portINT_PRIORITY_LEVEL2 ( 0x0002U ) /* Level 2 */ +#define portINT_PRIORITY_LEVEL3 ( 0x0003U ) /* Level 3 */ +#define portINT_PRIORITY_LEVEL4 ( 0x0004U ) /* Level 4 */ +#define portINT_PRIORITY_LEVEL5 ( 0x0005U ) /* Level 5 */ +#define portINT_PRIORITY_LEVEL6 ( 0x0006U ) /* Level 6 */ +#define portINT_PRIORITY_LEVEL7 ( 0x0007U ) /* Level 7 */ +#define portINT_PRIORITY_LEVEL8 ( 0x0008U ) /* Level 8 */ +#define portINT_PRIORITY_LEVEL9 ( 0x0009U ) /* Level 9 */ +#define portINT_PRIORITY_LEVEL10 ( 0x000AU ) /* Level 10 */ +#define portINT_PRIORITY_LEVEL11 ( 0x000BU ) /* Level 11 */ +#define portINT_PRIORITY_LEVEL12 ( 0x000CU ) /* Level 12 */ +#define portINT_PRIORITY_LEVEL13 ( 0x000DU ) /* Level 13 */ +#define portINT_PRIORITY_LEVEL14 ( 0x000EU ) /* Level 14 */ +#define portINT_PRIORITY_LOWEST ( 0x000FU ) /* Level 15 (lowest) */ + +/* Macros indicating status of scheduler request */ +#define PORT_SCHEDULER_NOREQUEST 0UL +#define PORT_SCHEDULER_TASKSWITCH 1UL /* Do not modify */ +#define PORT_SCHEDULER_STARTFIRSTTASK 2UL /* Do not modify */ + +#ifndef configSETUP_TICK_INTERRUPT + +/* The user has not provided their own tick interrupt configuration so use + * the definition in this file (which uses the interval timer). */ + #define configSETUP_TICK_INTERRUPT() prvSetupTimerInterrupt() +#endif /* configSETUP_TICK_INTERRUPT */ + +#ifndef configMAX_INT_NESTING + +/* Set the default value for depth of nested interrupt. In theory, the + * microcontroller have mechanism to limit number of nested level of interrupt + * by priority (maximum 16 levels). However, the large stack memory should be + * prepared for each task to save resource in interrupt handler. Therefore, it + * is necessary to limit depth of nesting interrupt to optimize memory usage. + * In addition, the execution time of interrupt handler should be very short + * (typically not exceed 20us), this constraint does not impact to system. + */ + #define configMAX_INT_NESTING 2UL +#endif + +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + +/* + * Sets up the periodic ISR used for the RTOS tick using the OSTM. + * The application writer can define configSETUP_TICK_INTERRUPT() (in + * FreeRTOSConfig.h) such that their own tick interrupt configuration is used + * in place of prvSetupTimerInterrupt(). + */ +static void prvSetupTimerInterrupt( void ); + +#if ( configNUMBER_OF_CORES > 1 ) + +/* + * Functions implement spin-lock between cores by atomic accesses to Exclusive + * Control Register (G0MEVm). There are separated access path between CPU cores, + * but they should wait if access to same register + */ + static void prvExclusiveLock( BaseType_t xFromIsr ); + static void prvExclusiveRelease( BaseType_t xFromIsr ); + +#endif + +/* + * Function to start the first task executing + */ +extern void vPortStartFirstTask( void ); + +/* Scheduler request on each cores which are starting first task and switching + * context */ +volatile BaseType_t xPortScheduleStatus[ configNUMBER_OF_CORES ] = { 0 }; + +/* Counts the interrupt nesting depth. A context switch is only performed if + * the nesting depth is 0. In addition, the interrupt shares same stack + * allocated for each tasks. With supporting nesting interrupt, the stack + * may be overflowed. + * It is necessary to control maximum stack depth. + */ +volatile UBaseType_t uxInterruptNesting[ configNUMBER_OF_CORES ] = { 0 }; +volatile const UBaseType_t uxPortMaxInterruptDepth = configMAX_INT_NESTING - 1; + +/* Count number of nested locks by same cores. The lock is completely released + * only if this count is decreased to 0, the lock is separated for task + * and isr */ +UBaseType_t uxLockNesting[ configNUMBER_OF_CORES ][ 2 ] = { 0 }; + +#if ( configNUMBER_OF_CORES > 1 ) + +/* Pointer to exclusive access memory */ + volatile BaseType_t * pxPortExclusiveReg = ( volatile BaseType_t * ) ( portMEV_BASE_ADDR ); +#endif + +/* Interrupt handler for OSTM timer which handling tick increment and resulting + * to switch context. */ +void vPortTickISR( void ); + +#if ( configNUMBER_OF_CORES > 1 ) + +/* Yield specific cores by send inter-processor interrupt */ + void vPortYieldCore( uint32_t xCoreID ); + +/* + * Inter-processor interrupt handler. The interrupt is triggered by + * portYIELD_CORE(). + */ + void vPortIPIHander( void ); + +/* These functions below implement recursive spinlock for exclusive access among + * cores. The core will wait until lock will be available, whilst the core which + * already had lock can acquire lock without waiting. This function could be + * call from task and interrupt context, the critical section is called + * as in ISR */ + void vPortRecursiveLockAcquire( BaseType_t xFromIsr ); + void vPortRecursiveLockRelease( BaseType_t xFromIsr ); + +#endif /* (configNUMBER_OF_CORES > 1) */ + +/*-----------------------------------------------------------*/ + +/* + * These below functions implement interrupt mask from interrupt. They are not + * called in nesting, it is protected by FreeRTOS kernel. + */ +portLONG xPortSetInterruptMask( void ) +{ + portLONG ulPSWValue = portSTSR( portPSW_REGISTER_ID ); + + portDISABLE_INTERRUPTS(); + + /* It returns current value of Program Status Word register */ + return ulPSWValue; +} + +/*-----------------------------------------------------------*/ + +void vPortClearInterruptMask( portLONG uxSavedInterruptStatus ) +{ + portLONG ulPSWValue = portSTSR( portPSW_REGISTER_ID ); + + /* Interrupt Disable status is indicates by bit#5 of PSW + * (1: Interrupt is disabled; 0: Interrupt is enabled) */ + + /* Revert to the status before interrupt mask. */ + ulPSWValue &= ( ~( portPSW_ID_MASK ) ); + ulPSWValue |= ( portPSW_ID_MASK & uxSavedInterruptStatus ); + portLDSR( portPSW_REGISTER_ID, ulPSWValue ); +} + +/*-----------------------------------------------------------*/ + +/* + * Using CC-RH intrinsic function to get HTCFG0 (regID, selID) = (0,2) + * Core ID is indicates by bit HTCFG0.PEID located at bit 18 to 16 + * Bit 31 to 19 are read only and always be read as 0. HTCFG0.PEID is 1 and 2 + * corresponding to core 0 (PE1) and core 1 (PE2). It is adjusted to 0 and 1. + */ +BaseType_t xPortGET_CORE_ID( void ) +{ + #if ( configNUMBER_OF_CORES > 1 ) + return ( portSTSR_CCRH( 0, 2 ) >> 16 ) - 1; + #else + + /* In single core, xPortGET_CORE_ID is used in this port only. + * The dummy core ID could be controlled inside this port. */ + return 0; + #endif +} + +/*-----------------------------------------------------------*/ + +/* + * This port supports both multi-cores and single-core, whilst TCB stack + * variables are different which are respectively pxCurrentTCB (single-core) + * and pxCurrentTCBs[] (multiple-cores). This function is defined to obtains + * TCBs of current cores. Also, the C function could switch to corresponding + * pointer by pre-compile conditions. + */ +void * pvPortGetCurrentTCB( void ) +{ + void * pvCurrentTCB = ( void * ) xTaskGetCurrentTaskHandle(); + + configASSERT( pvCurrentTCB != NULL ); + + return pvCurrentTCB; +} + +/*-----------------------------------------------------------*/ + +/* + * This function checks if a context switch is required and, if so, updates + * the scheduler status for the core on which the function is called. The + * scheduler status is set to indicate that a task switch should occur. + */ +void vPortSetSwitch( BaseType_t xSwitchRequired ) +{ + if( xSwitchRequired != pdFALSE ) + { + xPortScheduleStatus[ xPortGET_CORE_ID() ] = PORT_SCHEDULER_TASKSWITCH; + } +} + +/*-----------------------------------------------------------*/ + +/* + * Setup the stack of a new task so it is ready to be placed under the + * scheduler control. The registers have to be placed on the stack in the + * order that the port expects to find them. + * + * @param[in] pxTopOfStack Pointer to top of this task's stack + * @param[in] pxCode Task function, stored as initial PC for the task + * @param[in] pvParameters Parameters for task + */ +StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, + TaskFunction_t pxCode, + void * pvParameters ) +{ + /* Simulate the stack frame as it would be created by + * a context switch interrupt. */ + *pxTopOfStack = ( StackType_t ) prvTaskExitError; /* R31 (LP) */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R5; /* R5 (TP) */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) pvParameters; /* R6 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R7; /* R7 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R8; /* R8 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R9; /* R9 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R10; /* R10 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R11; /* R11 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R12; /* R12 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R13; /* R13 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R14; /* R14 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R15; /* R15 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R16; /* R16 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R17; /* R17 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R18; /* R18 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R19; /* R19 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R20; /* R20 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R21; /* R21 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R22; /* R22 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R23; /* R23 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R24; /* R24 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R25; /* R25 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R26; /* R26 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R27; /* R27 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R28; /* R28 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R29; /* R29 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R30; /* R30 (EP) */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R1; /* R1 */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portSTACK_INITIAL_VALUE_R2; /* R2 */ + + pxTopOfStack--; + + /* Keep System pre-configuration (HV, CUx, EBV) as current setting in + * PSW register */ + *pxTopOfStack = ( StackType_t ) ( portCURRENT_PSW_VALUE & portINITIAL_PSW_MASK ); /* EIPSW */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) pxCode; /* EIPC */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* EIIC */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) ( portCURRENT_PSW_VALUE & portINITIAL_PSW_MASK ); /* CTPSW */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* CTPC */ + +/* __FPU is defined by CCRH compiler if FPU is enabled */ + #if ( configENABLE_FPU == 1 ) + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) ( portCURRENT_FPSR_VALUE & portINITIAL_FPSR_MASK ); /* FPSR */ + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) portCURRENT_SR_ZERO_VALUE; /* FPEPC */ + #endif /* (configENABLE_FPU == 1) */ + + return pxTopOfStack; +} + +/*-----------------------------------------------------------*/ + +/* + * Configures the tick frequency and starts the first task. + */ +BaseType_t xPortStartScheduler( void ) +{ + #if ( configNUMBER_OF_CORES > 1 ) + BaseType_t xCurrentCore = xPortGET_CORE_ID(); + #endif + + /* Prevent interrupt by timer interrupt during starting first task. + * The interrupt shall be enabled automatically by being restored from + * task stack */ + portDISABLE_INTERRUPTS(); + + /* Setup the tick interrupt */ + configSETUP_TICK_INTERRUPT(); + + #if ( configNUMBER_OF_CORES > 1 ) + /* Start scheduler on other cores */ + for( uint16_t xCoreID = 0; xCoreID < configNUMBER_OF_CORES; xCoreID++ ) + { + if( xCoreID != xCurrentCore ) + { + /* Send yielding request to other cores with flag to start + * first task. TaskContextSwitch is not executed */ + xPortScheduleStatus[ xCoreID ] = PORT_SCHEDULER_STARTFIRSTTASK; + vPortYieldCore( xCoreID ); + } + else + { + /* Nothing to do. The first task is started in this call by + * below vPortStartFirstTask() */ + xPortScheduleStatus[ xCoreID ] = PORT_SCHEDULER_NOREQUEST; + } + } + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + + /* Start first task in primary core */ + vPortStartFirstTask(); + + /* Should never get here as the tasks will now be executing! */ + prvTaskExitError(); + + /* To prevent compiler warnings in the case that the application writer + * overrides this functionality by defining configTASK_RETURN_ADDRESS. + * Call vTaskSwitchContext() so link time optimization does not remove + * the symbol. */ + vTaskSwitchContext( + #if ( configNUMBER_OF_CORES > 1 ) + xCurrentCore + #endif + ); + + return pdFALSE; +} + +/*-----------------------------------------------------------*/ + +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ) +{ + /* A function that implements a task must not exit or attempt to return to + * its caller as there is nothing to return to. If a task wants to exit it + * should instead call vTaskDelete( NULL ). + * + * Artificially force an assert() to be triggered if configASSERT() is + * defined, then stop here so application writers can catch the error. */ + + /* This statement will always fail, triggering the assert */ + configASSERT( pdFALSE ); + + /* + * The following statement may be unreachable because configASSERT(pdFALSE) + * always triggers an assertion failure, which typically halts program + * execution. + * The warning may be reported to indicate to indicate that the compiler + * detects the subsequent code will not be executed. + * The warning is acceptable to ensure program is halt regardless of + * configASSERT(pdFALSE) implementation + */ + portDISABLE_INTERRUPTS(); + + for( ; ; ) + { + /* Infinite loop to ensure the function does not return. */ + } +} + +/*-----------------------------------------------------------*/ + +void vPortEndScheduler( void ) +{ + /* Not implemented in ports where there is nothing to return to. + * Artificially force an assert. */ + configASSERT( pdFALSE ); +} + +/*-----------------------------------------------------------*/ + +#if ( configNUMBER_OF_CORES > 1 ) + + void vPortYieldCore( uint32_t xCoreID ) + { + /* Check if we need to yield on a different core */ + if( xCoreID != xPortGET_CORE_ID() ) + { + volatile uint32_t * pulIPIRReg; + + /* Determine the IPI register based on the target core ID */ + pulIPIRReg = ( volatile uint32_t * ) ( portIPIR_BASE_ADDR ); + + /*Inter-processor interrupt generates an interrupt request by + * writing 1 to applicable bits of target cores. The interrupt + * should be enabled by application in corresponding cores + * including PSW.ID (EI instruction) and interrupt control setting + * for ICIPIRn channel (interrupt mask, vector method) + */ + *pulIPIRReg = ( 1 << xCoreID ); + } + else + { + /* Yielding current core */ + vPortYield(); + } + } + +/*-----------------------------------------------------------*/ + +/* + * Handler for inter-processor interrupt in second cores. The interrupt is + * triggered by portYIELD_CORE(). vTaskSwitchContext() is invoked to + * switch tasks + */ + void vPortIPIHander( void ) + { + BaseType_t xCurrentCore = xPortGET_CORE_ID(); + + /* 1st execution starts 1st task, TaskSwitchContext is not executed */ + if( PORT_SCHEDULER_STARTFIRSTTASK != xPortScheduleStatus[ xCurrentCore ] ) + { + xPortScheduleStatus[ xCurrentCore ] = PORT_SCHEDULER_TASKSWITCH; + } + } + +/*-----------------------------------------------------------*/ + +#endif /* (configNUMBER_OF_CORES > 1) */ + +void vPortTickISR( void ) +{ + /* In case of multicores with SMP, xTaskIncrementTick is required to + * called in critical section to avoid conflict resource as this function + * could be called by xTaskResumeAll() from any cores. */ + #if ( configNUMBER_OF_CORES > 1 ) + BaseType_t xSavedInterruptStatus; + + xSavedInterruptStatus = portENTER_CRITICAL_FROM_ISR(); + #endif + { + /* Increment the RTOS tick. */ + if( xTaskIncrementTick() != pdFALSE ) + { + /* Pend a context switch. */ + xPortScheduleStatus[ xPortGET_CORE_ID() ] = PORT_SCHEDULER_TASKSWITCH; + } + } + #if ( configNUMBER_OF_CORES > 1 ) + portEXIT_CRITICAL_FROM_ISR( xSavedInterruptStatus ); + #endif +} + +/*-----------------------------------------------------------*/ + +static void prvSetupTimerInterrupt( void ) +{ + volatile uint32_t * pulOSTMIntReg; + + /* Interrupt configuration for OSTM Timer + * By default, the second lowest priority is set for timer interrupt to + * avoid blocking other interrupt. Normally, user could set the lowest + * priority for non-critical event. It try to keep timer on time. + * In addition, direct vector table is used by default. + */ + pulOSTMIntReg = ( volatile uint32_t * ) portOSTM_EIC_ADDR; + *pulOSTMIntReg = ( portINT_PROCESSING_ENABLED | portINT_DIRECT_VECTOR | portINT_PRIORITY_LEVEL14 ); + + /* Set OSTM0 control setting */ + *( ( volatile uint32_t * ) portOSTM0CTL_ADDR ) = + ( portOSTM_MODE_INTERVAL_TIMER | portOSTM_START_INTERRUPT_DISABLE ); + *( ( volatile uint32_t * ) portOSTM0CMP_ADDR ) = + ( ( configCPU_CLOCK_HZ / configTIMER_PRESCALE ) / configTICK_RATE_HZ ) - 1; + + /* Enable OSTM0 operation */ + *( ( volatile uint32_t * ) portOSTM0TS_ADDR ) = portOSTM_COUNTER_START; +} + +/*-----------------------------------------------------------*/ + +#if ( configNUMBER_OF_CORES > 1 ) + +/* + * These functions implement spin-lock mechanism among cores using hardware + * exclusive control with atomic access by CLR1 and SET1 instruction. + * Nesting calls to these APIs are possible. + */ + #pragma inline_asm prvExclusiveLock + static void prvExclusiveLock( BaseType_t xBitPosition ) + { + /* No problem with r19, CCRH does not required to restore same value + * before and after function call. */ + mov # _pxPortExclusiveReg, r19 + ld.w 0[ r19 ], r19 + +prvExclusiveLock_Lock: + + /* r6 is xBitPosition */ + set1 r6, [ r19 ] + bz prvExclusiveLock_Lock_success + snooze + br prvExclusiveLock_Lock + +prvExclusiveLock_Lock_success: + } + +/*-----------------------------------------------------------*/ + + #pragma inline_asm prvExclusiveRelease + static void prvExclusiveRelease( BaseType_t xBitPosition ) + { + mov # _pxPortExclusiveReg, r19 + ld.w 0[ r19 ], r19 + + /* r6 is xBitPosition */ + clr1 r6, [ r19 ] + } + +/*-----------------------------------------------------------*/ + void vPortRecursiveLockAcquire( BaseType_t xFromIsr ) + { + BaseType_t xSavedInterruptStatus; + BaseType_t xCoreID = xPortGET_CORE_ID(); + BaseType_t xBitPosition = ( xFromIsr == pdTRUE ); + + xSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + + if( uxLockNesting[ xCoreID ][ xBitPosition ] == 0 ) + { + prvExclusiveLock( xBitPosition ); + } + + uxLockNesting[ xCoreID ][ xBitPosition ]++; + portCLEAR_INTERRUPT_MASK_FROM_ISR( xSavedInterruptStatus ); + } + + void vPortRecursiveLockRelease( BaseType_t xFromIsr ) + { + BaseType_t xSavedInterruptStatus; + BaseType_t xCoreID = xPortGET_CORE_ID(); + BaseType_t xBitPosition = ( xFromIsr == pdTRUE ); + + xSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + + /* Sync memory */ + portSYNCM(); + + /* Error check whether vPortRecursiveLockRelease() is not called in + * pair with vPortRecursiveLockAcquire() */ + configASSERT( ( uxLockNesting[ xCoreID ][ xBitPosition ] > 0 ) ); + uxLockNesting[ xCoreID ][ xBitPosition ]--; + + if( uxLockNesting[ xCoreID ][ xBitPosition ] == 0 ) + { + prvExclusiveRelease( xBitPosition ); + } + + portCLEAR_INTERRUPT_MASK_FROM_ISR( xSavedInterruptStatus ); + } + +/*-----------------------------------------------------------*/ + +#endif /* (configNUMBER_OF_CORES > 1) */ diff --git a/portable/CCRH/F1Kx/portasm.s b/portable/CCRH/F1Kx/portasm.s new file mode 100644 index 00000000000..4e56f449390 --- /dev/null +++ b/portable/CCRH/F1Kx/portasm.s @@ -0,0 +1,325 @@ +;/* +; * FreeRTOS Kernel +; * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. +; * +; * SPDX-License-Identifier: MIT +; * +; * 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. +; * +; * https://www.FreeRTOS.org +; * https://github.com/FreeRTOS +; * +; */ + +;------------------------------------------------------------------------------ +; Extern symbols +;------------------------------------------------------------------------------ +.extern _uxInterruptNesting +.extern _uxPortMaxInterruptDepth +.extern _xPortScheduleStatus +.extern _vTaskSwitchContext +.extern _pvPortGetCurrentTCB +.extern _vCommonISRHandler +.extern _xPortGET_CORE_ID + +.public _vIrq_Handler +.public _vPortStartFirstTask +.public _vPortYield +.public _vTRAP0_Handler +;------------------------------------------------------------------------------ +; Macro definitions +;------------------------------------------------------------------------------ +EIPC .set 0 +EIPSW .set 1 +PSW .set 5 +FPSR .set 6 +FPEPC .set 7 +EIIC .set 13 +CTPC .set 16 +CTPSW .set 17 +EIIC_MSK .set 0x00000FFF +FPU_MSK .set 0x00010000 +;------------------------------------------------------------------------------ +; portSAVE_CONTEXT +; Context saving +;------------------------------------------------------------------------------ +portSAVE_CONTEXT .macro + prepare lp, 0 + + ; Save general-purpose registers and EIPSW, EIPC, EIIC, CTPSW, CTPC into stack. + pushsp r5, r30 + $nowarning + pushsp r1, r2 + $warning + + stsr EIPSW, r15 + stsr EIPC, r16 + stsr EIIC, r17 + stsr CTPSW, r18 + stsr CTPC, r19 + pushsp r15, r19 + + ; Save FPU registers to stack if FPU is enabled + mov FPU_MSK, r19 + tst r15, r19 + + ; Jump over next 3 instructions: stsr (4 bytes)*2 + pushsp (4 bytes) + bz 12 + stsr FPSR, r18 + stsr FPEPC, r19 + pushsp r18, r19 + + ; Get current TCB, the return value is stored in r10 (CCRH compiler) + jarl _pvPortGetCurrentTCB, lp + st.w sp, 0[r10] + +.endm + +;------------------------------------------------------------------------------ +; portRESTORE_CONTEXT +; Context restoring +;------------------------------------------------------------------------------ +portRESTORE_CONTEXT .macro + ; Current TCB is returned by r10 (CCRH compiler) + jarl _pvPortGetCurrentTCB, lp + ld.w 0[r10], sp ; Restore the stack pointer from the TCB + + ; Restore FPU registers if FPU is enabled + mov FPU_MSK, r19 + stsr PSW, r18 + tst r18, r19 + + ; Jump over next 3 instructions: stsr (4 bytes)*2 + popsp (4 bytes) + bz 12 + popsp r18, r19 + ldsr r18, FPEPC + ldsr r19, FPSR + + ;Restore general-purpose registers and EIPSW, EIPC, EIIC, CTPSW, CTPC + popsp r15, r19 + ldsr r19, CTPC + ldsr r18, CTPSW + ldsr r17, EIIC + ldsr r16, EIPC + ldsr r15, EIPSW + + $nowarning + popsp r1, r2 + $warning + popsp r5, r30 + + dispose 0, lp +.endm + +;------------------------------------------------------------------------------ +; Save used registers +;------------------------------------------------------------------------------ +SAVE_REGISTER .macro + ; Save general-purpose registers and EIPSW, EIPC, EIIC, CTPSW, CTPC into stack. + ; Callee-Save registers (r20 to r30) are not used in interrupt handler and + ; guaranteed no change after function call. So, don't need to save register + ; to optimize the used stack memory. + pushsp r5, r19 + $nowarning + pushsp r1, r2 + $warning + + stsr EIPSW, r19 + stsr EIPC, r18 + stsr EIIC, r17 + mov lp, r16 + mov ep, r15 + stsr CTPSW, r14 + stsr CTPC, r13 + pushsp r13, r19 + + mov FPU_MSK, r16 + tst r16, r19 + bz 12 + stsr FPSR, r18 + stsr FPEPC, r19 + pushsp r18, r19 + +.endm +;------------------------------------------------------------------------------ +; Restore used registers +;------------------------------------------------------------------------------ +RESTORE_REGISTER .macro + + mov FPU_MSK, r16 + stsr PSW, r18 + tst r18, r19 + bz 12 + popsp r18, r19 + ldsr r18, FPEPC + ldsr r19, FPSR + + popsp r13, r19 + ldsr r13, CTPC + ldsr r14, CTPSW + mov r15, ep + mov r16, lp + ldsr r17, EIIC + ldsr r18, EIPC + ldsr r19, EIPSW + + $nowarning + popsp r1, r2 + $warning + popsp r5, r19 +.endm + +;------------------------------------------------------------------------------ +; Start the first task. +;------------------------------------------------------------------------------ +_vPortStartFirstTask: + portRESTORE_CONTEXT + eiret + +;------------------------------------------------------------------------------ +; _vPortYield +;------------------------------------------------------------------------------ +_vPortYield: + trap 0 + jmp [lp] ; Return to caller function + +;------------------------------------------------------------------------------ +; PortYield handler. This is installed as the TRAP exception handler. +;------------------------------------------------------------------------------ +_vTRAP0_Handler: + ;Save the context of the current task. + portSAVE_CONTEXT + + ; The use case that portYield() is called from interrupt context as nested interrupt. + ; Context switch should be executed at the most outer of interrupt tree. + ; In that case, set xPortScheduleStatus to flag context switch in interrupt handler. + jarl _xPortGET_CORE_ID, lp ; return value is contained in r10 (CCRH compiler) + mov r10, r11 + shl 2, r11 + mov #_uxInterruptNesting, r19 + add r11, r19 + ld.w 0[r19], r18 + cmp r0, r18 + be _vTRAP0_Handler_ContextSwitch + + mov #_xPortScheduleStatus, r19 + add r11, r19 + + ; Set xPortScheduleStatus[coreID]=PORT_SCHEDULER_TASKSWITCH + mov 1, r17 + st.w r17, 0[r19] + br _vTRAP0_Handler_Exit + +_vTRAP0_Handler_ContextSwitch: + ; Pass coreID (r10) as parameter by r6 (CCRH compiler) in SMP support. + mov r10, r6 + ; Call the scheduler to select the next task. + ; vPortYeild may be called to current core again at the end of vTaskSwitchContext. + ; This may case nested interrupt, however, it is not necessary to set + ; uxInterruptNesting (currently 0) for nested trap0 exception. The user interrupt + ; (EI level interrupt) is not accepted inside of trap0 exception. + jarl _vTaskSwitchContext, lp + +_vTRAP0_Handler_Exit: + ; Restore the context of the next task to run. + portRESTORE_CONTEXT + eiret + +;------------------------------------------------------------------------------ +; _Irq_Handler +; Handler interrupt service routine (ISR). +;------------------------------------------------------------------------------ +_vIrq_Handler: + ; Save used registers. + SAVE_REGISTER + + ; Get core ID by HTCFG0, thread configuration register. + ; Then, increase nesting count for current core. + jarl _xPortGET_CORE_ID, lp ; return value is contained in r10 (CCRH compiler) + shl 2, r10 + mov r10, r17 + + mov #_uxInterruptNesting, r19 + add r17, r19 + ld.w 0[r19], r18 + addi 0x1, r18, r16 + st.w r16, 0[r19] + + pushsp r17, r19 + + ;Call the interrupt handler. + stsr EIIC, r6 + andi EIIC_MSK, r6, r6 + + ; Do not enable interrupt for nesting. Stackover flow may occurs if the + ; depth of nesting interrupt is exceeded. + mov #_uxPortMaxInterruptDepth, r15 + cmp r16, r15 + be 4 ; Jump over ei instruction + ei + jarl _vCommonISRHandler, lp + di + synce + + popsp r17, r19 + st.w r18, 0[r19] ; Restore the old nesting count. + + ; A context switch if no nesting interrupt. + cmp 0x0, r18 + bne _vIrq_Handler_NotSwitchContext + + ; Check if context switch is requested. + mov #_xPortScheduleStatus, r19 + add r17, r19 + ld.w 0[r19], r18 + cmp r0, r18 + bne _vIrq_Handler_SwitchContext + +_vIrq_Handler_NotSwitchContext: + ; No context switch. Restore used registers + RESTORE_REGISTER + eiret + +;This sequence is executed for primary core only to switch context +_vIrq_Handler_SwitchContext: + ; Clear the context switch pending flag. + st.w r0, 0[r19] + + add -1, r18 + bnz _vIrq_Handler_StartFirstTask + ; Restore used registers before saving the context to the task stack. + RESTORE_REGISTER + portSAVE_CONTEXT + + ; Get Core ID and pass to vTaskSwitchContext as parameter (CCRH compiler) + ; The parameter is unused in single core, no problem with this redudant setting + jarl _xPortGET_CORE_ID, lp ; return value is contained in r10 (CCRH compiler) + mov r10, r6 + + ; vPortYeild may be called to current core again at the end of vTaskSwitchContext. + ; This may case nested interrupt, however, it is not necessary to set + ; uxInterruptNesting (currently 0) for trap0 exception. The user interrupt + ; (EI level interrupt) is not accepted inside of trap0 exception. + jarl _vTaskSwitchContext, lp ; + portRESTORE_CONTEXT + eiret + +_vIrq_Handler_StartFirstTask: + RESTORE_REGISTER + jr _vPortStartFirstTask + diff --git a/portable/CCRH/F1Kx/portmacro.h b/portable/CCRH/F1Kx/portmacro.h new file mode 100644 index 00000000000..e2b41f2640b --- /dev/null +++ b/portable/CCRH/F1Kx/portmacro.h @@ -0,0 +1,193 @@ +/* + * FreeRTOS Kernel + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * 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. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +#ifndef PORTMACRO_H + #define PORTMACRO_H + + #ifdef __cplusplus + extern "C" + { + #endif + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* Type definitions - These are a bit legacy and not really used now, other + * than portSTACK_TYPE and portBASE_TYPE. */ + #define portCHAR char + #define portFLOAT float + #define portDOUBLE double + #define portLONG long + #define portSHORT short + #define portSTACK_TYPE uint32_t + #define portBASE_TYPE long + + typedef portSTACK_TYPE StackType_t; + typedef long BaseType_t; + typedef unsigned long UBaseType_t; + +/* Defines the maximum time when using a wait command in a task */ + #if ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS ) + typedef uint16_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffff + #elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS ) + typedef uint32_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffffffffUL + +/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do + * not need to be guarded with a critical section. */ + #define portTICK_TYPE_IS_ATOMIC 1 + #else + #error configTICK_TYPE_WIDTH_IN_BITS set to unsupported tick type width. + #endif + +/*-----------------------------------------------------------*/ + +/* Architecture specifics */ + + #define portSTSR( reg ) __stsr( ( reg ) ) + #define portLDSR( reg, val ) __ldsr( ( reg ), ( val ) ) + #define portSTSR_CCRH( reg, sel ) __stsr_rh( ( reg ), ( sel ) ) + #define portSYNCM() __syncm() + +/* Determine the descending of the stack from high address to address */ + #define portSTACK_GROWTH ( -1 ) + +/* Determine the time (in milliseconds) corresponding to each tick */ + #define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) + +/* It is a multiple of 4 (the two lower-order bits of the address = 0), + * otherwise it will cause MAE (Misaligned Exception) according to the manual */ + #define portBYTE_ALIGNMENT ( 4 ) + +/* Interrupt control macros. */ + + #define portENABLE_INTERRUPTS() __EI() /* Macro to enable all maskable interrupts. */ + #define portDISABLE_INTERRUPTS() __DI() /* Macro to disable all maskable interrupts. */ + #define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS() + #define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS() + +/* SMP build which means configNUM_CORES is relevant */ + #define portSUPPORT_SMP 1 + + #define portMAX_CORE_COUNT 2 + #ifndef configNUMBER_OF_CORES + #define configNUMBER_OF_CORES 1 + #endif + +/*-----------------------------------------------------------*/ +/* Scheduler utilities */ + +/* Called at the end of an ISR that can cause a context switch */ + extern void vPortSetSwitch( BaseType_t vPortSetSwitch ); + + #define portEND_SWITCHING_ISR( xSwitchRequired ) vPortSetSwitch( vPortSetSwitch ) + + #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) + +/* Use to transfer control from one task to perform other tasks of + * higher priority */ + extern void vPortYield( void ); + + #define portYIELD() vPortYield() + #if ( configNUMBER_OF_CORES > 1 ) + +/* Return the core ID on which the code is running. */ + extern BaseType_t xPortGET_CORE_ID(); + + #define portGET_CORE_ID() xPortGET_CORE_ID() + #define coreid xPortGET_CORE_ID() + +/* Request the core ID x to yield. */ + extern void vPortYieldCore( unsigned int coreID ); + + #define portYIELD_CORE( x ) vPortYieldCore( x ) + + #define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR() + #define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x ) + + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ + + #if ( configNUMBER_OF_CORES == 1 ) + #define portGET_ISR_LOCK() + #define portRELEASE_ISR_LOCK() + #define portGET_TASK_LOCK() + #define portRELEASE_TASK_LOCK() + #else + extern void vPortRecursiveLockAcquire( BaseType_t xFromIsr ); + extern void vPortRecursiveLockRelease( BaseType_t xFromIsr ); + + #define portGET_ISR_LOCK() vPortRecursiveLockAcquire( pdTRUE ) + #define portRELEASE_ISR_LOCK() vPortRecursiveLockRelease( pdTRUE ) + #define portGET_TASK_LOCK() vPortRecursiveLockAcquire( pdFALSE ) + #define portRELEASE_TASK_LOCK() vPortRecursiveLockRelease( pdFALSE ) + #endif /* if ( configNUMBER_OF_CORES == 1 ) */ + +/*-----------------------------------------------------------*/ +/* Critical section management. */ + +/* The critical nesting functions defined within tasks.c */ + + extern void vTaskEnterCritical( void ); + extern void vTaskExitCritical( void ); + +/* Macro to mark the start of a critical code region */ + #define portENTER_CRITICAL() vTaskEnterCritical() + +/* Macro to mark the end of a critical code region */ + #define portEXIT_CRITICAL() vTaskExitCritical() + +/*-----------------------------------------------------------*/ +/* Macros to set and clear the interrupt mask. */ + portLONG xPortSetInterruptMask(); + void vPortClearInterruptMask( portLONG ); + + #define portSET_INTERRUPT_MASK() xPortSetInterruptMask() + #define portCLEAR_INTERRUPT_MASK( x ) vPortClearInterruptMask( ( x ) ) + #define portSET_INTERRUPT_MASK_FROM_ISR() xPortSetInterruptMask() + #define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vPortClearInterruptMask( ( x ) ) + +/*-----------------------------------------------------------*/ +/* Task function macros as described on the FreeRTOS.org WEB site. */ + + #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters ) + #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters ) + +/*-----------------------------------------------------------*/ + + #ifdef __cplusplus +} + #endif +#endif /* PORTMACRO_H */ From 190906aeaf7ee0a7a35d6e4b83d2b0fd34b14163 Mon Sep 17 00:00:00 2001 From: superroc Date: Mon, 12 Aug 2024 19:36:47 +0800 Subject: [PATCH 3/8] Add portMEMORY_BARRIER defination to fix over-optimization in xTaskResumeAll. (#1116) Co-authored-by: owen --- portable/ThirdParty/XCC/Xtensa/portmacro.h | 1 + 1 file changed, 1 insertion(+) diff --git a/portable/ThirdParty/XCC/Xtensa/portmacro.h b/portable/ThirdParty/XCC/Xtensa/portmacro.h index d6a79b9bea7..dced2382ca4 100644 --- a/portable/ThirdParty/XCC/Xtensa/portmacro.h +++ b/portable/ThirdParty/XCC/Xtensa/portmacro.h @@ -114,6 +114,7 @@ static inline unsigned portENTER_CRITICAL_NESTED() { unsigned state = XTOS_SET_I #define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) #define portBYTE_ALIGNMENT 4 #define portNOP() XT_NOP() +#define portMEMORY_BARRIER() XT_MEMW() /*-----------------------------------------------------------*/ /* Fine resolution time */ From 40dbccf1421e0af28a9525129e25fa6e15ac954b Mon Sep 17 00:00:00 2001 From: xuelix <33909469+xuelix@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:47:30 -0700 Subject: [PATCH 4/8] =?UTF-8?q?Updated=20the=20return=20values=20for=20fun?= =?UTF-8?q?ctions=20in=20queue.c=20based=20on=20the=20actua=E2=80=A6=20(#1?= =?UTF-8?q?117)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Updated the return values for functions in queue.c based on the actual code. --- include/queue.h | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/include/queue.h b/include/queue.h index 80345b9f02e..963904bb38e 100644 --- a/include/queue.h +++ b/include/queue.h @@ -109,7 +109,7 @@ typedef struct QueueDefinition * QueueSetMemberHandle_t; * the same size. * * @return If the queue is successfully create then a handle to the newly - * created queue is returned. If the queue cannot be created then 0 is + * created queue is returned. If the queue cannot be created then NULL is * returned. * * Example usage: @@ -126,7 +126,7 @@ typedef struct QueueDefinition * QueueSetMemberHandle_t; * * // Create a queue capable of containing 10 uint32_t values. * xQueue1 = xQueueCreate( 10, sizeof( uint32_t ) ); - * if( xQueue1 == 0 ) + * if( xQueue1 == NULL ) * { * // Queue was not created and must not be used. * } @@ -134,7 +134,7 @@ typedef struct QueueDefinition * QueueSetMemberHandle_t; * // Create a queue capable of containing 10 pointers to AMessage structures. * // These should be passed by pointer as they contain a lot of data. * xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) ); - * if( xQueue2 == 0 ) + * if( xQueue2 == NULL ) * { * // Queue was not created and must not be used. * } @@ -292,7 +292,7 @@ typedef struct QueueDefinition * QueueSetMemberHandle_t; * queue is full. The time is defined in tick periods so the constant * portTICK_PERIOD_MS should be used to convert to real time if this is required. * - * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * @return pdPASS if the item was successfully posted, otherwise errQUEUE_FULL. * * Example usage: * @code{c} @@ -375,7 +375,7 @@ typedef struct QueueDefinition * QueueSetMemberHandle_t; * is full. The time is defined in tick periods so the constant * portTICK_PERIOD_MS should be used to convert to real time if this is required. * - * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * @return pdPASS if the item was successfully posted, otherwise errQUEUE_FULL. * * Example usage: * @code{c} @@ -460,7 +460,7 @@ typedef struct QueueDefinition * QueueSetMemberHandle_t; * queue is full. The time is defined in tick periods so the constant * portTICK_PERIOD_MS should be used to convert to real time if this is required. * - * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * @return pdPASS if the item was successfully posted, otherwise errQUEUE_FULL. * * Example usage: * @code{c} @@ -633,7 +633,7 @@ typedef struct QueueDefinition * QueueSetMemberHandle_t; * item at the back of the queue, or queueSEND_TO_FRONT to place the item * at the front of the queue (for high priority messages). * - * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL. + * @return pdPASS if the item was successfully posted, otherwise errQUEUE_FULL. * * Example usage: * @code{c} @@ -723,8 +723,8 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, * xQueuePeek() will return immediately if xTicksToWait is 0 and the queue * is empty. * - * @return pdTRUE if an item was successfully received from the queue, - * otherwise pdFALSE. + * @return pdPASS if an item was successfully received from the queue, + * otherwise errQUEUE_EMPTY. * * Example usage: * @code{c} @@ -811,8 +811,8 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue, * @param pvBuffer Pointer to the buffer into which the received item will * be copied. * - * @return pdTRUE if an item was successfully received from the queue, - * otherwise pdFALSE. + * @return pdPASS if an item was successfully received from the queue, + * otherwise pdFAIL. * * \defgroup xQueuePeekFromISR xQueuePeekFromISR * \ingroup QueueManagement @@ -852,8 +852,8 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, * constant portTICK_PERIOD_MS should be used to convert to real time if this is * required. * - * @return pdTRUE if an item was successfully received from the queue, - * otherwise pdFALSE. + * @return pdPASS if an item was successfully received from the queue, + * otherwise errQUEUE_EMPTY. * * Example usage: * @code{c} @@ -998,7 +998,7 @@ void vQueueDelete( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; * running task. If xQueueSendToFrontFromISR() sets this value to pdTRUE then * a context switch should be requested before the interrupt is exited. * - * @return pdTRUE if the data was successfully sent to the queue, otherwise + * @return pdPASS if the data was successfully sent to the queue, otherwise * errQUEUE_FULL. * * Example usage for buffered IO (where the ISR can obtain more than one value @@ -1070,7 +1070,7 @@ void vQueueDelete( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; * running task. If xQueueSendToBackFromISR() sets this value to pdTRUE then * a context switch should be requested before the interrupt is exited. * - * @return pdTRUE if the data was successfully sent to the queue, otherwise + * @return pdPASS if the data was successfully sent to the queue, otherwise * errQUEUE_FULL. * * Example usage for buffered IO (where the ISR can obtain more than one value @@ -1235,7 +1235,7 @@ void vQueueDelete( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; * running task. If xQueueSendFromISR() sets this value to pdTRUE then * a context switch should be requested before the interrupt is exited. * - * @return pdTRUE if the data was successfully sent to the queue, otherwise + * @return pdPASS if the data was successfully sent to the queue, otherwise * errQUEUE_FULL. * * Example usage for buffered IO (where the ISR can obtain more than one value @@ -1318,7 +1318,7 @@ void vQueueDelete( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; * item at the back of the queue, or queueSEND_TO_FRONT to place the item * at the front of the queue (for high priority messages). * - * @return pdTRUE if the data was successfully sent to the queue, otherwise + * @return pdPASS if the data was successfully sent to the queue, otherwise * errQUEUE_FULL. * * Example usage for buffered IO (where the ISR can obtain more than one value @@ -1389,8 +1389,8 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, * to unblock *pxTaskWoken will get set to pdTRUE, otherwise *pxTaskWoken will * remain unchanged. * - * @return pdTRUE if an item was successfully received from the queue, - * otherwise pdFALSE. + * @return pdPASS if an item was successfully received from the queue, + * otherwise pdFAIL. * * Example usage: * @code{c} From a936c10e2c2eab24e625ce6b8d27b6d88c22808a Mon Sep 17 00:00:00 2001 From: xuelix <33909469+xuelix@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:08:32 -0700 Subject: [PATCH 5/8] Modify the name of a private function to reflect what it actually does (#1119) --- queue.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/queue.c b/queue.c index dd302c90889..1a14c743d8a 100644 --- a/queue.c +++ b/queue.c @@ -247,7 +247,7 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, * other tasks that are waiting for the same mutex. This function returns * that priority. */ - static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue ) PRIVILEGED_FUNCTION; + static UBaseType_t prvGetHighestPriorityOfWaitToReceiveList( const Queue_t * const pxQueue ) PRIVILEGED_FUNCTION; #endif /*-----------------------------------------------------------*/ @@ -1844,13 +1844,13 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, * has timed out the priority should be disinherited * again, but only as low as the next highest priority * task that is waiting for the same mutex. */ - uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue ); + uxHighestWaitingPriority = prvGetHighestPriorityOfWaitToReceiveList( pxQueue ); /* vTaskPriorityDisinheritAfterTimeout uses the uxHighestWaitingPriority * parameter to index pxReadyTasksLists when adding the task holding * mutex to the ready list for its new priority. Coverity thinks that * it can result in out-of-bounds access which is not true because - * uxHighestWaitingPriority, as returned by prvGetDisinheritPriorityAfterTimeout, + * uxHighestWaitingPriority, as returned by prvGetHighestPriorityOfWaitToReceiveList, * is capped at ( configMAX_PRIORITIES - 1 ). */ /* coverity[overrun] */ vTaskPriorityDisinheritAfterTimeout( pxQueue->u.xSemaphore.xMutexHolder, uxHighestWaitingPriority ); @@ -2362,7 +2362,7 @@ UBaseType_t uxQueueGetQueueLength( QueueHandle_t xQueue ) /* PRIVILEGED_FUNCTION #if ( configUSE_MUTEXES == 1 ) - static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue ) + static UBaseType_t prvGetHighestPriorityOfWaitToReceiveList( const Queue_t * const pxQueue ) { UBaseType_t uxHighestPriorityOfWaitingTasks; From 294569e495515e238dc890a8b4613d01260d1f06 Mon Sep 17 00:00:00 2001 From: Chen YM Date: Mon, 19 Aug 2024 13:04:33 +0800 Subject: [PATCH 6/8] Optimize xTaskIncrementTick for configNUMBER_OF_CORES > 1 (#1118) The original implementation only initializes the first variable. After executing xTaskIncrementTick, the schedule might not behave as expected. When configUSE_PREEMPTION == 1 & configUSE_TIME_SLICING == 1, replace setting xYieldRequiredForCore[ xCoreID ] with setting xYieldPendings[ xCoreID ]. And when configUSE_PREEMPTION == 1, simplify the check condition to only check xYieldPendings[ xCoreID ]. Signed-off-by: cymzier Co-authored-by: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> --- tasks.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tasks.c b/tasks.c index 3382954b806..cb3c190b938 100644 --- a/tasks.c +++ b/tasks.c @@ -4698,10 +4698,6 @@ BaseType_t xTaskIncrementTick( void ) TickType_t xItemValue; BaseType_t xSwitchRequired = pdFALSE; - #if ( configUSE_PREEMPTION == 1 ) && ( configNUMBER_OF_CORES > 1 ) - BaseType_t xYieldRequiredForCore[ configNUMBER_OF_CORES ] = { pdFALSE }; - #endif /* #if ( configUSE_PREEMPTION == 1 ) && ( configNUMBER_OF_CORES > 1 ) */ - traceENTER_xTaskIncrementTick(); /* Called by the portable layer each time a tick interrupt occurs. @@ -4853,7 +4849,7 @@ BaseType_t xTaskIncrementTick( void ) { if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCBs[ xCoreID ]->uxPriority ] ) ) > 1U ) { - xYieldRequiredForCore[ xCoreID ] = pdTRUE; + xYieldPendings[ xCoreID ] = pdTRUE; } else { @@ -4905,7 +4901,7 @@ BaseType_t xTaskIncrementTick( void ) if( pxCurrentTCBs[ xCoreID ]->xPreemptionDisable == pdFALSE ) #endif { - if( ( xYieldRequiredForCore[ xCoreID ] != pdFALSE ) || ( xYieldPendings[ xCoreID ] != pdFALSE ) ) + if( xYieldPendings[ xCoreID ] != pdFALSE ) { if( xCoreID == xCurrentCoreID ) { From 49e88310bec6f54f7cfe9db94edf3fb97e7d4ccc Mon Sep 17 00:00:00 2001 From: Rahul Kar <118818625+kar-rahul-aws@users.noreply.github.com> Date: Mon, 19 Aug 2024 05:37:24 +0000 Subject: [PATCH 7/8] Fix compilation issue of IA32_flat port (#1122) * Fix compilation issue of IAR32 port * Add new line at EOF * Fix header check --------- Co-authored-by: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> --- portable/GCC/IA32_flat/ISR_Support.h | 145 +++++++++++++-------------- 1 file changed, 71 insertions(+), 74 deletions(-) diff --git a/portable/GCC/IA32_flat/ISR_Support.h b/portable/GCC/IA32_flat/ISR_Support.h index 545a8d23634..18e10bf91e7 100644 --- a/portable/GCC/IA32_flat/ISR_Support.h +++ b/portable/GCC/IA32_flat/ISR_Support.h @@ -26,106 +26,103 @@ * */ -.extern ulTopOfSystemStack - .extern ulInterruptNesting + .extern ulTopOfSystemStack + .extern ulInterruptNesting /*-----------------------------------------------------------*/ - .macro portFREERTOS_INTERRUPT_ENTRY +.macro portFREERTOS_INTERRUPT_ENTRY -/* Save general purpose registers. */ -pusha + /* Save general purpose registers. */ + pusha -/* If ulInterruptNesting is zero the rest of the task context will need - * saving and a stack switch might be required. */ -movl ulInterruptNesting, % eax -test % eax, % eax -jne 2f + /* If ulInterruptNesting is zero the rest of the task context will need + saving and a stack switch might be required. */ + movl ulInterruptNesting, %eax + test %eax, %eax + jne 2f -/* Interrupts are not nested, so save the rest of the task context. */ - . + /* Interrupts are not nested, so save the rest of the task context. */ + .if configSUPPORT_FPU == 1 - if configSUPPORT_FPU == 1 + /* If the task has a buffer allocated to save the FPU context then + save the FPU context now. */ + movl pucPortTaskFPUContextBuffer, %eax + test %eax, %eax + je 1f + fnsave ( %eax ) /* Save FLOP context into ucTempFPUBuffer array. */ + fwait -/* If the task has a buffer allocated to save the FPU context then - * save the FPU context now. */ -movl pucPortTaskFPUContextBuffer, % eax -test % eax, % eax -je 1f -fnsave( % eax ) /* Save FLOP context into ucTempFPUBuffer array. */ -fwait + 1: + /* Save the address of the FPU context, if any. */ + push pucPortTaskFPUContextBuffer -1 : -/* Save the address of the FPU context, if any. */ -push pucPortTaskFPUContextBuffer + .endif /* configSUPPORT_FPU */ - .endif /* configSUPPORT_FPU */ + /* Find the TCB. */ + movl pxCurrentTCB, %eax -/* Find the TCB. */ -movl pxCurrentTCB, % eax + /* Stack location is first item in the TCB. */ + movl %esp, (%eax) -/* Stack location is first item in the TCB. */ - movl % esp, ( % eax ) + /* Switch stacks. */ + movl ulTopOfSystemStack, %esp + movl %esp, %ebp -/* Switch stacks. */ -movl ulTopOfSystemStack, % esp -movl % esp, % ebp + 2: + /* Increment nesting count. */ + add $1, ulInterruptNesting -2 : -/* Increment nesting count. */ -add $1, ulInterruptNesting - - .endm +.endm /*-----------------------------------------------------------*/ - .macro portINTERRUPT_EPILOGUE - -cli -sub $1, ulInterruptNesting +.macro portINTERRUPT_EPILOGUE -/* If the nesting has unwound to zero. */ -movl ulInterruptNesting, % eax - test % eax, % eax - jne 2f + cli + sub $1, ulInterruptNesting -/* If a yield was requested then select a new TCB now. */ -movl ulPortYieldPending, % eax - test % eax, % eax - je 1f -movl $0, ulPortYieldPending -call vTaskSwitchContext + /* If the nesting has unwound to zero. */ + movl ulInterruptNesting, %eax + test %eax, %eax + jne 2f -1 : -/* Stack location is first item in the TCB. */ -movl pxCurrentTCB, % eax movl( % eax ), % esp + /* If a yield was requested then select a new TCB now. */ + movl ulPortYieldPending, %eax + test %eax, %eax + je 1f + movl $0, ulPortYieldPending + call vTaskSwitchContext - . + 1: + /* Stack location is first item in the TCB. */ + movl pxCurrentTCB, %eax + movl (%eax), %esp - if configSUPPORT_FPU == 1 + .if configSUPPORT_FPU == 1 -/* Restore address of task's FPU context buffer. */ -pop pucPortTaskFPUContextBuffer + /* Restore address of task's FPU context buffer. */ + pop pucPortTaskFPUContextBuffer -/* If the task has a buffer allocated in which its FPU context is saved, - * then restore it now. */ -movl pucPortTaskFPUContextBuffer, % eax -test % eax, % eax -je 1f -frstor( % eax ) -1 : -.endif + /* If the task has a buffer allocated in which its FPU context is saved, + then restore it now. */ + movl pucPortTaskFPUContextBuffer, %eax + test %eax, %eax + je 1f + frstor ( %eax ) + 1: + .endif -2 : -popa + 2: + popa - .endm +.endm /*-----------------------------------------------------------*/ - .macro portFREERTOS_INTERRUPT_EXIT +.macro portFREERTOS_INTERRUPT_EXIT -portINTERRUPT_EPILOGUE -/* EOI. */ -movl $0x00, ( 0xFEE000B0 ) -iret + portINTERRUPT_EPILOGUE + /* EOI. */ + movl $0x00, (0xFEE000B0) + iret - .endm +.endm From 2faa8bc1541355b20f25ef4d47d1c1e48c81810a Mon Sep 17 00:00:00 2001 From: mayl <192939+mayl@users.noreply.github.com> Date: Mon, 19 Aug 2024 02:01:30 -0400 Subject: [PATCH 8/8] Remove hardware dependence in portmacros.h (#1112) * Remove hardware dependence in portmacros.h The IAR MSP430X port `#include "msp430.h"` which pulls all the hardware register definitions into anything which `#include "FreeRTOS.h"`. This removes that hardware dependency "leak" by removing the header file and re-defining the `portDISABLE_INTERRUPTS()` and `portENABLE_INTERRUPTS()` macros in terms of `__asm`. * Code review suggestions Signed-off-by: Gaurav Aggarwal --------- Signed-off-by: Gaurav Aggarwal Co-authored-by: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> Co-authored-by: Gaurav Aggarwal --- portable/CCS/MSP430X/port.c | 3 +++ portable/CCS/MSP430X/portmacro.h | 9 +++------ portable/IAR/MSP430X/port.c | 3 +++ portable/IAR/MSP430X/portmacro.h | 9 +++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/portable/CCS/MSP430X/port.c b/portable/CCS/MSP430X/port.c index 186fb2cdd45..2097a293189 100644 --- a/portable/CCS/MSP430X/port.c +++ b/portable/CCS/MSP430X/port.c @@ -26,6 +26,9 @@ * */ +/* Hardware includes. */ +#include "msp430.h" + /* Scheduler includes. */ #include "FreeRTOS.h" #include "task.h" diff --git a/portable/CCS/MSP430X/portmacro.h b/portable/CCS/MSP430X/portmacro.h index 91e2b9c5b5f..c00c5a90266 100644 --- a/portable/CCS/MSP430X/portmacro.h +++ b/portable/CCS/MSP430X/portmacro.h @@ -39,9 +39,6 @@ *----------------------------------------------------------- */ -/* Hardware includes. */ -#include "msp430.h" - /* Type definitions. */ #define portCHAR char #define portFLOAT float @@ -75,8 +72,8 @@ typedef unsigned short UBaseType_t; /*-----------------------------------------------------------*/ /* Interrupt control macros. */ -#define portDISABLE_INTERRUPTS() _disable_interrupt(); _nop() -#define portENABLE_INTERRUPTS() _enable_interrupt(); _nop() +#define portDISABLE_INTERRUPTS() __asm volatile ( " DINT\n" " NOP" ) +#define portENABLE_INTERRUPTS() __asm volatile ( " NOP\n" " EINT\n" " NOP" ) /*-----------------------------------------------------------*/ /* Critical section control macros. */ @@ -126,7 +123,7 @@ extern void vPortYield( void ); #define portBYTE_ALIGNMENT 2 #define portSTACK_GROWTH ( -1 ) #define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) -#define portNOP() __no_operation() +#define portNOP() __asm volatile ( " NOP" ) /*-----------------------------------------------------------*/ /* Task function macros as described on the FreeRTOS.org WEB site. */ diff --git a/portable/IAR/MSP430X/port.c b/portable/IAR/MSP430X/port.c index a6f81580b82..6c5b21c3a2c 100644 --- a/portable/IAR/MSP430X/port.c +++ b/portable/IAR/MSP430X/port.c @@ -30,6 +30,9 @@ #include "FreeRTOS.h" #include "task.h" +/* Hardware includes. */ +#include "msp430.h" + /*----------------------------------------------------------- * Implementation of functions defined in portable.h for the MSP430X port. *----------------------------------------------------------*/ diff --git a/portable/IAR/MSP430X/portmacro.h b/portable/IAR/MSP430X/portmacro.h index e426154e891..b428f8d405d 100644 --- a/portable/IAR/MSP430X/portmacro.h +++ b/portable/IAR/MSP430X/portmacro.h @@ -39,9 +39,6 @@ *----------------------------------------------------------- */ -/* Hardware includes. */ -#include "msp430.h" - /* Type definitions. */ #define portCHAR char #define portFLOAT float @@ -75,8 +72,8 @@ typedef unsigned short UBaseType_t; /*-----------------------------------------------------------*/ /* Interrupt control macros. */ -#define portDISABLE_INTERRUPTS() _DINT(); _NOP() -#define portENABLE_INTERRUPTS() _EINT(); _NOP() +#define portDISABLE_INTERRUPTS() __asm volatile ( "DINT\n" "NOP" ) +#define portENABLE_INTERRUPTS() __asm volatile ( "NOP\n" "EINT\n" "NOP" ) /*-----------------------------------------------------------*/ /* Critical section control macros. */ @@ -126,7 +123,7 @@ extern void vPortYield( void ); #define portBYTE_ALIGNMENT 2 #define portSTACK_GROWTH ( -1 ) #define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) -#define portNOP() __no_operation() +#define portNOP() __asm volatile ( "NOP" ) /*-----------------------------------------------------------*/ /* Task function macros as described on the FreeRTOS.org WEB site. */