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] 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 0ba0be7c5b..42f9196d7d 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 0000000000..7583c67aff --- /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 0000000000..e3d71929d8 --- /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 0000000000..4e56f44939 --- /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 0000000000..e2b41f2640 --- /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 */