diff --git a/portable/GCC/RX/port.c b/portable/GCC/RX/port.c new file mode 100644 index 0000000000..f7be7cd997 --- /dev/null +++ b/portable/GCC/RX/port.c @@ -0,0 +1,834 @@ +/* + * 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 + * + */ + +/*----------------------------------------------------------- +* Implementation of functions defined in portable.h for the Renesas RX port. +*----------------------------------------------------------*/ + +/* Scheduler includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Library includes. */ +#include "string.h" + +/* Hardware specifics. */ +#if ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 0 ) + #include "iodefine.h" +#elif ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 1 ) + #include "platform.h" +#elif ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 2 ) + /* Nothing to be included here. */ +#else + #error Invalid configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H setting - configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H must be set to 0, 1, 2, or left undefined. +#endif + +/* Miscellaneous checks for this port. */ +#if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) || ( configUSE_TASK_DPFPU_SUPPORT == 2 ) + #warning Testing for DPFPU support in this port is not yet complete +#elif ( configUSE_TASK_DPFPU_SUPPORT != 0 ) + #error Invalid configUSE_TASK_DPFPU_SUPPORT setting - configUSE_TASK_DPFPU_SUPPORT must be set to 0, 1, 2, or left undefined. +#endif + +#if !defined( __RXv1__ ) && !defined( __RXv2__ ) && !defined( __RXv3__ ) + #if ( __GNUC__ < 8 ) + /* Not necessary: #error This old version of GNURX is not supported. */ + #else + #warning This new CPU core may not be supported. + #endif +#endif + +#if !defined( __STDC_VERSION__ ) || ( __STDC_VERSION__ < 199901L ) + #error This port needs C99 or later. +#endif + +/*-----------------------------------------------------------*/ + +/* Tasks should start with interrupts enabled and in Supervisor mode, therefore + * PSW is set with U and I set, and PM and IPL clear. */ +#define portINITIAL_PSW ( ( StackType_t ) 0x00030000 ) +#define portINITIAL_FPSW ( ( StackType_t ) 0x00000100 ) +#define portINITIAL_DPSW ( ( StackType_t ) 0x00000100 ) +#define portINITIAL_DCMR ( ( StackType_t ) 0x00000000 ) +#define portINITIAL_DECNT ( ( StackType_t ) 0x00000001 ) + +/* Tasks are not created with a DPFPU context, but can be given a DPFPU context + * after they have been created. A variable is stored as part of the tasks context + * that holds portNO_DPFPU_CONTEXT if the task does not have a DPFPU context, or + * any other value if the task does have a DPFPU context. */ +#define portNO_DPFPU_CONTEXT ( ( StackType_t ) 0 ) +#define portHAS_DPFPU_CONTEXT ( ( StackType_t ) 1 ) + +/* The space on the stack required to hold the general purpos registers. This is 16 + * 32-bit registers, except for R0 (for stack pointer) and R1 (for pvParameters). */ +#define portGENERAL_PURPOSE_REGISTER_WORDS ( 16 - 2 ) + +/* The space on the stack required to hold the accumulator. This is 2 or 6 + * 32-bit registers. */ +#if ( portUSE_TASK_ACC_SUPPORT == 1 ) + + #define portACCUMULATOR_REGISTER_WORDS ( 2 ) + +#elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + + #define portACCUMULATOR_REGISTER_WORDS ( 6 ) + +#endif /* portUSE_TASK_ACC_SUPPORT */ + +/* The space on the stack required to hold the DPFPU data registers. This is 16 + * 64-bit registers. */ +#define portDPFPU_DATA_REGISTER_WORDS ( 16 * 2 ) + +/*-----------------------------------------------------------*/ + +/* + * Function to start the first task executing - written in asm code as direct + * access to registers is required. + */ +static void prvStartFirstTask( void ) __attribute__( ( naked ) ); + +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ) __attribute__( ( naked, noinline ) ); + +/* + * Force an assert. + */ +static void prvForceAssert( void ) __attribute__( ( noinline ) ); + +/* + * Software interrupt handler. Performs the actual context switch (saving and + * restoring of registers). Written in asm code as direct register access is + * required. + */ +#if ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 1 ) + + R_BSP_PRAGMA_INTERRUPT( vSoftwareInterruptISR, _VECT( _ICU_SWINT ) ) + R_BSP_ATTRIB_INTERRUPT void vSoftwareInterruptISR( void ) __attribute__( ( naked ) ); + +#else + + void vSoftwareInterruptISR( void ) __attribute__( ( naked ) ); + +#endif /* if ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 1 ) */ + +/* + * The tick ISR handler. The peripheral used is configured by the application + * via a hook/callback function. + */ +#if ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 1 ) + + R_BSP_PRAGMA_INTERRUPT( vTickISR, _VECT( configTICK_VECTOR ) ) + R_BSP_ATTRIB_INTERRUPT void vTickISR( void ); /* Do not add __attribute__( ( interrupt ) ). */ + +#else + + void vTickISR( void ) __attribute__( ( interrupt ) ); + +#endif /* if ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 1 ) */ + +/*-----------------------------------------------------------*/ + +/* Saved as part of the task context. If ulPortTaskHasDPFPUContext is non-zero + * then a DPFPU context must be saved and restored for the task. */ +#if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + StackType_t ulPortTaskHasDPFPUContext = portNO_DPFPU_CONTEXT; + +#endif + +/* This is accessed by the inline assembler functions so is file scope for + * convenience. */ +extern void * pxCurrentTCB; +extern void vTaskSwitchContext( void ); + +/*-----------------------------------------------------------*/ + +/* + * See header file for description. + */ +StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, + TaskFunction_t pxCode, + void * pvParameters ) +{ + /* R0 is not included as it is the stack pointer. */ + + /* Prevent the debugger from messing up unwinding of the stack. */ + *pxTopOfStack = ( StackType_t ) 0x0; + pxTopOfStack--; + + /* '+ 1 ' is a workaround for preventing rx-elf-gdb from messing up. */ + *pxTopOfStack = ( ( StackType_t ) prvTaskExitError ) + 1; + pxTopOfStack--; + *pxTopOfStack = portINITIAL_PSW; + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) pxCode; + + /* When debugging it can be useful if every register is set to a known + * value. Otherwise code space can be saved by just setting the registers + * that need to be set. */ + #ifdef USE_FULL_REGISTER_INITIALISATION + { + pxTopOfStack--; + *pxTopOfStack = 0xffffffff; /* r15. */ + pxTopOfStack--; + *pxTopOfStack = 0xeeeeeeee; + pxTopOfStack--; + *pxTopOfStack = 0xdddddddd; + pxTopOfStack--; + *pxTopOfStack = 0xcccccccc; + pxTopOfStack--; + *pxTopOfStack = 0xbbbbbbbb; + pxTopOfStack--; + *pxTopOfStack = 0xaaaaaaaa; + pxTopOfStack--; + *pxTopOfStack = 0x99999999; + pxTopOfStack--; + *pxTopOfStack = 0x88888888; + pxTopOfStack--; + *pxTopOfStack = 0x77777777; + pxTopOfStack--; + *pxTopOfStack = 0x66666666; + pxTopOfStack--; + *pxTopOfStack = 0x55555555; + pxTopOfStack--; + *pxTopOfStack = 0x44444444; + pxTopOfStack--; + *pxTopOfStack = 0x33333333; + pxTopOfStack--; + *pxTopOfStack = 0x22222222; + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= portGENERAL_PURPOSE_REGISTER_WORDS; + memset( pxTopOfStack, 0x00, portGENERAL_PURPOSE_REGISTER_WORDS * sizeof( StackType_t ) ); + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) pvParameters; /* R1 */ + + #if ( portUSE_TASK_FPU_SUPPORT == 1 ) + { + pxTopOfStack--; + *pxTopOfStack = portINITIAL_FPSW; + } + #endif + + #if ( portUSE_TASK_ACC_SUPPORT == 1 ) + { + #ifdef USE_FULL_REGISTER_INITIALISATION + { + pxTopOfStack--; + *pxTopOfStack = 0x12345678; /* Accumulator. */ + pxTopOfStack--; + *pxTopOfStack = 0x87654321; /* Accumulator. */ + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= portACCUMULATOR_REGISTER_WORDS; + memset( pxTopOfStack, 0x00, portACCUMULATOR_REGISTER_WORDS * sizeof( StackType_t ) ); + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + } + #elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + { + #ifdef USE_FULL_REGISTER_INITIALISATION + { + pxTopOfStack--; + *pxTopOfStack = 0x11111111; /* Accumulator 1. */ + pxTopOfStack--; + *pxTopOfStack = 0x22222222; /* Accumulator 1. */ + pxTopOfStack--; + *pxTopOfStack = 0x33333333; /* Accumulator 1. */ + pxTopOfStack--; + *pxTopOfStack = 0x44444444; /* Accumulator 0. */ + pxTopOfStack--; + *pxTopOfStack = 0x55555555; /* Accumulator 0. */ + pxTopOfStack--; + *pxTopOfStack = 0x66666666; /* Accumulator 0. */ + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= portACCUMULATOR_REGISTER_WORDS; + memset( pxTopOfStack, 0x00, portACCUMULATOR_REGISTER_WORDS * sizeof( StackType_t ) ); + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + } + #endif /* portUSE_TASK_ACC_SUPPORT */ + + #if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + { + /* The task will start without a DPFPU context. A task that + * uses the DPFPU hardware must call vPortTaskUsesDPFPU() before + * executing any floating point instructions. */ + pxTopOfStack--; + *pxTopOfStack = portNO_DPFPU_CONTEXT; + } + #elif ( portUSE_TASK_DPFPU_SUPPORT == 2 ) + { + /* The task will start with a DPFPU context. Leave enough + * space for the registers - and ensure they are initialised if desired. */ + #ifdef USE_FULL_REGISTER_INITIALISATION + { + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1515.1515; /* DR15. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1414.1414; /* DR14. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1313.1313; /* DR13. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1212.1212; /* DR12. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1111.1111; /* DR11. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1010.1010; /* DR10. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 909.0909; /* DR9. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 808.0808; /* DR8. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 707.0707; /* DR7. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 606.0606; /* DR6. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 505.0505; /* DR5. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 404.0404; /* DR4. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 303.0303; /* DR3. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 202.0202; /* DR2. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 101.0101; /* DR1. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 9876.54321; /* DR0. */ + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= portDPFPU_DATA_REGISTER_WORDS; + memset( pxTopOfStack, 0x00, portDPFPU_DATA_REGISTER_WORDS * sizeof( StackType_t ) ); + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + pxTopOfStack--; + *pxTopOfStack = portINITIAL_DECNT; /* DECNT. */ + pxTopOfStack--; + *pxTopOfStack = portINITIAL_DCMR; /* DCMR. */ + pxTopOfStack--; + *pxTopOfStack = portINITIAL_DPSW; /* DPSW. */ + } + #endif /* portUSE_TASK_DPFPU_SUPPORT */ + + return pxTopOfStack; +} +/*-----------------------------------------------------------*/ + +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. */ + + /* Adding NOP is a workaround to prevent rx-elf-gdb from messing up. */ + portNOP(); + + /* Any function call other than portNOP() should not be inlined in this + * function to ensure the address of here is 'prvTaskExitError + 1'. */ + prvForceAssert(); +} +/*-----------------------------------------------------------*/ + +#if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + void vPortTaskUsesDPFPU( void ) + { + /* A task is registering the fact that it needs a DPFPU context. Set the + * DPFPU flag (which is saved as part of the task context). */ + ulPortTaskHasDPFPUContext = portHAS_DPFPU_CONTEXT; + } + +#endif /* portUSE_TASK_DPFPU_SUPPORT */ +/*-----------------------------------------------------------*/ + +BaseType_t xPortStartScheduler( void ) +{ + extern void vApplicationSetupTimerInterrupt( void ); + + /* Use pxCurrentTCB just so it does not get optimised away. */ + if( pxCurrentTCB != NULL ) + { + /* Call an application function to set up the timer that will generate the + * tick interrupt. This way the application can decide which peripheral to + * use. A demo application is provided to show a suitable example. */ + vApplicationSetupTimerInterrupt(); + + /* Enable the software interrupt. */ + _IEN( _ICU_SWINT ) = 1; + + /* Ensure the software interrupt is clear. */ + _IR( _ICU_SWINT ) = 0; + + /* Ensure the software interrupt is set to the kernel priority. */ + _IPR( _ICU_SWINT ) = configKERNEL_INTERRUPT_PRIORITY; + + /* Start the first task. */ + prvStartFirstTask(); + } + + /* Should not get here. */ + return pdFAIL; +} +/*-----------------------------------------------------------*/ + +void vPortEndScheduler( void ) +{ + /* Not implemented in ports where there is nothing to return to. + * Artificially force an assert. */ + prvForceAssert(); +} +/*-----------------------------------------------------------*/ + +static void prvForceAssert( void ) +{ + configASSERT( pxCurrentTCB == NULL ); + portDISABLE_INTERRUPTS(); + + for( ; ; ) + { + } +} +/*-----------------------------------------------------------*/ + +static void prvStartFirstTask( void ) +{ +/* *INDENT-OFF* */ +portASM_BEGIN + + /* When starting the scheduler there is nothing that needs moving to the + * interrupt stack because the function is not called from an interrupt. + * Just ensure the current stack is the user stack. */ + portASM( SETPSW U ) + + + /* Obtain the location of the stack associated with which ever task + * pxCurrentTCB is currently pointing to. */ + portASM( MOV.L #_pxCurrentTCB, R15 ) + portASM( MOV.L [ R15 ], R15 ) + portASM( MOV.L [ R15 ], R0 ) + + + /* Restore the registers from the stack of the task pointed to by + * pxCurrentTCB. */ + + #if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* The restored ulPortTaskHasDPFPUContext is to be zero here. + * So, it is never necessary to restore the DPFPU context here. */ + portASM( POP R15 ) + portASM( MOV.L #_ulPortTaskHasDPFPUContext, R14 ) + portASM( MOV.L R15, [ R14 ] ) + + #elif ( portUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Restore the DPFPU context. */ +#if defined(USE_PATCH_FOR_GNURX_202102_INTERNAL_TYPO) + /* The following code is a workaround for an internal typo of + * GNURX 8.3.0.202102. + * https://llvm-gcc-renesas.com/question/gnurx-8-3-0-202102-doesnt-recognize-decnt-register-rxv3/#li-comment-374 */ + portASM( DPOPM.L DPSW-DCENT ) +#else + /* The following code is correct but this code causes a compile error + * when using the above version of GNURX. */ + portASM( DPOPM.L DPSW-DECNT ) +#endif + portASM( DPOPM.D DR0-DR15 ) + + #endif /* portUSE_TASK_DPFPU_SUPPORT */ + + #if ( portUSE_TASK_ACC_SUPPORT == 1 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15 ) + + #elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15, A0 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15, A0 ) + + /* Accumulator guard. */ + portASM( POP R15 ) + portASM( MVTACGU R15, A0 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15, A1 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15, A1 ) + + /* Accumulator guard. */ + portASM( POP R15 ) + portASM( MVTACGU R15, A1 ) + + #endif /* portUSE_TASK_ACC_SUPPORT */ + + #if ( portUSE_TASK_FPU_SUPPORT == 1 ) + + /* Floating point status word. */ + portASM( POP R15 ) + portASM( MVTC R15, FPSW ) + + #endif + + /* R1 to R15 - R0 is not included as it is the SP. */ + portASM( POPM R1-R15 ) + + /* This pops the remaining registers. */ + portASM( RTE ) + portASM( NOP ) + portASM( NOP ) + +portASM_END +/* *INDENT-ON* */ +} +/*-----------------------------------------------------------*/ + +void vSoftwareInterruptISR( void ) +{ +/* *INDENT-OFF* */ +portASM_BEGIN + + /* Re-enable interrupts. */ + portASM( SETPSW I ) + + + /* Move the data that was automatically pushed onto the interrupt stack when + * the interrupt occurred from the interrupt stack to the user stack. + * + * R15 is saved before it is clobbered. */ + portASM( PUSH.L R15 ) + + /* Read the user stack pointer. */ + portASM( MVFC USP, R15 ) + + /* Move the address down to the data being moved. */ + portASM( SUB #12, R15 ) + portASM( MVTC R15, USP ) + + /* Copy the data across, R15, then PC, then PSW. */ + portASM( MOV.L [ R0 ], [ R15 ] ) + portASM( MOV.L 4[ R0 ], 4[ R15 ] ) + portASM( MOV.L 8[ R0 ], 8[ R15 ] ) + + /* Move the interrupt stack pointer to its new correct position. */ + portASM( ADD #12, R0 ) + + /* All the rest of the registers are saved directly to the user stack. */ + portASM( SETPSW U ) + + /* Save the rest of the general registers (R15 has been saved already). */ + portASM( PUSHM R1-R14 ) + + /* Save the FPSW and accumulators. */ + #if ( portUSE_TASK_FPU_SUPPORT == 1 ) + + portASM( MVFC FPSW, R15 ) + portASM( PUSH.L R15 ) + + #endif + + #if ( portUSE_TASK_ACC_SUPPORT == 1 ) + + /* Save the accumulator. */ + portASM( MVFACHI R15 ) + portASM( PUSH.L R15 ) + + /* Middle word. */ + portASM( MVFACMI R15 ) + + /* Shifted left as it is restored to the low order word. */ + portASM( SHLL #16, R15 ) + portASM( PUSH.L R15 ) + + #elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + + /* Accumulator guard. */ + portASM( MVFACGU #0, A1, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator high 32 bits. */ + portASM( MVFACHI #0, A1, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator low 32 bits. */ + portASM( MVFACLO #0, A1, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator guard. */ + portASM( MVFACGU #0, A0, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator high 32 bits. */ + portASM( MVFACHI #0, A0, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator low 32 bits. */ + portASM( MVFACLO #0, A0, R15 ) + portASM( PUSH.L R15 ) + + #endif /* portUSE_TASK_ACC_SUPPORT */ + + #if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* Does the task have a DPFPU context that needs saving? If + * ulPortTaskHasDPFPUContext is 0 then no. */ + portASM( MOV.L #_ulPortTaskHasDPFPUContext, R15 ) + portASM( MOV.L [ R15 ], R15 ) + portASM( CMP #0, R15 ) + + /* Save the DPFPU context, if any. */ + portASM( BEQ.B portASM_LAB_NEXT( vSoftwareInterruptISR_1 ) ) + portASM( DPUSHM.D DR0-DR15 ) +#if defined(USE_PATCH_FOR_GNURX_202102_INTERNAL_TYPO) + /* The following code is a workaround for an internal typo of + * GNURX 8.3.0.202102. + * https://llvm-gcc-renesas.com/question/gnurx-8-3-0-202102-doesnt-recognize-decnt-register-rxv3/#li-comment-374 */ + portASM( DPUSHM.L DPSW-DCENT ) +#else + /* The following code is correct but this code causes a compile error + * when using the above version of GNURX. */ + portASM( DPUSHM.L DPSW-DECNT ) +#endif + portASM_LAB( vSoftwareInterruptISR_1: ) + + /* Save ulPortTaskHasDPFPUContext itself. */ + portASM( PUSH.L R15 ) + + #elif ( portUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Save the DPFPU context, always. */ + portASM( DPUSHM.D DR0-DR15 ) +#if defined(USE_PATCH_FOR_GNURX_202102_INTERNAL_TYPO) + portASM( DPUSHM.L DPSW-DCENT ) +#else + portASM( DPUSHM.L DPSW-DECNT ) +#endif + + #endif /* portUSE_TASK_DPFPU_SUPPORT */ + + + /* Save the stack pointer to the TCB. */ + portASM( MOV.L #_pxCurrentTCB, R15 ) + portASM( MOV.L [ R15 ], R15 ) + portASM( MOV.L R0, [ R15 ] ) + + + /* Ensure the interrupt mask is set to the syscall priority while the kernel + * structures are being accessed. */ + portASM( MVTIPL #configMAX_SYSCALL_INTERRUPT_PRIORITY ) + + /* Select the next task to run. */ + portASM( BSR.A _vTaskSwitchContext ) + + /* Reset the interrupt mask as no more data structure access is required. */ + portASM( MVTIPL #configKERNEL_INTERRUPT_PRIORITY ) + + + /* Load the stack pointer of the task that is now selected as the Running + * state task from its TCB. */ + portASM( MOV.L #_pxCurrentTCB, R15 ) + portASM( MOV.L [ R15 ], R15 ) + portASM( MOV.L [ R15 ], R0 ) + + + /* Restore the context of the new task. The PSW (Program Status Word) and + * PC will be popped by the RTE instruction. */ + + #if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* Is there a DPFPU context to restore? If the restored + * ulPortTaskHasDPFPUContext is zero then no. */ + portASM( POP R15 ) + portASM( MOV.L #_ulPortTaskHasDPFPUContext, R14 ) + portASM( MOV.L R15, [ R14 ] ) + portASM( CMP #0, R15 ) + + /* Restore the DPFPU context, if any. */ + portASM( BEQ.B portASM_LAB_NEXT( vSoftwareInterruptISR_2 ) ) +#if defined(USE_PATCH_FOR_GNURX_202102_INTERNAL_TYPO) + portASM( DPOPM.L DPSW-DCENT ) +#else + portASM( DPOPM.L DPSW-DECNT ) +#endif + portASM( DPOPM.D DR0-DR15 ) + portASM_LAB( vSoftwareInterruptISR_2: ) + + #elif ( portUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Restore the DPFPU context, always. */ +#if defined(USE_PATCH_FOR_GNURX_202102_INTERNAL_TYPO) + portASM( DPOPM.L DPSW-DCENT ) +#else + portASM( DPOPM.L DPSW-DECNT ) +#endif + portASM( DPOPM.D DR0-DR15 ) + + #endif /* portUSE_TASK_DPFPU_SUPPORT */ + + #if ( portUSE_TASK_ACC_SUPPORT == 1 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15 ) + + #elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15, A0 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15, A0 ) + + /* Accumulator guard. */ + portASM( POP R15 ) + portASM( MVTACGU R15, A0 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15, A1 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15, A1 ) + + /* Accumulator guard. */ + portASM( POP R15 ) + portASM( MVTACGU R15, A1 ) + + #endif /* portUSE_TASK_ACC_SUPPORT */ + + #if ( portUSE_TASK_FPU_SUPPORT == 1 ) + + portASM( POP R15 ) + portASM( MVTC R15, FPSW ) + + #endif + + portASM( POPM R1-R15 ) + portASM( RTE ) + portASM( NOP ) + portASM( NOP ) + +portASM_END +/* *INDENT-ON* */ +} +/*-----------------------------------------------------------*/ + +void vTickISR( void ) +{ +/* *INDENT-OFF* */ +portASM_BEGIN + + /* Re-enabled interrupts. */ + portASM( SETPSW I ) + + /* Increment the tick, and perform any processing the new tick value + * necessitates. Ensure IPL is at the max syscall value first. */ + portASM( MVTIPL #configMAX_SYSCALL_INTERRUPT_PRIORITY ) + { + if( xTaskIncrementTick() != pdFALSE ) + { + taskYIELD(); + } + } + portASM( MVTIPL #configKERNEL_INTERRUPT_PRIORITY ) + +portASM_END +/* *INDENT-ON* */ +} +/*-----------------------------------------------------------*/ + +uint32_t ulPortGetIPL( void ) +{ +/* *INDENT-OFF* */ +portASM_BEGIN + + portASM( MVFC PSW, R1 ) + portASM( SHLR #24, R1 ) + portASM( RTS ) + +portASM_END +/* *INDENT-ON* */ + + /* This will never get executed, but keeps the compiler from complaining. */ + return 0; +} +/*-----------------------------------------------------------*/ + +void vPortSetIPL( uint32_t ulNewIPL ) +{ + /* Avoid compiler warning about unreferenced parameter. */ + ( void ) ulNewIPL; + +/* *INDENT-OFF* */ +portASM_BEGIN + + portASM( PUSH R5 ) + portASM( MVFC PSW, R5 ) + portASM( SHLL #24, R1 ) + portASM( AND #-0F000001H, R5 ) + portASM( OR R1, R5 ) + portASM( MVTC R5, PSW ) + portASM( POP R5 ) + portASM( RTS ) + +portASM_END +/* *INDENT-ON* */ +} +/*-----------------------------------------------------------*/ diff --git a/portable/GCC/RX/portmacro.h b/portable/GCC/RX/portmacro.h new file mode 100644 index 0000000000..2ffb03451a --- /dev/null +++ b/portable/GCC/RX/portmacro.h @@ -0,0 +1,260 @@ +/* + * 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 + +/* *INDENT-OFF* */ +#ifdef __cplusplus + extern "C" { +#endif +/* *INDENT-ON* */ + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* If configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H is set to 0 then iodefine.h + * is included and used in FreeRTOS Kernel's Renesas RX port. If the macro is set + * to 1 then platform.h is included and used in the port. If the macro is set to 2 + * then neither iodefine.h nor platform.h are included. If the macro is undefined, + * it is set to 0 (CC-RX/GNURX) or 2 (ICCRX) internally for backward compatibility. + * When the FIT configurator or the Smart Configurator is used, platform.h has to be + * used. */ +#ifndef configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H + #define configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H 0 +#endif + +/* If configUSE_TASK_DPFPU_SUPPORT is set to 1 (or undefined) then each task will + * be created without a DPFPU context, and a task must call vTaskUsesDPFPU() before + * making use of any DPFPU registers. If configUSE_TASK_DPFPU_SUPPORT is set to 2 then + * tasks are created with a DPFPU context by default, and calling vTaskUsesDPFPU() has + * no effect. If configUSE_TASK_DPFPU_SUPPORT is set to 0 then tasks never take care + * of any DPFPU context (even if DPFPU registers are used). */ +#ifdef __RX_DFPU_INSNS__ + /* The compiler may use DPFPU registers. */ + #ifndef configUSE_TASK_DPFPU_SUPPORT + #define configUSE_TASK_DPFPU_SUPPORT 1 + #endif +#else + /* The compiler does not use DPFPU registers. */ + #ifdef configUSE_TASK_DPFPU_SUPPORT + #undef configUSE_TASK_DPFPU_SUPPORT + #endif + #define configUSE_TASK_DPFPU_SUPPORT 0 +#endif +#define portUSE_TASK_DPFPU_SUPPORT configUSE_TASK_DPFPU_SUPPORT + +#ifdef __RX_FPU_INSNS__ + /* The compiler may use FPSW register. */ + #define portUSE_TASK_FPU_SUPPORT 1 +#else + /* The compiler does not use FPSW register. */ + #define portUSE_TASK_FPU_SUPPORT 0 +#endif + +#ifdef __RXv1__ + /* The CPU has only one accumulator. */ + #define portUSE_TASK_ACC_SUPPORT 1 +#elif !defined( __RXv2__ ) && !defined( __RXv3__ ) && ( __GNUC__ < 8 ) + /* The CPU is RXv1 and has only one accumulator. */ + #define portUSE_TASK_ACC_SUPPORT 1 +#else + /* The CPU has two accumulators. */ + #define portUSE_TASK_ACC_SUPPORT 2 +#endif + +/*-----------------------------------------------------------*/ + +/* 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; + +#if ( configUSE_16_BIT_TICKS == 1 ) + typedef uint16_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffff +#else + 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 +#endif + +/*-----------------------------------------------------------*/ + +/* Inline assembler specifics. */ +#if ( defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901L ) ) + /* *INDENT-OFF* */ + #define _portASM( ... ) __asm volatile ( #__VA_ARGS__ "\n" ); + #define portASM( ... ) _portASM( __VA_ARGS__ ) + #define portASM_LAB_NEXT( name ) ?+ + #define portASM_LAB_PREV( name ) ?- + #define portASM_LAB( name_colon ) _portASM( ?: ) + #define portASM_BEGIN + #define portASM_END + /* *INDENT-ON* */ +#endif /* if ( defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901L ) ) */ + +/* Workaround to reduce errors/warnings caused by e2 studio CDT's INDEXER and CODAN. */ +#ifdef __CDT_PARSER__ + #ifndef __asm + #define __asm asm + #endif + #ifndef __attribute__ + #define __attribute__( ... ) + #endif +#endif + +/*-----------------------------------------------------------*/ + +/* Hardware specifics. */ +#define portBYTE_ALIGNMENT 8 /* Could make four, according to manual. */ +#define portSTACK_GROWTH -1 +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#define portNOP() __asm volatile ( "NOP" ) + +/* Yield equivalent to "*portITU_SWINTR = 0x01; ( void ) ( *portITU_SWINTR == XXX );" + * where portITU_SWINTR is the location of the software interrupt register + * (0x000872E0) and XXX is an arbitrary number. Don't rely on the assembler to + * select a register, so instead save and restore clobbered registers manually. */ +/* *INDENT-OFF* */ +#define portYIELD() \ +__asm volatile \ +( \ + "PUSH.L R10 \n"\ + "MOV.L #0x872E0, R10 \n"\ + "MOV.B #0x1, [ R10 ] \n"\ + "CMP [ R10 ].UB, R10 \n"\ + "POP R10 "\ + :::"cc" \ +) +/* *INDENT-ON* */ + +#define portYIELD_FROM_ISR( x ) do { if( ( x ) != pdFALSE ) portYIELD(); } while( 0 ) + +/* These macros should not be called directly, but through the + * taskENTER_CRITICAL() and taskEXIT_CRITICAL() macros. An extra check is + * performed if configASSERT() is defined to ensure an assertion handler does not + * inadvertently attempt to lower the IPL when the call to assert was triggered + * because the IPL value was found to be above configMAX_SYSCALL_INTERRUPT_PRIORITY + * when an ISR safe FreeRTOS API function was executed. ISR safe FreeRTOS API + * functions are those that end in FromISR. FreeRTOS maintains a separate + * interrupt API to ensure API function and interrupt entry is as fast and as + * simple as possible. */ +#define portENABLE_INTERRUPTS() __asm volatile ( "MVTIPL #0" ) +#ifdef configASSERT + #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() configASSERT( ( ulPortGetIPL() <= configMAX_SYSCALL_INTERRUPT_PRIORITY ) ) + #define portDISABLE_INTERRUPTS() if( ulPortGetIPL() < configMAX_SYSCALL_INTERRUPT_PRIORITY ) __asm volatile ( "MVTIPL %0" ::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) ) +#else + #define portDISABLE_INTERRUPTS() __asm volatile ( "MVTIPL %0" ::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) ) +#endif + +/* Critical nesting counts are stored in the TCB. */ +#define portCRITICAL_NESTING_IN_TCB ( 1 ) + +/* The critical nesting functions defined within tasks.c. */ +extern void vTaskEnterCritical( void ); +extern void vTaskExitCritical( void ); +#define portENTER_CRITICAL() vTaskEnterCritical() +#define portEXIT_CRITICAL() vTaskExitCritical() + +/* As this port allows interrupt nesting... */ +uint32_t ulPortGetIPL( void ) __attribute__( ( naked ) ); +void vPortSetIPL( uint32_t ulNewIPL ) __attribute__( ( naked ) ); +#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortGetIPL(); portDISABLE_INTERRUPTS() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ) vPortSetIPL( uxSavedInterruptStatus ) + +/*-----------------------------------------------------------*/ + +/* 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 ) + +/*-----------------------------------------------------------*/ + +/* If portUSE_TASK_DPFPU_SUPPORT is set to 1 (or left undefined) then tasks are + * created without a DPFPU context and must call vPortTaskUsesDPFPU() to give + * themselves a DPFPU context before using any DPFPU instructions. If + * portUSE_TASK_DPFPU_SUPPORT is set to 2 then all tasks will have a DPFPU context + * by default. */ +#if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + void vPortTaskUsesDPFPU( void ); +#else + + /* Each task has a DPFPU context already, so define this function away to + * nothing to prevent it being called accidentally. */ + #define vPortTaskUsesDPFPU() +#endif +#define portTASK_USES_DPFPU() vPortTaskUsesDPFPU() + +/* Definition to allow compatibility with existing FreeRTOS Demo using flop.c. */ +#define portTASK_USES_FLOATING_POINT() vPortTaskUsesDPFPU() + +/*-----------------------------------------------------------*/ + +/* Checks whether the current execution context is interrupt. + * Return pdTRUE if the current execution context is interrupt, + * pdFALSE otherwise. */ +__inline __attribute__( ( always_inline ) ) static BaseType_t xPortIsInsideInterrupt( void ) +{ + /* When the user stack pointer is used, the context is not interrupt. + * When the interrupt stack pointer is used, the context is interrupt. + * Don't call this function before the scheduler has started because + * this function always returns pdTRUE before the timing. */ + return ( __builtin_rx_mvfc( 0x0 /* PSW */ ) & 0x00020000 /* PSW.U */ ) != 0 ? pdFALSE : pdTRUE; +} + +/*-----------------------------------------------------------*/ + +#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" ) + +/* *INDENT-OFF* */ +#ifdef __cplusplus + } +#endif +/* *INDENT-ON* */ + +#endif /* PORTMACRO_H */ diff --git a/portable/GCC/RX/readme.txt b/portable/GCC/RX/readme.txt new file mode 100644 index 0000000000..5617c8df4e --- /dev/null +++ b/portable/GCC/RX/readme.txt @@ -0,0 +1,87 @@ +The generic RX port layer in this folder can be used for the following MCUs in case of other than using +tickless idle functionality of RX100 port layers and/or using C89 specification and/or using old version +of ICCRX. + + +RX MCU Group CPU FPU FPU + Core (Single (Double + Type Precision) Precision) + +RX110 RXv1 No --- +RX111 RXv1 No --- +RX113 RXv1 No --- +RX130 RXv1 No --- +RX13T RXv1 Yes --- + +RX210 RXv1 No --- +RX21A RXv1 No --- +RX220 RXv1 No --- +RX230,RX231 RXv2 Yes --- +RX23E-A RXv2 Yes --- +RX23W RXv2 Yes --- +RX23T RXv2 Yes --- +RX24T RXv2 Yes --- +RX24U RXv2 Yes --- + +RX610 RXv1 Yes --- +RX62N,RX621 RXv1 Yes --- +RX630 RXv1 Yes --- +RX634 RXv1 Yes --- +RX63N,RX631 RXv1 Yes --- +RX64M RXv2 Yes --- +RX65N,RX651 RXv2 Yes --- +RX66N RXv3 Yes Yes +RX62T RXv1 Yes --- +RX62G RXv1 Yes --- +RX63T RXv1 Yes --- +RX66T RXv3 Yes No + +RX71M RXv2 Yes --- +RX72M RXv3 Yes Yes +RX72N RXv3 Yes Yes +RX72T RXv3 Yes No + +Notes: + +(1) When you use the FIT configurator or the Smart Configurator, platform.h has to be used. In this case, +the following definition is necessary in FreeRTOSConfig.h. + +/* If configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H is set to 0 then iodefine.h +is included and used in FreeRTOS Kernel's Renesas RX port. If the macro is set +to 1 then platform.h is included and used in the port. If the macro is set to 2 +then neither iodefine.h nor platform.h are included. If the macro is undefined, +it is set to 0 (CC-RX/GNURX) or 2 (ICCRX) internally for backward compatibility. +When the FIT configurator or the Smart Configurator is used, platform.h has to be +used. */ +#define configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H 1 + +(2) When you use the CC-RX compiler of Renesas or the GNURX compiler, the definition of configTICK_VECTOR +is like the following: + +/* The peripheral used to generate the tick interrupt is configured as part of +the application code. This constant should be set to the vector number of the +peripheral chosen. As supplied this is CMT0. */ +#define configTICK_VECTOR _CMT0_CMI0 + +(3) When you use the ICCRX compiler of IAR, the definition of configTICK_VECTOR depends on the setting of +configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H like the followings: + +(3-1) In case of configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 0 or 1 + +#define configTICK_VECTOR _CMT0_CMI0 + +(3-2) In case of configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 2 or undefined + +#define configTICK_VECTOR VECT_CMT0_CMI0 + +(4) Moreover in the case of above (3-2), I/O register definition header file which is provided from IAR +has to be included in FreeRTOSConfig.h like the followings: + +/* Renesas hardware definition header. */ +#include + + +For more information about Renesas RX MCUs, please visit the following URL: + +https://www.renesas.com/products/microcontrollers-microprocessors/rx.html + diff --git a/portable/IAR/RX/port.c b/portable/IAR/RX/port.c new file mode 100644 index 0000000000..0f466deccf --- /dev/null +++ b/portable/IAR/RX/port.c @@ -0,0 +1,750 @@ +/* + * 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 + * + */ + +/*----------------------------------------------------------- +* Implementation of functions defined in portable.h for the Renesas RX port. +*----------------------------------------------------------*/ + +/* Scheduler includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Library includes. */ +#include "string.h" + +/* Hardware specifics. */ +#if ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 0 ) + #include "iodefine.h" +#elif ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 1 ) + #include "platform.h" +#elif ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 2 ) + /* Nothing to be included here. */ +#else + #error Invalid configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H setting - configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H must be set to 0, 1, 2, or left undefined. +#endif + +/* Miscellaneous checks for this port. */ +#if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) || ( configUSE_TASK_DPFPU_SUPPORT == 2 ) + #warning Testing for DPFPU support in this port is not yet complete +#elif ( configUSE_TASK_DPFPU_SUPPORT != 0 ) + #error Invalid configUSE_TASK_DPFPU_SUPPORT setting - configUSE_TASK_DPFPU_SUPPORT must be set to 0, 1, 2, or left undefined. +#endif + +#if !defined( __RXV1 ) && !defined( __RXV2 ) && !defined( __RXV3 ) + #if ( __VER__ < 414 ) + #error This old version of ICCRX is not supported. + #else + #warning This new CPU core may not be supported. + #endif +#endif + +#if !defined( __STDC_VERSION__ ) || ( __STDC_VERSION__ < 199901L ) + #error This port needs C99 or later. +#endif + +/*-----------------------------------------------------------*/ + +/* Tasks should start with interrupts enabled and in Supervisor mode, therefore + * PSW is set with U and I set, and PM and IPL clear. */ +#define portINITIAL_PSW ( ( StackType_t ) 0x00030000 ) +#define portINITIAL_FPSW ( ( StackType_t ) 0x00000100 ) +#define portINITIAL_DPSW ( ( StackType_t ) 0x00000100 ) +#define portINITIAL_DCMR ( ( StackType_t ) 0x00000000 ) +#define portINITIAL_DECNT ( ( StackType_t ) 0x00000001 ) + +/* Tasks are not created with a DPFPU context, but can be given a DPFPU context + * after they have been created. A variable is stored as part of the tasks context + * that holds portNO_DPFPU_CONTEXT if the task does not have a DPFPU context, or + * any other value if the task does have a DPFPU context. */ +#define portNO_DPFPU_CONTEXT ( ( StackType_t ) 0 ) +#define portHAS_DPFPU_CONTEXT ( ( StackType_t ) 1 ) + +/* The space on the stack required to hold the general purpos registers. This is 16 + * 32-bit registers, except for R0 (for stack pointer) and R1 (for pvParameters). */ +#define portGENERAL_PURPOSE_REGISTER_WORDS ( 16 - 2 ) + +/* The space on the stack required to hold the accumulator. This is 2 or 6 + * 32-bit registers. */ +#if ( portUSE_TASK_ACC_SUPPORT == 1 ) + + #define portACCUMULATOR_REGISTER_WORDS ( 2 ) + +#elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + + #define portACCUMULATOR_REGISTER_WORDS ( 6 ) + +#endif /* portUSE_TASK_ACC_SUPPORT */ + +/* The space on the stack required to hold the DPFPU data registers. This is 16 + * 64-bit registers. */ +#define portDPFPU_DATA_REGISTER_WORDS ( 16 * 2 ) + +/*-----------------------------------------------------------*/ + +/* + * Function to start the first task executing - written in asm code as direct + * access to registers is required. + */ +static void prvStartFirstTask( void ); + +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + +/* + * Force an assert. + */ +static void prvForceAssert( void ); + +/* + * Software interrupt handler. Performs the actual context switch (saving and + * restoring of registers). Written in asm code as direct register access is + * required. + */ +__interrupt void vSoftwareInterruptISR( void ); + +/* + * The tick ISR handler. The peripheral used is configured by the application + * via a hook/callback function. + */ +__interrupt void vTickISR( void ); + +/*-----------------------------------------------------------*/ + +/* Saved as part of the task context. If ulPortTaskHasDPFPUContext is non-zero + * then a DPFPU context must be saved and restored for the task. */ +#if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + StackType_t ulPortTaskHasDPFPUContext = portNO_DPFPU_CONTEXT; + +#endif + +/* This is accessed by the inline assembler functions so is file scope for + * convenience. */ +extern void * pxCurrentTCB; +extern void vTaskSwitchContext( void ); + +/*-----------------------------------------------------------*/ + +/* + * See header file for description. + */ +StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, + TaskFunction_t pxCode, + void * pvParameters ) +{ + /* R0 is not included as it is the stack pointer. */ + + /* Prevent the debugger from messing up unwinding of the stack. */ + *pxTopOfStack = ( StackType_t ) 0x0; + pxTopOfStack--; + + /* '+ 1 ' is a workaround for preventing rx-elf-gdb from messing up. */ + *pxTopOfStack = ( ( StackType_t ) prvTaskExitError ) + 1; + pxTopOfStack--; + *pxTopOfStack = portINITIAL_PSW; + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) pxCode; + + /* When debugging it can be useful if every register is set to a known + * value. Otherwise code space can be saved by just setting the registers + * that need to be set. */ + #ifdef USE_FULL_REGISTER_INITIALISATION + { + pxTopOfStack--; + *pxTopOfStack = 0xffffffff; /* r15. */ + pxTopOfStack--; + *pxTopOfStack = 0xeeeeeeee; + pxTopOfStack--; + *pxTopOfStack = 0xdddddddd; + pxTopOfStack--; + *pxTopOfStack = 0xcccccccc; + pxTopOfStack--; + *pxTopOfStack = 0xbbbbbbbb; + pxTopOfStack--; + *pxTopOfStack = 0xaaaaaaaa; + pxTopOfStack--; + *pxTopOfStack = 0x99999999; + pxTopOfStack--; + *pxTopOfStack = 0x88888888; + pxTopOfStack--; + *pxTopOfStack = 0x77777777; + pxTopOfStack--; + *pxTopOfStack = 0x66666666; + pxTopOfStack--; + *pxTopOfStack = 0x55555555; + pxTopOfStack--; + *pxTopOfStack = 0x44444444; + pxTopOfStack--; + *pxTopOfStack = 0x33333333; + pxTopOfStack--; + *pxTopOfStack = 0x22222222; + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= portGENERAL_PURPOSE_REGISTER_WORDS; + memset( pxTopOfStack, 0x00, portGENERAL_PURPOSE_REGISTER_WORDS * sizeof( StackType_t ) ); + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) pvParameters; /* R1 */ + + #if ( portUSE_TASK_FPU_SUPPORT == 1 ) + { + pxTopOfStack--; + *pxTopOfStack = portINITIAL_FPSW; + } + #endif + + #if ( portUSE_TASK_ACC_SUPPORT == 1 ) + { + #ifdef USE_FULL_REGISTER_INITIALISATION + { + pxTopOfStack--; + *pxTopOfStack = 0x12345678; /* Accumulator. */ + pxTopOfStack--; + *pxTopOfStack = 0x87654321; /* Accumulator. */ + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= portACCUMULATOR_REGISTER_WORDS; + memset( pxTopOfStack, 0x00, portACCUMULATOR_REGISTER_WORDS * sizeof( StackType_t ) ); + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + } + #elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + { + #ifdef USE_FULL_REGISTER_INITIALISATION + { + pxTopOfStack--; + *pxTopOfStack = 0x11111111; /* Accumulator 1. */ + pxTopOfStack--; + *pxTopOfStack = 0x22222222; /* Accumulator 1. */ + pxTopOfStack--; + *pxTopOfStack = 0x33333333; /* Accumulator 1. */ + pxTopOfStack--; + *pxTopOfStack = 0x44444444; /* Accumulator 0. */ + pxTopOfStack--; + *pxTopOfStack = 0x55555555; /* Accumulator 0. */ + pxTopOfStack--; + *pxTopOfStack = 0x66666666; /* Accumulator 0. */ + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= portACCUMULATOR_REGISTER_WORDS; + memset( pxTopOfStack, 0x00, portACCUMULATOR_REGISTER_WORDS * sizeof( StackType_t ) ); + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + } + #endif /* portUSE_TASK_ACC_SUPPORT */ + + #if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + { + /* The task will start without a DPFPU context. A task that + * uses the DPFPU hardware must call vPortTaskUsesDPFPU() before + * executing any floating point instructions. */ + pxTopOfStack--; + *pxTopOfStack = portNO_DPFPU_CONTEXT; + } + #elif ( portUSE_TASK_DPFPU_SUPPORT == 2 ) + { + /* The task will start with a DPFPU context. Leave enough + * space for the registers - and ensure they are initialised if desired. */ + #ifdef USE_FULL_REGISTER_INITIALISATION + { + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1515.1515; /* DR15. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1414.1414; /* DR14. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1313.1313; /* DR13. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1212.1212; /* DR12. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1111.1111; /* DR11. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1010.1010; /* DR10. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 909.0909; /* DR9. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 808.0808; /* DR8. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 707.0707; /* DR7. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 606.0606; /* DR6. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 505.0505; /* DR5. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 404.0404; /* DR4. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 303.0303; /* DR3. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 202.0202; /* DR2. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 101.0101; /* DR1. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 9876.54321; /* DR0. */ + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= portDPFPU_DATA_REGISTER_WORDS; + memset( pxTopOfStack, 0x00, portDPFPU_DATA_REGISTER_WORDS * sizeof( StackType_t ) ); + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + pxTopOfStack--; + *pxTopOfStack = portINITIAL_DECNT; /* DECNT. */ + pxTopOfStack--; + *pxTopOfStack = portINITIAL_DCMR; /* DCMR. */ + pxTopOfStack--; + *pxTopOfStack = portINITIAL_DPSW; /* DPSW. */ + } + #endif /* portUSE_TASK_DPFPU_SUPPORT */ + + return pxTopOfStack; +} +/*-----------------------------------------------------------*/ + +#pragma inline = never +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. */ + + /* Adding NOP is a workaround to prevent rx-elf-gdb from messing up. */ + portNOP(); + + /* Any function call other than portNOP() should not be inlined in this + * function to ensure the address of here is 'prvTaskExitError + 1'. */ + prvForceAssert(); +} +/*-----------------------------------------------------------*/ + +#if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + void vPortTaskUsesDPFPU( void ) + { + /* A task is registering the fact that it needs a DPFPU context. Set the + * DPFPU flag (which is saved as part of the task context). */ + ulPortTaskHasDPFPUContext = portHAS_DPFPU_CONTEXT; + } + +#endif /* portUSE_TASK_DPFPU_SUPPORT */ +/*-----------------------------------------------------------*/ + +BaseType_t xPortStartScheduler( void ) +{ + extern void vApplicationSetupTimerInterrupt( void ); + + /* Use pxCurrentTCB just so it does not get optimised away. */ + if( pxCurrentTCB != NULL ) + { + /* Call an application function to set up the timer that will generate the + * tick interrupt. This way the application can decide which peripheral to + * use. A demo application is provided to show a suitable example. */ + vApplicationSetupTimerInterrupt(); + + /* Enable the software interrupt. */ + _IEN( _ICU_SWINT ) = 1; + + /* Ensure the software interrupt is clear. */ + _IR( _ICU_SWINT ) = 0; + + /* Ensure the software interrupt is set to the kernel priority. */ + _IPR( _ICU_SWINT ) = configKERNEL_INTERRUPT_PRIORITY; + + /* Start the first task. */ + prvStartFirstTask(); + } + + /* Should not get here. */ + return pdFAIL; +} +/*-----------------------------------------------------------*/ + +void vPortEndScheduler( void ) +{ + /* Not implemented in ports where there is nothing to return to. + * Artificially force an assert. */ + prvForceAssert(); +} +/*-----------------------------------------------------------*/ + +#pragma inline = never +static void prvForceAssert( void ) +{ + configASSERT( pxCurrentTCB == NULL ); + portDISABLE_INTERRUPTS(); + + for( ; ; ) + { + } +} +/*-----------------------------------------------------------*/ + +static void prvStartFirstTask( void ) +{ +/* *INDENT-OFF* */ +portASM_BEGIN + + /* When starting the scheduler there is nothing that needs moving to the + * interrupt stack because the function is not called from an interrupt. + * Just ensure the current stack is the user stack. */ + portASM( SETPSW U ) + + + /* Obtain the location of the stack associated with which ever task + * pxCurrentTCB is currently pointing to. */ + portASM( MOV.L #_pxCurrentTCB, R15 ) + portASM( MOV.L [ R15 ], R15 ) + portASM( MOV.L [ R15 ], R0 ) + + + /* Restore the registers from the stack of the task pointed to by + * pxCurrentTCB. */ + + #if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* The restored ulPortTaskHasDPFPUContext is to be zero here. + * So, it is never necessary to restore the DPFPU context here. */ + portASM( POP R15 ) + portASM( MOV.L #_ulPortTaskHasDPFPUContext, R14 ) + portASM( MOV.L R15, [ R14 ] ) + + #elif ( portUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Restore the DPFPU context. */ + portASM( DPOPM.L DPSW-DECNT ) + portASM( DPOPM.D DR0-DR15 ) + + #endif /* portUSE_TASK_DPFPU_SUPPORT */ + + #if ( portUSE_TASK_ACC_SUPPORT == 1 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15 ) + + #elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15, A0 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15, A0 ) + + /* Accumulator guard. */ + portASM( POP R15 ) + portASM( MVTACGU R15, A0 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15, A1 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15, A1 ) + + /* Accumulator guard. */ + portASM( POP R15 ) + portASM( MVTACGU R15, A1 ) + + #endif /* portUSE_TASK_ACC_SUPPORT */ + + #if ( portUSE_TASK_FPU_SUPPORT == 1 ) + + /* Floating point status word. */ + portASM( POP R15 ) + portASM( MVTC R15, FPSW ) + + #endif + + /* R1 to R15 - R0 is not included as it is the SP. */ + portASM( POPM R1-R15 ) + + /* This pops the remaining registers. */ + portASM( RTE ) + portASM( NOP ) + portASM( NOP ) + +portASM_END +/* *INDENT-ON* */ +} +/*-----------------------------------------------------------*/ + +#pragma required = vTaskSwitchContext +#pragma vector = _VECT( _ICU_SWINT ) +__interrupt void vSoftwareInterruptISR( void ) +{ +/* *INDENT-OFF* */ +portASM_BEGIN + + /* Re-enable interrupts. */ + portASM( SETPSW I ) + + + /* Move the data that was automatically pushed onto the interrupt stack when + * the interrupt occurred from the interrupt stack to the user stack. + * + * R15 is saved before it is clobbered. */ + portASM( PUSH.L R15 ) + + /* Read the user stack pointer. */ + portASM( MVFC USP, R15 ) + + /* Move the address down to the data being moved. */ + portASM( SUB #12, R15 ) + portASM( MVTC R15, USP ) + + /* Copy the data across, R15, then PC, then PSW. */ + portASM( MOV.L [ R0 ], [ R15 ] ) + portASM( MOV.L 4[ R0 ], 4[ R15 ] ) + portASM( MOV.L 8[ R0 ], 8[ R15 ] ) + + /* Move the interrupt stack pointer to its new correct position. */ + portASM( ADD #12, R0 ) + + /* All the rest of the registers are saved directly to the user stack. */ + portASM( SETPSW U ) + + /* Save the rest of the general registers (R15 has been saved already). */ + portASM( PUSHM R1-R14 ) + + /* Save the FPSW and accumulators. */ + #if ( portUSE_TASK_FPU_SUPPORT == 1 ) + + portASM( MVFC FPSW, R15 ) + portASM( PUSH.L R15 ) + + #endif + + #if ( portUSE_TASK_ACC_SUPPORT == 1 ) + + /* Save the accumulator. */ + portASM( MVFACHI R15 ) + portASM( PUSH.L R15 ) + + /* Middle word. */ + portASM( MVFACMI R15 ) + + /* Shifted left as it is restored to the low order word. */ + portASM( SHLL #16, R15 ) + portASM( PUSH.L R15 ) + + #elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + + /* Accumulator guard. */ + portASM( MVFACGU #0, A1, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator high 32 bits. */ + portASM( MVFACHI #0, A1, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator low 32 bits. */ + portASM( MVFACLO #0, A1, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator guard. */ + portASM( MVFACGU #0, A0, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator high 32 bits. */ + portASM( MVFACHI #0, A0, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator low 32 bits. */ + portASM( MVFACLO #0, A0, R15 ) + portASM( PUSH.L R15 ) + + #endif /* portUSE_TASK_ACC_SUPPORT */ + + #if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* Does the task have a DPFPU context that needs saving? If + * ulPortTaskHasDPFPUContext is 0 then no. */ + portASM( MOV.L #_ulPortTaskHasDPFPUContext, R15 ) + portASM( MOV.L [ R15 ], R15 ) + portASM( CMP #0, R15 ) + + /* Save the DPFPU context, if any. */ + portASM( BEQ.B portASM_LAB_NEXT( vSoftwareInterruptISR_1 ) ) + portASM( DPUSHM.D DR0-DR15 ) + portASM( DPUSHM.L DPSW-DECNT ) + portASM_LAB( vSoftwareInterruptISR_1: ) + + /* Save ulPortTaskHasDPFPUContext itself. */ + portASM( PUSH.L R15 ) + + #elif ( portUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Save the DPFPU context, always. */ + portASM( DPUSHM.D DR0-DR15 ) + portASM( DPUSHM.L DPSW-DECNT ) + + #endif /* portUSE_TASK_DPFPU_SUPPORT */ + + + /* Save the stack pointer to the TCB. */ + portASM( MOV.L #_pxCurrentTCB, R15 ) + portASM( MOV.L [ R15 ], R15 ) + portASM( MOV.L R0, [ R15 ] ) + + + /* Ensure the interrupt mask is set to the syscall priority while the kernel + * structures are being accessed. */ + portASM( MVTIPL #configMAX_SYSCALL_INTERRUPT_PRIORITY ) + + /* Select the next task to run. */ + portASM( BSR.A _vTaskSwitchContext ) + + /* Reset the interrupt mask as no more data structure access is required. */ + portASM( MVTIPL #configKERNEL_INTERRUPT_PRIORITY ) + + + /* Load the stack pointer of the task that is now selected as the Running + * state task from its TCB. */ + portASM( MOV.L #_pxCurrentTCB, R15 ) + portASM( MOV.L [ R15 ], R15 ) + portASM( MOV.L [ R15 ], R0 ) + + + /* Restore the context of the new task. The PSW (Program Status Word) and + * PC will be popped by the RTE instruction. */ + + #if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* Is there a DPFPU context to restore? If the restored + * ulPortTaskHasDPFPUContext is zero then no. */ + portASM( POP R15 ) + portASM( MOV.L #_ulPortTaskHasDPFPUContext, R14 ) + portASM( MOV.L R15, [ R14 ] ) + portASM( CMP #0, R15 ) + + /* Restore the DPFPU context, if any. */ + portASM( BEQ.B portASM_LAB_NEXT( vSoftwareInterruptISR_2 ) ) + portASM( DPOPM.L DPSW-DECNT ) + portASM( DPOPM.D DR0-DR15 ) + portASM_LAB( vSoftwareInterruptISR_2: ) + + #elif ( portUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Restore the DPFPU context, always. */ + portASM( DPOPM.L DPSW-DECNT ) + portASM( DPOPM.D DR0-DR15 ) + + #endif /* portUSE_TASK_DPFPU_SUPPORT */ + + #if ( portUSE_TASK_ACC_SUPPORT == 1 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15 ) + + #elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15, A0 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15, A0 ) + + /* Accumulator guard. */ + portASM( POP R15 ) + portASM( MVTACGU R15, A0 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15, A1 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15, A1 ) + + /* Accumulator guard. */ + portASM( POP R15 ) + portASM( MVTACGU R15, A1 ) + + #endif /* portUSE_TASK_ACC_SUPPORT */ + + #if ( portUSE_TASK_FPU_SUPPORT == 1 ) + + portASM( POP R15 ) + portASM( MVTC R15, FPSW ) + + #endif + + portASM( POPM R1-R15 ) + portASM( RTE ) + portASM( NOP ) + portASM( NOP ) + +portASM_END +/* *INDENT-ON* */ +} +/*-----------------------------------------------------------*/ + +#if ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H < 2 ) + #pragma vector = _VECT( configTICK_VECTOR ) +#else + #pragma vector = configTICK_VECTOR +#endif +__interrupt void vTickISR( void ) +{ + /* Re-enable interrupts. */ + __enable_interrupt(); + + /* Increment the tick, and perform any processing the new tick value + * necessitates. Ensure IPL is at the max syscall value first. */ + __set_interrupt_level( configMAX_SYSCALL_INTERRUPT_PRIORITY ); + { + if( xTaskIncrementTick() != pdFALSE ) + { + taskYIELD(); + } + } + __set_interrupt_level( configKERNEL_INTERRUPT_PRIORITY ); +} +/*-----------------------------------------------------------*/ diff --git a/portable/IAR/RX/portmacro.h b/portable/IAR/RX/portmacro.h new file mode 100644 index 0000000000..9863704e19 --- /dev/null +++ b/portable/IAR/RX/portmacro.h @@ -0,0 +1,272 @@ +/* + * 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 + +/* Hardware specifics. */ +#include + +/* *INDENT-OFF* */ +#ifdef __cplusplus + extern "C" { +#endif +/* *INDENT-ON* */ + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* If configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H is set to 0 then iodefine.h + * is included and used in FreeRTOS Kernel's Renesas RX port. If the macro is set + * to 1 then platform.h is included and used in the port. If the macro is set to 2 + * then neither iodefine.h nor platform.h are included. If the macro is undefined, + * it is set to 0 (CC-RX/GNURX) or 2 (ICCRX) internally for backward compatibility. + * When the FIT configurator or the Smart Configurator is used, platform.h has to be + * used. */ +#ifndef configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H + #define configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H 2 +#endif + +/* If configUSE_TASK_DPFPU_SUPPORT is set to 1 (or undefined) then each task will + * be created without a DPFPU context, and a task must call vTaskUsesDPFPU() before + * making use of any DPFPU registers. If configUSE_TASK_DPFPU_SUPPORT is set to 2 then + * tasks are created with a DPFPU context by default, and calling vTaskUsesDPFPU() has + * no effect. If configUSE_TASK_DPFPU_SUPPORT is set to 0 then tasks never take care + * of any DPFPU context (even if DPFPU registers are used). */ +#ifdef __DPFPU + /* The compiler may use DPFPU registers. */ + #ifndef configUSE_TASK_DPFPU_SUPPORT + #define configUSE_TASK_DPFPU_SUPPORT 1 + #endif +#else + /* The compiler does not use DPFPU registers. */ + #ifdef configUSE_TASK_DPFPU_SUPPORT + #undef configUSE_TASK_DPFPU_SUPPORT + #endif + #define configUSE_TASK_DPFPU_SUPPORT 0 +#endif +#define portUSE_TASK_DPFPU_SUPPORT configUSE_TASK_DPFPU_SUPPORT + +#ifdef __FPU + /* The compiler may use FPSW register. */ + #define portUSE_TASK_FPU_SUPPORT 1 +#else + /* The compiler does not use FPSW register. */ + #define portUSE_TASK_FPU_SUPPORT 0 +#endif + +#ifdef __RXV1 + /* The CPU has only one accumulator. */ + #define portUSE_TASK_ACC_SUPPORT 1 +#elif !defined( __RXV2 ) && !defined( __RXV3 ) && ( __VER__ < 414 ) + /* This version of the compiler is not supported because the CPU core is unknown. */ + #define portUSE_TASK_ACC_SUPPORT 0 +#else + /* The CPU has two accumulators. */ + #define portUSE_TASK_ACC_SUPPORT 2 +#endif + +/*-----------------------------------------------------------*/ + +/* 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; + +#if ( configUSE_16_BIT_TICKS == 1 ) + typedef uint16_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffff +#else + 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 +#endif + +/*-----------------------------------------------------------*/ + +/* Inline assembler specifics. */ +#if ( defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901L ) ) + /* *INDENT-OFF* */ + #define _portASM( ... ) __asm volatile ( #__VA_ARGS__ "\n" ); + #define portASM( ... ) _portASM( __VA_ARGS__ ) + #define portASM_LAB_NEXT( name ) _lab_##name + #define portASM_LAB_PREV( name ) _lab_##name + #define portASM_LAB( name_colon ) _portASM( _lab_##name_colon: ) + #define portASM_BEGIN _Pragma( "diag_suppress = Pe010" ) + #define portASM_END _Pragma( "diag_default = Pe010" ) + /* *INDENT-ON* */ +#endif /* if ( defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901L ) ) */ + +/* Workaround to reduce errors/warnings caused by e2 studio CDT's INDEXER and CODAN. */ +#ifdef __CDT_PARSER__ + #ifndef __asm + #define __asm asm + #endif + #ifndef __attribute__ + #define __attribute__( ... ) + #endif + #define portCDT_NO_PARSE( token ) +#else + #define portCDT_NO_PARSE( token ) token +#endif + +/*-----------------------------------------------------------*/ + +/* Hardware specifics. */ +#define portBYTE_ALIGNMENT 8 /* Could make four, according to manual. */ +#define portSTACK_GROWTH -1 +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#define portNOP() __no_operation() + +/* Yield equivalent to "*portITU_SWINTR = 0x01; ( void ) ( *portITU_SWINTR == XXX );" + * where portITU_SWINTR is the location of the software interrupt register + * (0x000872E0) and XXX is an arbitrary number. Don't rely on the assembler to + * select a register, so instead save and restore clobbered registers manually. */ +/* *INDENT-OFF* */ +#define portYIELD() \ +__asm volatile \ +( \ + "PUSH.L R10 \n"\ + "MOV.L #0x872E0, R10 \n"\ + "MOV.B #0x1, [ R10 ] \n"\ + "CMP [ R10 ].UB, R10 \n"\ + "POP R10 "\ + portCDT_NO_PARSE( ::: ) "cc"\ +) +/* *INDENT-ON* */ + +#define portYIELD_FROM_ISR( x ) do { if( ( x ) != pdFALSE ) portYIELD(); } while( 0 ) + +/* These macros should not be called directly, but through the + * taskENTER_CRITICAL() and taskEXIT_CRITICAL() macros. An extra check is + * performed if configASSERT() is defined to ensure an assertion handler does not + * inadvertently attempt to lower the IPL when the call to assert was triggered + * because the IPL value was found to be above configMAX_SYSCALL_INTERRUPT_PRIORITY + * when an ISR safe FreeRTOS API function was executed. ISR safe FreeRTOS API + * functions are those that end in FromISR. FreeRTOS maintains a separate + * interrupt API to ensure API function and interrupt entry is as fast and as + * simple as possible. */ +#define portENABLE_INTERRUPTS() __set_interrupt_level( ( uint8_t ) 0 ) +#ifdef configASSERT + #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() configASSERT( ( __get_interrupt_level() <= configMAX_SYSCALL_INTERRUPT_PRIORITY ) ) + #define portDISABLE_INTERRUPTS() if( __get_interrupt_level() < configMAX_SYSCALL_INTERRUPT_PRIORITY ) __set_interrupt_level( ( uint8_t ) configMAX_SYSCALL_INTERRUPT_PRIORITY ) +#else + #define portDISABLE_INTERRUPTS() __set_interrupt_level( ( uint8_t ) configMAX_SYSCALL_INTERRUPT_PRIORITY ) +#endif + +/* Critical nesting counts are stored in the TCB. */ +#define portCRITICAL_NESTING_IN_TCB ( 1 ) + +/* The critical nesting functions defined within tasks.c. */ +extern void vTaskEnterCritical( void ); +extern void vTaskExitCritical( void ); +#define portENTER_CRITICAL() vTaskEnterCritical() +#define portEXIT_CRITICAL() vTaskExitCritical() + +/* As this port allows interrupt nesting... */ +#define portSET_INTERRUPT_MASK_FROM_ISR() __get_interrupt_level(); portDISABLE_INTERRUPTS() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ) __set_interrupt_level( ( uint8_t ) ( uxSavedInterruptStatus ) ) + +/*-----------------------------------------------------------*/ + +/* 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 ) + +/*-----------------------------------------------------------*/ + +/* If portUSE_TASK_DPFPU_SUPPORT is set to 1 (or left undefined) then tasks are + * created without a DPFPU context and must call vPortTaskUsesDPFPU() to give + * themselves a DPFPU context before using any DPFPU instructions. If + * portUSE_TASK_DPFPU_SUPPORT is set to 2 then all tasks will have a DPFPU context + * by default. */ +#if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + void vPortTaskUsesDPFPU( void ); +#else + + /* Each task has a DPFPU context already, so define this function away to + * nothing to prevent it being called accidentally. */ + #define vPortTaskUsesDPFPU() +#endif +#define portTASK_USES_DPFPU() vPortTaskUsesDPFPU() + +/* Definition to allow compatibility with existing FreeRTOS Demo using flop.c. */ +#define portTASK_USES_FLOATING_POINT() vPortTaskUsesDPFPU() + +/*-----------------------------------------------------------*/ + +/* Checks whether the current execution context is interrupt. + * Return pdTRUE if the current execution context is interrupt, + * pdFALSE otherwise. */ +#pragma inline = forced +static __inline BaseType_t xPortIsInsideInterrupt( void ) +{ + /* When the user stack pointer is used, the context is not interrupt. + * When the interrupt stack pointer is used, the context is interrupt. + * Don't call this function before the scheduler has started because + * this function always returns pdTRUE before the timing. */ + return ( __get_PSW_register() & 0x00020000 /* PSW.U */ ) != 0 ? pdFALSE : pdTRUE; +} + +/*-----------------------------------------------------------*/ + +#define portMEMORY_BARRIER() __asm volatile ( "" portCDT_NO_PARSE( ::: ) "memory" ) + +/*-----------------------------------------------------------*/ + +/* Prevent warnings of undefined behaviour: the order of volatile accesses is + * undefined - all warnings have been manually checked and are not an issue, and + * the warnings cannot be prevent by code changes without undesirable effects. */ +#pragma diag_suppress=Pa082 + +/* *INDENT-OFF* */ +#ifdef __cplusplus + } +#endif +/* *INDENT-ON* */ + +#endif /* PORTMACRO_H */ diff --git a/portable/IAR/RX/readme.txt b/portable/IAR/RX/readme.txt new file mode 100644 index 0000000000..5617c8df4e --- /dev/null +++ b/portable/IAR/RX/readme.txt @@ -0,0 +1,87 @@ +The generic RX port layer in this folder can be used for the following MCUs in case of other than using +tickless idle functionality of RX100 port layers and/or using C89 specification and/or using old version +of ICCRX. + + +RX MCU Group CPU FPU FPU + Core (Single (Double + Type Precision) Precision) + +RX110 RXv1 No --- +RX111 RXv1 No --- +RX113 RXv1 No --- +RX130 RXv1 No --- +RX13T RXv1 Yes --- + +RX210 RXv1 No --- +RX21A RXv1 No --- +RX220 RXv1 No --- +RX230,RX231 RXv2 Yes --- +RX23E-A RXv2 Yes --- +RX23W RXv2 Yes --- +RX23T RXv2 Yes --- +RX24T RXv2 Yes --- +RX24U RXv2 Yes --- + +RX610 RXv1 Yes --- +RX62N,RX621 RXv1 Yes --- +RX630 RXv1 Yes --- +RX634 RXv1 Yes --- +RX63N,RX631 RXv1 Yes --- +RX64M RXv2 Yes --- +RX65N,RX651 RXv2 Yes --- +RX66N RXv3 Yes Yes +RX62T RXv1 Yes --- +RX62G RXv1 Yes --- +RX63T RXv1 Yes --- +RX66T RXv3 Yes No + +RX71M RXv2 Yes --- +RX72M RXv3 Yes Yes +RX72N RXv3 Yes Yes +RX72T RXv3 Yes No + +Notes: + +(1) When you use the FIT configurator or the Smart Configurator, platform.h has to be used. In this case, +the following definition is necessary in FreeRTOSConfig.h. + +/* If configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H is set to 0 then iodefine.h +is included and used in FreeRTOS Kernel's Renesas RX port. If the macro is set +to 1 then platform.h is included and used in the port. If the macro is set to 2 +then neither iodefine.h nor platform.h are included. If the macro is undefined, +it is set to 0 (CC-RX/GNURX) or 2 (ICCRX) internally for backward compatibility. +When the FIT configurator or the Smart Configurator is used, platform.h has to be +used. */ +#define configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H 1 + +(2) When you use the CC-RX compiler of Renesas or the GNURX compiler, the definition of configTICK_VECTOR +is like the following: + +/* The peripheral used to generate the tick interrupt is configured as part of +the application code. This constant should be set to the vector number of the +peripheral chosen. As supplied this is CMT0. */ +#define configTICK_VECTOR _CMT0_CMI0 + +(3) When you use the ICCRX compiler of IAR, the definition of configTICK_VECTOR depends on the setting of +configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H like the followings: + +(3-1) In case of configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 0 or 1 + +#define configTICK_VECTOR _CMT0_CMI0 + +(3-2) In case of configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 2 or undefined + +#define configTICK_VECTOR VECT_CMT0_CMI0 + +(4) Moreover in the case of above (3-2), I/O register definition header file which is provided from IAR +has to be included in FreeRTOSConfig.h like the followings: + +/* Renesas hardware definition header. */ +#include + + +For more information about Renesas RX MCUs, please visit the following URL: + +https://www.renesas.com/products/microcontrollers-microprocessors/rx.html + diff --git a/portable/Renesas/RX/port.c b/portable/Renesas/RX/port.c new file mode 100644 index 0000000000..dc4657f1c1 --- /dev/null +++ b/portable/Renesas/RX/port.c @@ -0,0 +1,754 @@ +/* + * 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 + * + */ + +/*----------------------------------------------------------- +* Implementation of functions defined in portable.h for the Renesas RX port. +*----------------------------------------------------------*/ + +/* Scheduler includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Library includes. */ +#include "string.h" + +/* Hardware specifics. */ +#if ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 0 ) + #include "iodefine.h" +#elif ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 1 ) + #include "platform.h" +#elif ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 2 ) + /* Nothing to be included here. */ +#else + #error Invalid configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H setting - configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H must be set to 0, 1, 2, or left undefined. +#endif + +/* Miscellaneous checks for this port. */ +#if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) || ( configUSE_TASK_DPFPU_SUPPORT == 2 ) + #warning Testing for DPFPU support in this port is not yet complete +#elif ( configUSE_TASK_DPFPU_SUPPORT != 0 ) + #error Invalid configUSE_TASK_DPFPU_SUPPORT setting - configUSE_TASK_DPFPU_SUPPORT must be set to 0, 1, 2, or left undefined. +#endif + +#if !defined( __RXV1 ) && !defined( __RXV2 ) && !defined( __RXV3 ) + #if ( __RENESAS_VERSION__ < 0x03010000 ) + /* Not necessary: #error This old version of CC-RX is not supported. */ + #else + #warning This new CPU core may not be supported. + #endif +#endif + +#if !defined( __STDC_VERSION__ ) || ( __STDC_VERSION__ < 199901L ) + #error This port needs C99 or later. +#endif + +/*-----------------------------------------------------------*/ + +/* Tasks should start with interrupts enabled and in Supervisor mode, therefore + * PSW is set with U and I set, and PM and IPL clear. */ +#define portINITIAL_PSW ( ( StackType_t ) 0x00030000 ) +#define portINITIAL_FPSW ( ( StackType_t ) 0x00000100 ) +#define portINITIAL_DPSW ( ( StackType_t ) 0x00000100 ) +#define portINITIAL_DCMR ( ( StackType_t ) 0x00000000 ) +#define portINITIAL_DECNT ( ( StackType_t ) 0x00000001 ) + +/* Tasks are not created with a DPFPU context, but can be given a DPFPU context + * after they have been created. A variable is stored as part of the tasks context + * that holds portNO_DPFPU_CONTEXT if the task does not have a DPFPU context, or + * any other value if the task does have a DPFPU context. */ +#define portNO_DPFPU_CONTEXT ( ( StackType_t ) 0 ) +#define portHAS_DPFPU_CONTEXT ( ( StackType_t ) 1 ) + +/* The space on the stack required to hold the general purpos registers. This is 16 + * 32-bit registers, except for R0 (for stack pointer) and R1 (for pvParameters). */ +#define portGENERAL_PURPOSE_REGISTER_WORDS ( 16 - 2 ) + +/* The space on the stack required to hold the accumulator. This is 2 or 6 + * 32-bit registers. */ +#if ( portUSE_TASK_ACC_SUPPORT == 1 ) + + #define portACCUMULATOR_REGISTER_WORDS ( 2 ) + +#elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + + #define portACCUMULATOR_REGISTER_WORDS ( 6 ) + +#endif /* portUSE_TASK_ACC_SUPPORT */ + +/* The space on the stack required to hold the DPFPU data registers. This is 16 + * 64-bit registers. */ +#define portDPFPU_DATA_REGISTER_WORDS ( 16 * 2 ) + +/*-----------------------------------------------------------*/ + +/* The following lines are to ensure vSoftwareInterruptEntry can be referenced, + * and therefore installed in the vector table, when the FreeRTOS code is built + * as a library. */ +extern BaseType_t vSoftwareInterruptEntry; +const BaseType_t * p_vSoftwareInterruptEntry = &vSoftwareInterruptEntry; + +/*-----------------------------------------------------------*/ + +/* + * Function to start the first task executing - written in asm code as direct + * access to registers is required. + */ +static void prvStartFirstTask( void ); + +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + +/* + * Force an assert. + */ +static void prvForceAssert( void ); + +/* + * Software interrupt handler. Performs the actual context switch (saving and + * restoring of registers). Written in asm code as direct register access is + * required. It is installed in the vector table written in other asm source. + */ +void vSoftwareInterruptISR( void ); + +/* + * The tick ISR handler. The peripheral used is configured by the application + * via a hook/callback function. + */ +void vTickISR( void ); + +/*-----------------------------------------------------------*/ + +/* Saved as part of the task context. If ulPortTaskHasDPFPUContext is non-zero + * then a DPFPU context must be saved and restored for the task. */ +#if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + StackType_t ulPortTaskHasDPFPUContext = portNO_DPFPU_CONTEXT; + +#endif + +/* This is accessed by the inline assembler functions so is file scope for + * convenience. */ +extern void * pxCurrentTCB; +extern void vTaskSwitchContext( void ); + +/*-----------------------------------------------------------*/ + +/* + * See header file for description. + */ +StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, + TaskFunction_t pxCode, + void * pvParameters ) +{ + /* R0 is not included as it is the stack pointer. */ + + /* Prevent the debugger from messing up unwinding of the stack. */ + *pxTopOfStack = ( StackType_t ) 0x0; + pxTopOfStack--; + + /* '+ 1 ' is a workaround for preventing rx-elf-gdb from messing up. */ + *pxTopOfStack = ( ( StackType_t ) prvTaskExitError ) + 1; + pxTopOfStack--; + *pxTopOfStack = portINITIAL_PSW; + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) pxCode; + + /* When debugging it can be useful if every register is set to a known + * value. Otherwise code space can be saved by just setting the registers + * that need to be set. */ + #ifdef USE_FULL_REGISTER_INITIALISATION + { + pxTopOfStack--; + *pxTopOfStack = 0xffffffff; /* r15. */ + pxTopOfStack--; + *pxTopOfStack = 0xeeeeeeee; + pxTopOfStack--; + *pxTopOfStack = 0xdddddddd; + pxTopOfStack--; + *pxTopOfStack = 0xcccccccc; + pxTopOfStack--; + *pxTopOfStack = 0xbbbbbbbb; + pxTopOfStack--; + *pxTopOfStack = 0xaaaaaaaa; + pxTopOfStack--; + *pxTopOfStack = 0x99999999; + pxTopOfStack--; + *pxTopOfStack = 0x88888888; + pxTopOfStack--; + *pxTopOfStack = 0x77777777; + pxTopOfStack--; + *pxTopOfStack = 0x66666666; + pxTopOfStack--; + *pxTopOfStack = 0x55555555; + pxTopOfStack--; + *pxTopOfStack = 0x44444444; + pxTopOfStack--; + *pxTopOfStack = 0x33333333; + pxTopOfStack--; + *pxTopOfStack = 0x22222222; + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= portGENERAL_PURPOSE_REGISTER_WORDS; + memset( pxTopOfStack, 0x00, portGENERAL_PURPOSE_REGISTER_WORDS * sizeof( StackType_t ) ); + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + + pxTopOfStack--; + *pxTopOfStack = ( StackType_t ) pvParameters; /* R1 */ + + #if ( portUSE_TASK_FPU_SUPPORT == 1 ) + { + pxTopOfStack--; + *pxTopOfStack = portINITIAL_FPSW; + } + #endif + + #if ( portUSE_TASK_ACC_SUPPORT == 1 ) + { + #ifdef USE_FULL_REGISTER_INITIALISATION + { + pxTopOfStack--; + *pxTopOfStack = 0x12345678; /* Accumulator. */ + pxTopOfStack--; + *pxTopOfStack = 0x87654321; /* Accumulator. */ + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= portACCUMULATOR_REGISTER_WORDS; + memset( pxTopOfStack, 0x00, portACCUMULATOR_REGISTER_WORDS * sizeof( StackType_t ) ); + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + } + #elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + { + #ifdef USE_FULL_REGISTER_INITIALISATION + { + pxTopOfStack--; + *pxTopOfStack = 0x11111111; /* Accumulator 1. */ + pxTopOfStack--; + *pxTopOfStack = 0x22222222; /* Accumulator 1. */ + pxTopOfStack--; + *pxTopOfStack = 0x33333333; /* Accumulator 1. */ + pxTopOfStack--; + *pxTopOfStack = 0x44444444; /* Accumulator 0. */ + pxTopOfStack--; + *pxTopOfStack = 0x55555555; /* Accumulator 0. */ + pxTopOfStack--; + *pxTopOfStack = 0x66666666; /* Accumulator 0. */ + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= portACCUMULATOR_REGISTER_WORDS; + memset( pxTopOfStack, 0x00, portACCUMULATOR_REGISTER_WORDS * sizeof( StackType_t ) ); + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + } + #endif /* portUSE_TASK_ACC_SUPPORT */ + + #if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + { + /* The task will start without a DPFPU context. A task that + * uses the DPFPU hardware must call vPortTaskUsesDPFPU() before + * executing any floating point instructions. */ + pxTopOfStack--; + *pxTopOfStack = portNO_DPFPU_CONTEXT; + } + #elif ( portUSE_TASK_DPFPU_SUPPORT == 2 ) + { + /* The task will start with a DPFPU context. Leave enough + * space for the registers - and ensure they are initialised if desired. */ + #ifdef USE_FULL_REGISTER_INITIALISATION + { + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1515.1515; /* DR15. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1414.1414; /* DR14. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1313.1313; /* DR13. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1212.1212; /* DR12. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1111.1111; /* DR11. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 1010.1010; /* DR10. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 909.0909; /* DR9. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 808.0808; /* DR8. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 707.0707; /* DR7. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 606.0606; /* DR6. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 505.0505; /* DR5. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 404.0404; /* DR4. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 303.0303; /* DR3. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 202.0202; /* DR2. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 101.0101; /* DR1. */ + pxTopOfStack -= 2; + *( double * ) pxTopOfStack = 9876.54321; /* DR0. */ + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= portDPFPU_DATA_REGISTER_WORDS; + memset( pxTopOfStack, 0x00, portDPFPU_DATA_REGISTER_WORDS * sizeof( StackType_t ) ); + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + pxTopOfStack--; + *pxTopOfStack = portINITIAL_DECNT; /* DECNT. */ + pxTopOfStack--; + *pxTopOfStack = portINITIAL_DCMR; /* DCMR. */ + pxTopOfStack--; + *pxTopOfStack = portINITIAL_DPSW; /* DPSW. */ + } + #endif /* portUSE_TASK_DPFPU_SUPPORT */ + + return pxTopOfStack; +} +/*-----------------------------------------------------------*/ + +#pragma noinline prvTaskExitError +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. */ + + /* Adding NOP is a workaround to prevent rx-elf-gdb from messing up. */ + portNOP(); + + /* Any function call other than portNOP() should not be inlined in this + * function to ensure the address of here is 'prvTaskExitError + 1'. */ + prvForceAssert(); +} +/*-----------------------------------------------------------*/ + +#if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + void vPortTaskUsesDPFPU( void ) + { + /* A task is registering the fact that it needs a DPFPU context. Set the + * DPFPU flag (which is saved as part of the task context). */ + ulPortTaskHasDPFPUContext = portHAS_DPFPU_CONTEXT; + } + +#endif /* portUSE_TASK_DPFPU_SUPPORT */ +/*-----------------------------------------------------------*/ + +BaseType_t xPortStartScheduler( void ) +{ + extern void vApplicationSetupTimerInterrupt( void ); + + /* Use pxCurrentTCB just so it does not get optimised away. */ + if( pxCurrentTCB != NULL ) + { + /* Call an application function to set up the timer that will generate the + * tick interrupt. This way the application can decide which peripheral to + * use. A demo application is provided to show a suitable example. */ + vApplicationSetupTimerInterrupt(); + + /* Enable the software interrupt. */ + _IEN( _ICU_SWINT ) = 1; + + /* Ensure the software interrupt is clear. */ + _IR( _ICU_SWINT ) = 0; + + /* Ensure the software interrupt is set to the kernel priority. */ + _IPR( _ICU_SWINT ) = configKERNEL_INTERRUPT_PRIORITY; + + /* Start the first task. */ + prvStartFirstTask(); + } + + /* The following line is just to prevent the symbol getting optimised away. */ + ( void ) vTaskSwitchContext(); + + /* Should not get here. */ + return pdFAIL; +} +/*-----------------------------------------------------------*/ + +void vPortEndScheduler( void ) +{ + /* Not implemented in ports where there is nothing to return to. + * Artificially force an assert. */ + prvForceAssert(); +} +/*-----------------------------------------------------------*/ + +#pragma noinline prvForceAssert +static void prvForceAssert( void ) +{ + configASSERT( pxCurrentTCB == NULL ); + portDISABLE_INTERRUPTS(); + + for( ; ; ) + { + } +} +/*-----------------------------------------------------------*/ + +#pragma inline_asm prvStartFirstTask +static void prvStartFirstTask( void ) +{ +/* *INDENT-OFF* */ +portASM_BEGIN + + /* When starting the scheduler there is nothing that needs moving to the + * interrupt stack because the function is not called from an interrupt. + * Just ensure the current stack is the user stack. */ + portASM( SETPSW U ) + + + /* Obtain the location of the stack associated with which ever task + * pxCurrentTCB is currently pointing to. */ + portASM( MOV.L #_pxCurrentTCB, R15 ) + portASM( MOV.L [ R15 ], R15 ) + portASM( MOV.L [ R15 ], R0 ) + + + /* Restore the registers from the stack of the task pointed to by + * pxCurrentTCB. */ + + #if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* The restored ulPortTaskHasDPFPUContext is to be zero here. + * So, it is never necessary to restore the DPFPU context here. */ + portASM( POP R15 ) + portASM( MOV.L #_ulPortTaskHasDPFPUContext, R14 ) + portASM( MOV.L R15, [ R14 ] ) + + #elif ( portUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Restore the DPFPU context. */ + portASM( DPOPM.L DPSW-DECNT ) + portASM( DPOPM.D DR0-DR15 ) + + #endif /* portUSE_TASK_DPFPU_SUPPORT */ + + #if ( portUSE_TASK_ACC_SUPPORT == 1 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15 ) + + #elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15, A0 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15, A0 ) + + /* Accumulator guard. */ + portASM( POP R15 ) + portASM( MVTACGU R15, A0 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15, A1 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15, A1 ) + + /* Accumulator guard. */ + portASM( POP R15 ) + portASM( MVTACGU R15, A1 ) + + #endif /* portUSE_TASK_ACC_SUPPORT */ + + #if ( portUSE_TASK_FPU_SUPPORT == 1 ) + + /* Floating point status word. */ + portASM( POP R15 ) + portASM( MVTC R15, FPSW ) + + #endif + + /* R1 to R15 - R0 is not included as it is the SP. */ + portASM( POPM R1-R15 ) + + /* This pops the remaining registers. */ + portASM( RTE ) + portASM( NOP ) + portASM( NOP ) + +portASM_END +/* *INDENT-ON* */ +} +/*-----------------------------------------------------------*/ + +#pragma inline_asm vSoftwareInterruptISR +void vSoftwareInterruptISR( void ) +{ +/* *INDENT-OFF* */ +portASM_BEGIN + + /* Re-enable interrupts. */ + portASM( SETPSW I ) + + + /* Move the data that was automatically pushed onto the interrupt stack when + * the interrupt occurred from the interrupt stack to the user stack. + * + * R15 is saved before it is clobbered. */ + portASM( PUSH.L R15 ) + + /* Read the user stack pointer. */ + portASM( MVFC USP, R15 ) + + /* Move the address down to the data being moved. */ + portASM( SUB #12, R15 ) + portASM( MVTC R15, USP ) + + /* Copy the data across, R15, then PC, then PSW. */ + portASM( MOV.L [ R0 ], [ R15 ] ) + portASM( MOV.L 4[ R0 ], 4[ R15 ] ) + portASM( MOV.L 8[ R0 ], 8[ R15 ] ) + + /* Move the interrupt stack pointer to its new correct position. */ + portASM( ADD #12, R0 ) + + /* All the rest of the registers are saved directly to the user stack. */ + portASM( SETPSW U ) + + /* Save the rest of the general registers (R15 has been saved already). */ + portASM( PUSHM R1-R14 ) + + /* Save the FPSW and accumulators. */ + #if ( portUSE_TASK_FPU_SUPPORT == 1 ) + + portASM( MVFC FPSW, R15 ) + portASM( PUSH.L R15 ) + + #endif + + #if ( portUSE_TASK_ACC_SUPPORT == 1 ) + + /* Save the accumulator. */ + portASM( MVFACHI R15 ) + portASM( PUSH.L R15 ) + + /* Middle word. */ + portASM( MVFACMI R15 ) + + /* Shifted left as it is restored to the low order word. */ + portASM( SHLL #16, R15 ) + portASM( PUSH.L R15 ) + + #elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + + /* Accumulator guard. */ + portASM( MVFACGU #0, A1, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator high 32 bits. */ + portASM( MVFACHI #0, A1, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator low 32 bits. */ + portASM( MVFACLO #0, A1, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator guard. */ + portASM( MVFACGU #0, A0, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator high 32 bits. */ + portASM( MVFACHI #0, A0, R15 ) + portASM( PUSH.L R15 ) + + /* Accumulator low 32 bits. */ + portASM( MVFACLO #0, A0, R15 ) + portASM( PUSH.L R15 ) + + #endif /* portUSE_TASK_ACC_SUPPORT */ + + #if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* Does the task have a DPFPU context that needs saving? If + * ulPortTaskHasDPFPUContext is 0 then no. */ + portASM( MOV.L #_ulPortTaskHasDPFPUContext, R15 ) + portASM( MOV.L [ R15 ], R15 ) + portASM( CMP #0, R15 ) + + /* Save the DPFPU context, if any. */ + portASM( BEQ.B portASM_LAB_NEXT( vSoftwareInterruptISR_1 ) ) + portASM( DPUSHM.D DR0-DR15 ) + portASM( DPUSHM.L DPSW-DECNT ) + portASM_LAB( vSoftwareInterruptISR_1: ) + + /* Save ulPortTaskHasDPFPUContext itself. */ + portASM( PUSH.L R15 ) + + #elif ( portUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Save the DPFPU context, always. */ + portASM( DPUSHM.D DR0-DR15 ) + portASM( DPUSHM.L DPSW-DECNT ) + + #endif /* portUSE_TASK_DPFPU_SUPPORT */ + + + /* Save the stack pointer to the TCB. */ + portASM( MOV.L #_pxCurrentTCB, R15 ) + portASM( MOV.L [ R15 ], R15 ) + portASM( MOV.L R0, [ R15 ] ) + + + /* Ensure the interrupt mask is set to the syscall priority while the kernel + * structures are being accessed. */ + portASM( MVTIPL #configMAX_SYSCALL_INTERRUPT_PRIORITY ) + + /* Select the next task to run. */ + portASM( BSR.A _vTaskSwitchContext ) + + /* Reset the interrupt mask as no more data structure access is required. */ + portASM( MVTIPL #configKERNEL_INTERRUPT_PRIORITY ) + + + /* Load the stack pointer of the task that is now selected as the Running + * state task from its TCB. */ + portASM( MOV.L #_pxCurrentTCB, R15 ) + portASM( MOV.L [ R15 ], R15 ) + portASM( MOV.L [ R15 ], R0 ) + + + /* Restore the context of the new task. The PSW (Program Status Word) and + * PC will be popped by the RTE instruction. */ + + #if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* Is there a DPFPU context to restore? If the restored + * ulPortTaskHasDPFPUContext is zero then no. */ + portASM( POP R15 ) + portASM( MOV.L #_ulPortTaskHasDPFPUContext, R14 ) + portASM( MOV.L R15, [ R14 ] ) + portASM( CMP #0, R15 ) + + /* Restore the DPFPU context, if any. */ + portASM( BEQ.B portASM_LAB_NEXT( vSoftwareInterruptISR_2 ) ) + portASM( DPOPM.L DPSW-DECNT ) + portASM( DPOPM.D DR0-DR15 ) + portASM_LAB( vSoftwareInterruptISR_2: ) + + #elif ( portUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Restore the DPFPU context, always. */ + portASM( DPOPM.L DPSW-DECNT ) + portASM( DPOPM.D DR0-DR15 ) + + #endif /* portUSE_TASK_DPFPU_SUPPORT */ + + #if ( portUSE_TASK_ACC_SUPPORT == 1 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15 ) + + #elif ( portUSE_TASK_ACC_SUPPORT == 2 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15, A0 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15, A0 ) + + /* Accumulator guard. */ + portASM( POP R15 ) + portASM( MVTACGU R15, A0 ) + + /* Accumulator low 32 bits. */ + portASM( POP R15 ) + portASM( MVTACLO R15, A1 ) + + /* Accumulator high 32 bits. */ + portASM( POP R15 ) + portASM( MVTACHI R15, A1 ) + + /* Accumulator guard. */ + portASM( POP R15 ) + portASM( MVTACGU R15, A1 ) + + #endif /* portUSE_TASK_ACC_SUPPORT */ + + #if ( portUSE_TASK_FPU_SUPPORT == 1 ) + + portASM( POP R15 ) + portASM( MVTC R15, FPSW ) + + #endif + + portASM( POPM R1-R15 ) + portASM( RTE ) + portASM( NOP ) + portASM( NOP ) + +portASM_END +/* *INDENT-ON* */ +} +/*-----------------------------------------------------------*/ + +#pragma interrupt ( vTickISR( vect = _VECT( configTICK_VECTOR ), enable ) ) +void vTickISR( void ) +{ + /* Increment the tick, and perform any processing the new tick value + * necessitates. Ensure IPL is at the max syscall value first. */ + set_ipl( configMAX_SYSCALL_INTERRUPT_PRIORITY ); + { + if( xTaskIncrementTick() != pdFALSE ) + { + taskYIELD(); + } + } + set_ipl( configKERNEL_INTERRUPT_PRIORITY ); +} +/*-----------------------------------------------------------*/ diff --git a/portable/Renesas/RX/port_asm.src b/portable/Renesas/RX/port_asm.src new file mode 100644 index 0000000000..428d14a173 --- /dev/null +++ b/portable/Renesas/RX/port_asm.src @@ -0,0 +1,41 @@ +; /* *INDENT-OFF* */ +; /* +; * 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 +; * +; */ + + .GLB _vSoftwareInterruptISR + .GLB _vSoftwareInterruptEntry + + .SECTION P,CODE + +_vSoftwareInterruptEntry: + + BRA _vSoftwareInterruptISR + + .RVECTOR 27, _vSoftwareInterruptEntry + + .END diff --git a/portable/Renesas/RX/portmacro.h b/portable/Renesas/RX/portmacro.h new file mode 100644 index 0000000000..ffcfcd3945 --- /dev/null +++ b/portable/Renesas/RX/portmacro.h @@ -0,0 +1,269 @@ +/* + * 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 + +/* *INDENT-OFF* */ +#ifdef __cplusplus + extern "C" { +#endif +/* *INDENT-ON* */ + +/* Hardware specifics. */ +#include + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* If configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H is set to 0 then iodefine.h + * is included and used in FreeRTOS Kernel's Renesas RX port. If the macro is set + * to 1 then platform.h is included and used in the port. If the macro is set to 2 + * then neither iodefine.h nor platform.h are included. If the macro is undefined, + * it is set to 0 (CC-RX/GNURX) or 2 (ICCRX) internally for backward compatibility. + * When the FIT configurator or the Smart Configurator is used, platform.h has to be + * used. */ +#ifndef configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H + #define configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H 0 +#endif + +/* If configUSE_TASK_DPFPU_SUPPORT is set to 1 (or undefined) then each task will + * be created without a DPFPU context, and a task must call vTaskUsesDPFPU() before + * making use of any DPFPU registers. If configUSE_TASK_DPFPU_SUPPORT is set to 2 then + * tasks are created with a DPFPU context by default, and calling vTaskUsesDPFPU() has + * no effect. If configUSE_TASK_DPFPU_SUPPORT is set to 0 then tasks never take care + * of any DPFPU context (even if DPFPU registers are used). */ +#ifdef __DPFPU + /* The compiler may use DPFPU registers. */ + #ifndef configUSE_TASK_DPFPU_SUPPORT + #define configUSE_TASK_DPFPU_SUPPORT 1 + #endif +#else + /* The compiler does not use DPFPU registers. */ + #ifdef configUSE_TASK_DPFPU_SUPPORT + #undef configUSE_TASK_DPFPU_SUPPORT + #endif + #define configUSE_TASK_DPFPU_SUPPORT 0 +#endif +#define portUSE_TASK_DPFPU_SUPPORT configUSE_TASK_DPFPU_SUPPORT + +#ifdef __FPU + /* The compiler may use FPSW register. */ + #define portUSE_TASK_FPU_SUPPORT 1 +#else + /* The compiler does not use FPSW register. */ + #define portUSE_TASK_FPU_SUPPORT 0 +#endif + +#ifdef __RXV1 + /* The CPU has only one accumulator. */ + #define portUSE_TASK_ACC_SUPPORT 1 +#elif !defined( __RXV2 ) && !defined( __RXV3 ) && ( __RENESAS_VERSION__ < 0x03010000 ) + /* The CPU is RXv1 and has only one accumulator. */ + #define portUSE_TASK_ACC_SUPPORT 1 +#else + /* The CPU has two accumulators. */ + #define portUSE_TASK_ACC_SUPPORT 2 +#endif + +/*-----------------------------------------------------------*/ + +/* 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; + +#if ( configUSE_16_BIT_TICKS == 1 ) + typedef uint16_t TickType_t; + #define portMAX_DELAY ( TickType_t ) 0xffff +#else + 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 +#endif + +/*-----------------------------------------------------------*/ + +/* Inline assembler specifics. */ +#if ( defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901L ) ) + /* *INDENT-OFF* */ + #ifdef __CDT_PARSER__ + #define _portASM( ... ) (void) ( #__VA_ARGS__ "\n" ); + #else + #define _portASM( ... ) __VA_ARGS__ + #endif + #define portASM( ... ) _portASM( __VA_ARGS__ ) + #define portASM_LAB_NEXT( name ) ?+ + #define portASM_LAB_PREV( name ) ?- + #define portASM_LAB( name_colon ) _portASM( ?: ) + #define portASM_BEGIN + #define portASM_END + /* *INDENT-ON* */ +#endif /* if ( defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901L ) ) */ + +/*-----------------------------------------------------------*/ + +/* Hardware specifics. */ +#define portBYTE_ALIGNMENT 8 /* Could make four, according to manual. */ +#define portSTACK_GROWTH -1 +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#define portNOP() nop() + +/* Yield equivalent to "*portITU_SWINTR = 0x01; ( void ) ( *portITU_SWINTR == XXX );" + * where portITU_SWINTR is the location of the software interrupt register + * (0x000872E0) and XXX is an arbitrary number. Don't rely on the assembler to + * select a register, so instead save and restore clobbered registers manually. */ +/* *INDENT-OFF* */ +#pragma inline_asm vPortYield +static void vPortYield( void ) +{ +#ifndef __CDT_PARSER__ + /* Save clobbered register - may not actually be necessary if inline asm + * functions are considered to use the same rules as function calls by the + * compiler. */ + PUSH.L R5 + /* Set ITU SWINTR. */ + MOV.L #000872E0H, R5 + MOV.B #1, [ R5 ] + /* Read back to ensure the value is taken before proceeding. */ + CMP [ R5 ].UB, R5 + /* Restore clobbered register to its previous value. */ + POP R5 +#endif +} +/* *INDENT-ON* */ + +#define portYIELD() vPortYield() +#define portYIELD_FROM_ISR( x ) do { if( ( x ) != pdFALSE ) portYIELD(); } while( 0 ) + +/* These macros should not be called directly, but through the + * taskENTER_CRITICAL() and taskEXIT_CRITICAL() macros. An extra check is + * performed if configASSERT() is defined to ensure an assertion handler does not + * inadvertently attempt to lower the IPL when the call to assert was triggered + * because the IPL value was found to be above configMAX_SYSCALL_INTERRUPT_PRIORITY + * when an ISR safe FreeRTOS API function was executed. ISR safe FreeRTOS API + * functions are those that end in FromISR. FreeRTOS maintains a separate + * interrupt API to ensure API function and interrupt entry is as fast and as + * simple as possible. */ +#define portENABLE_INTERRUPTS() set_ipl( ( long ) 0 ) +#ifdef configASSERT + #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() configASSERT( ( get_ipl() <= configMAX_SYSCALL_INTERRUPT_PRIORITY ) ) + #define portDISABLE_INTERRUPTS() if( get_ipl() < configMAX_SYSCALL_INTERRUPT_PRIORITY ) set_ipl( ( long ) configMAX_SYSCALL_INTERRUPT_PRIORITY ) +#else + #define portDISABLE_INTERRUPTS() set_ipl( ( long ) configMAX_SYSCALL_INTERRUPT_PRIORITY ) +#endif + +/* Critical nesting counts are stored in the TCB. */ +#define portCRITICAL_NESTING_IN_TCB ( 1 ) + +/* The critical nesting functions defined within tasks.c. */ +extern void vTaskEnterCritical( void ); +extern void vTaskExitCritical( void ); +#define portENTER_CRITICAL() vTaskEnterCritical() +#define portEXIT_CRITICAL() vTaskExitCritical() + +/* As this port allows interrupt nesting... */ +#define portSET_INTERRUPT_MASK_FROM_ISR() ( UBaseType_t ) get_ipl(); set_ipl( ( long ) configMAX_SYSCALL_INTERRUPT_PRIORITY ) +#define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ) set_ipl( ( long ) uxSavedInterruptStatus ) + +/*-----------------------------------------------------------*/ + +/* 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 ) + +/*-----------------------------------------------------------*/ + +/* If portUSE_TASK_DPFPU_SUPPORT is set to 1 (or left undefined) then tasks are + * created without a DPFPU context and must call vPortTaskUsesDPFPU() to give + * themselves a DPFPU context before using any DPFPU instructions. If + * portUSE_TASK_DPFPU_SUPPORT is set to 2 then all tasks will have a DPFPU context + * by default. */ +#if ( portUSE_TASK_DPFPU_SUPPORT == 1 ) + void vPortTaskUsesDPFPU( void ); +#else + + /* Each task has a DPFPU context already, so define this function away to + * nothing to prevent it being called accidentally. */ + #define vPortTaskUsesDPFPU() +#endif +#define portTASK_USES_DPFPU() vPortTaskUsesDPFPU() + +/* Definition to allow compatibility with existing FreeRTOS Demo using flop.c. */ +#define portTASK_USES_FLOATING_POINT() vPortTaskUsesDPFPU() + +/*-----------------------------------------------------------*/ + +/* Checks whether the current execution context is interrupt. + * Return pdTRUE if the current execution context is interrupt, + * pdFALSE otherwise. */ +#pragma inline xPortIsInsideInterrupt +static BaseType_t xPortIsInsideInterrupt( void ) +{ + /* When the user stack pointer is used, the context is not interrupt. + * When the interrupt stack pointer is used, the context is interrupt. + * Don't call this function before the scheduler has started because + * this function always returns pdTRUE before the timing. */ + return ( get_psw() & 0x00020000 /* PSW.U */ ) != 0 ? pdFALSE : pdTRUE; +} + +/*-----------------------------------------------------------*/ + +#pragma inline_asm vPortMemoryBarrier +static void vPortMemoryBarrier( void ) +{ +} + +#define portMEMORY_BARRIER() vPortMemoryBarrier() + +/* *INDENT-OFF* */ +#ifdef __cplusplus + } +#endif +/* *INDENT-ON* */ + +#endif /* PORTMACRO_H */ diff --git a/portable/Renesas/RX/readme.txt b/portable/Renesas/RX/readme.txt new file mode 100644 index 0000000000..5617c8df4e --- /dev/null +++ b/portable/Renesas/RX/readme.txt @@ -0,0 +1,87 @@ +The generic RX port layer in this folder can be used for the following MCUs in case of other than using +tickless idle functionality of RX100 port layers and/or using C89 specification and/or using old version +of ICCRX. + + +RX MCU Group CPU FPU FPU + Core (Single (Double + Type Precision) Precision) + +RX110 RXv1 No --- +RX111 RXv1 No --- +RX113 RXv1 No --- +RX130 RXv1 No --- +RX13T RXv1 Yes --- + +RX210 RXv1 No --- +RX21A RXv1 No --- +RX220 RXv1 No --- +RX230,RX231 RXv2 Yes --- +RX23E-A RXv2 Yes --- +RX23W RXv2 Yes --- +RX23T RXv2 Yes --- +RX24T RXv2 Yes --- +RX24U RXv2 Yes --- + +RX610 RXv1 Yes --- +RX62N,RX621 RXv1 Yes --- +RX630 RXv1 Yes --- +RX634 RXv1 Yes --- +RX63N,RX631 RXv1 Yes --- +RX64M RXv2 Yes --- +RX65N,RX651 RXv2 Yes --- +RX66N RXv3 Yes Yes +RX62T RXv1 Yes --- +RX62G RXv1 Yes --- +RX63T RXv1 Yes --- +RX66T RXv3 Yes No + +RX71M RXv2 Yes --- +RX72M RXv3 Yes Yes +RX72N RXv3 Yes Yes +RX72T RXv3 Yes No + +Notes: + +(1) When you use the FIT configurator or the Smart Configurator, platform.h has to be used. In this case, +the following definition is necessary in FreeRTOSConfig.h. + +/* If configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H is set to 0 then iodefine.h +is included and used in FreeRTOS Kernel's Renesas RX port. If the macro is set +to 1 then platform.h is included and used in the port. If the macro is set to 2 +then neither iodefine.h nor platform.h are included. If the macro is undefined, +it is set to 0 (CC-RX/GNURX) or 2 (ICCRX) internally for backward compatibility. +When the FIT configurator or the Smart Configurator is used, platform.h has to be +used. */ +#define configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H 1 + +(2) When you use the CC-RX compiler of Renesas or the GNURX compiler, the definition of configTICK_VECTOR +is like the following: + +/* The peripheral used to generate the tick interrupt is configured as part of +the application code. This constant should be set to the vector number of the +peripheral chosen. As supplied this is CMT0. */ +#define configTICK_VECTOR _CMT0_CMI0 + +(3) When you use the ICCRX compiler of IAR, the definition of configTICK_VECTOR depends on the setting of +configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H like the followings: + +(3-1) In case of configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 0 or 1 + +#define configTICK_VECTOR _CMT0_CMI0 + +(3-2) In case of configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 2 or undefined + +#define configTICK_VECTOR VECT_CMT0_CMI0 + +(4) Moreover in the case of above (3-2), I/O register definition header file which is provided from IAR +has to be included in FreeRTOSConfig.h like the followings: + +/* Renesas hardware definition header. */ +#include + + +For more information about Renesas RX MCUs, please visit the following URL: + +https://www.renesas.com/products/microcontrollers-microprocessors/rx.html +