diff --git a/portable/GCC/RX700v3_DPFPU/port.c b/portable/GCC/RX700v3_DPFPU/port.c new file mode 100644 index 000000000..51ce77727 --- /dev/null +++ b/portable/GCC/RX700v3_DPFPU/port.c @@ -0,0 +1,619 @@ +/* + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/*----------------------------------------------------------- +* Implementation of functions defined in portable.h for the RXv3 DPFPU port. +*----------------------------------------------------------*/ + +/* Scheduler includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Library includes. */ +#include "string.h" + +/* Hardware specifics. */ +#if ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 1 ) + + #include "platform.h" + +#else /* configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H */ + + #include "iodefine.h" + +#endif /* configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H */ + +/*-----------------------------------------------------------*/ + +/* 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 DPFPU data registers. This is 16 + * 64-bit registers. */ +#define portDPFPU_DATA_REGISTER_WORDS ( 16 * 2 ) + +/* These macros allow a critical section to be added around the call to + * xTaskIncrementTick(), which is only ever called from interrupts at the kernel + * priority - ie a known priority. Therefore these local macros are a slight + * optimisation compared to calling the global SET/CLEAR_INTERRUPT_MASK macros, + * which would require the old IPL to be read first and stored in a local variable. */ +#define portMASK_INTERRUPTS_FROM_KERNEL_ISR() __asm volatile ( "MVTIPL %0" ::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) ) +#define portUNMASK_INTERRUPTS_FROM_KERNEL_ISR() __asm volatile ( "MVTIPL %0" ::"i" ( configKERNEL_INTERRUPT_PRIORITY ) ) + +/*-----------------------------------------------------------*/ + +/* + * Function to start the first task executing - written in asm code as direct + * access to registers is required. + */ +static void prvStartFirstTask( void ) __attribute__( ( naked ) ); + +/* + * 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 /* configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H */ + + void vSoftwareInterruptISR( void ) __attribute__( ( naked ) ); + +#endif /* configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H */ + +/* + * 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 /* configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H */ + + void vTickISR( void ) __attribute__( ( interrupt ) ); + +#endif /* configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H */ + +/*-----------------------------------------------------------*/ + +/* 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 ( configUSE_TASK_DPFPU_SUPPORT == 1 ) + + StackType_t ulPortTaskHasDPFPUContext = portNO_DPFPU_CONTEXT; + +#endif /* configUSE_TASK_DPFPU_SUPPORT */ + +/* 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. */ + + *pxTopOfStack = 0x00; + 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; + pxTopOfStack--; + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= 15; + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + + *pxTopOfStack = ( StackType_t ) pvParameters; /* R1 */ + pxTopOfStack--; + *pxTopOfStack = portINITIAL_FPSW; + 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. */ + + #if ( configUSE_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 ( configUSE_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. */ + } + #elif ( configUSE_TASK_DPFPU_SUPPORT == 0 ) + { + /* Omit DPFPU support. */ + } + #else /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + { + #error Invalid configUSE_TASK_DPFPU_SUPPORT setting - configUSE_TASK_DPFPU_SUPPORT must be set to 0, 1, 2, or left undefined. + } + #endif /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + + return pxTopOfStack; +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_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 /* configUSE_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. */ + configASSERT( pxCurrentTCB == NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvStartFirstTask( void ) +{ + __asm volatile + ( + + /* 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. */ + "SETPSW U \n"\ + + + /* Obtain the location of the stack associated with which ever task + * pxCurrentTCB is currently pointing to. */ + "MOV.L #_pxCurrentTCB, R15 \n"\ + "MOV.L [R15], R15 \n"\ + "MOV.L [R15], R0 \n"\ + + + /* Restore the registers from the stack of the task pointed to by + * pxCurrentTCB. */ + + #if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* The restored ulPortTaskHasDPFPUContext is to be zero here. + * So, it is never necessary to restore the DPFPU context here. */ + "POP R15 \n"\ + "MOV.L #_ulPortTaskHasDPFPUContext, R14 \n"\ + "MOV.L R15, [R14] \n"\ + + #elif ( configUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Restore the DPFPU context. */ + "DPOPM.L DPSW-DECNT \n"\ + "DPOPM.D DR0-DR15 \n"\ + + #endif /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + + "POP R15 \n"\ + + /* Accumulator low 32 bits. */ + "MVTACLO R15, A0 \n"\ + "POP R15 \n"\ + + /* Accumulator high 32 bits. */ + "MVTACHI R15, A0 \n"\ + "POP R15 \n"\ + + /* Accumulator guard. */ + "MVTACGU R15, A0 \n"\ + "POP R15 \n"\ + + /* Accumulator low 32 bits. */ + "MVTACLO R15, A1 \n"\ + "POP R15 \n"\ + + /* Accumulator high 32 bits. */ + "MVTACHI R15, A1 \n"\ + "POP R15 \n"\ + + /* Accumulator guard. */ + "MVTACGU R15, A1 \n"\ + "POP R15 \n"\ + + /* Floating point status word. */ + "MVTC R15, FPSW \n"\ + + /* R1 to R15 - R0 is not included as it is the SP. */ + "POPM R1-R15 \n"\ + + /* This pops the remaining registers. */ + "RTE \n"\ + "NOP \n"\ + "NOP \n" + ); +} +/*-----------------------------------------------------------*/ + +void vSoftwareInterruptISR( void ) +{ + __asm volatile + ( + /* Re-enable interrupts. */ + "SETPSW I \n"\ + + + /* 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. */ + "PUSH.L R15 \n"\ + + /* Read the user stack pointer. */ + "MVFC USP, R15 \n"\ + + /* Move the address down to the data being moved. */ + "SUB #12, R15 \n"\ + "MVTC R15, USP \n"\ + + /* Copy the data across, R15, then PC, then PSW. */ + "MOV.L [ R0 ], [ R15 ] \n"\ + "MOV.L 4[ R0 ], 4[ R15 ] \n"\ + "MOV.L 8[ R0 ], 8[ R15 ] \n"\ + + /* Move the interrupt stack pointer to its new correct position. */ + "ADD #12, R0 \n"\ + + /* All the rest of the registers are saved directly to the user stack. */ + "SETPSW U \n"\ + + /* Save the rest of the general registers (R15 has been saved already). */ + "PUSHM R1-R14 \n"\ + + /* Save the FPSW and accumulators. */ + "MVFC FPSW, R15 \n"\ + "PUSH.L R15 \n"\ + "MVFACGU #0, A1, R15 \n"\ + "PUSH.L R15 \n"\ + "MVFACHI #0, A1, R15 \n"\ + "PUSH.L R15 \n"\ + "MVFACLO #0, A1, R15 \n" /* Low order word. */ \ + "PUSH.L R15 \n"\ + "MVFACGU #0, A0, R15 \n"\ + "PUSH.L R15 \n"\ + "MVFACHI #0, A0, R15 \n"\ + "PUSH.L R15 \n"\ + "MVFACLO #0, A0, R15 \n" /* Low order word. */ \ + "PUSH.L R15 \n"\ + + #if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* Does the task have a DPFPU context that needs saving? If + * ulPortTaskHasDPFPUContext is 0 then no. */ + "MOV.L #_ulPortTaskHasDPFPUContext, R15 \n"\ + "MOV.L [R15], R15 \n"\ + "CMP #0, R15 \n"\ + + /* Save the DPFPU context, if any. */ + "BEQ.B ?+ \n"\ + "DPUSHM.D DR0-DR15 \n"\ + "DPUSHM.L DPSW-DECNT \n"\ + "?: \n"\ + + /* Save ulPortTaskHasDPFPUContext itself. */ + "PUSH.L R15 \n"\ + + #elif ( configUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Save the DPFPU context, always. */ + "DPUSHM.D DR0-DR15 \n"\ + "DPUSHM.L DPSW-DECNT \n"\ + + #endif /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + + + /* Save the stack pointer to the TCB. */ + "MOV.L #_pxCurrentTCB, R15 \n"\ + "MOV.L [ R15 ], R15 \n"\ + "MOV.L R0, [ R15 ] \n"\ + + + /* Ensure the interrupt mask is set to the syscall priority while the kernel + * structures are being accessed. */ + "MVTIPL %0 \n"\ + + /* Select the next task to run. */ + "BSR.A _vTaskSwitchContext \n"\ + + /* Reset the interrupt mask as no more data structure access is required. */ + "MVTIPL %1 \n"\ + + + /* Load the stack pointer of the task that is now selected as the Running + * state task from its TCB. */ + "MOV.L #_pxCurrentTCB,R15 \n"\ + "MOV.L [ R15 ], R15 \n"\ + "MOV.L [ R15 ], R0 \n"\ + + + /* Restore the context of the new task. The PSW (Program Status Word) and + * PC will be popped by the RTE instruction. */ + + #if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* Is there a DPFPU context to restore? If the restored + * ulPortTaskHasDPFPUContext is zero then no. */ + "POP R15 \n"\ + "MOV.L #_ulPortTaskHasDPFPUContext, R14 \n"\ + "MOV.L R15, [R14] \n"\ + "CMP #0, R15 \n"\ + + /* Restore the DPFPU context, if any. */ + "BEQ.B ?+ \n"\ + "DPOPM.L DPSW-DECNT \n"\ + "DPOPM.D DR0-DR15 \n"\ + "?: \n"\ + + #elif ( configUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Restore the DPFPU context, always. */ + "DPOPM.L DPSW-DECNT \n"\ + "DPOPM.D DR0-DR15 \n"\ + + #endif /* if( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + + "POP R15 \n"\ + + /* Accumulator low 32 bits. */ + "MVTACLO R15, A0 \n"\ + "POP R15 \n"\ + + /* Accumulator high 32 bits. */ + "MVTACHI R15, A0 \n"\ + "POP R15 \n"\ + + /* Accumulator guard. */ + "MVTACGU R15, A0 \n"\ + "POP R15 \n"\ + + /* Accumulator low 32 bits. */ + "MVTACLO R15, A1 \n"\ + "POP R15 \n"\ + + /* Accumulator high 32 bits. */ + "MVTACHI R15, A1 \n"\ + "POP R15 \n"\ + + /* Accumulator guard. */ + "MVTACGU R15, A1 \n"\ + "POP R15 \n"\ + "MVTC R15, FPSW \n"\ + "POPM R1-R15 \n"\ + "RTE \n"\ + "NOP \n"\ + "NOP " + ::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ), "i" ( configKERNEL_INTERRUPT_PRIORITY ) + ); +} +/*-----------------------------------------------------------*/ + +void vTickISR( void ) +{ + /* Re-enabled interrupts. */ + __asm volatile ( "SETPSW I"); + + /* Increment the tick, and perform any processing the new tick value + * necessitates. Ensure IPL is at the max syscall value first. */ + portMASK_INTERRUPTS_FROM_KERNEL_ISR(); + { + if( xTaskIncrementTick() != pdFALSE ) + { + taskYIELD(); + } + } + portUNMASK_INTERRUPTS_FROM_KERNEL_ISR(); +} +/*-----------------------------------------------------------*/ + +uint32_t ulPortGetIPL( void ) +{ + __asm volatile + ( + "MVFC PSW, R1 \n"\ + "SHLR #24, R1 \n"\ + "RTS " + ); + + /* 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; + + __asm volatile + ( + "PUSH R5 \n"\ + "MVFC PSW, R5 \n"\ + "SHLL #24, R1 \n"\ + "AND #-0F000001H, R5 \n"\ + "OR R1, R5 \n"\ + "MVTC R5, PSW \n"\ + "POP R5 \n"\ + "RTS " + ); +} +/*-----------------------------------------------------------*/ diff --git a/portable/GCC/RX700v3_DPFPU/portmacro.h b/portable/GCC/RX700v3_DPFPU/portmacro.h new file mode 100644 index 000000000..8cffa3835 --- /dev/null +++ b/portable/GCC/RX700v3_DPFPU/portmacro.h @@ -0,0 +1,186 @@ +/* + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +#ifndef PORTMACRO_H + #define PORTMACRO_H + + #ifdef __cplusplus + extern "C" { + #endif + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* 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). */ + #ifndef configUSE_TASK_DPFPU_SUPPORT + #define configUSE_TASK_DPFPU_SUPPORT 1 + #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 + +/*-----------------------------------------------------------*/ + +/* 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;" + * where portITU_SWINTR is the location of the software interrupt register + * (0x000872E0). Don't rely on the assembler to select a register, so instead + * save and restore clobbered registers manually. */ + #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 \n"\ + :::"cc" \ + ) + + #define portYIELD_FROM_ISR( x ) if( ( x ) != pdFALSE ) portYIELD() + +/* 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 + +/* 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 configUSE_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 + * configUSE_TASK_DPFPU_SUPPORT is set to 2 then all tasks will have a DPFPU context + * by default. */ + #if( configUSE_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() + + #ifdef __cplusplus + } + #endif + +#endif /* PORTMACRO_H */ diff --git a/portable/IAR/RX700v3_DPFPU/port.c b/portable/IAR/RX700v3_DPFPU/port.c new file mode 100644 index 000000000..fc0446419 --- /dev/null +++ b/portable/IAR/RX700v3_DPFPU/port.c @@ -0,0 +1,565 @@ +/* + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/*----------------------------------------------------------- +* Implementation of functions defined in portable.h for the RXv3 DPFPU port. +*----------------------------------------------------------*/ + +/* Scheduler includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Library includes. */ +#include "string.h" + +/* Hardware specifics. */ +#if ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 1 ) + + #include "platform.h" + +#else /* configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H */ + + #include "iodefine.h" + +#endif /* configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H */ + +/*-----------------------------------------------------------*/ + +/* 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 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 ); + +/* + * 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 ( configUSE_TASK_DPFPU_SUPPORT == 1 ) + + StackType_t ulPortTaskHasDPFPUContext = portNO_DPFPU_CONTEXT; + +#endif /* configUSE_TASK_DPFPU_SUPPORT */ + +/* 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. */ + + *pxTopOfStack = 0x00; + 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; + pxTopOfStack--; + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= 15; + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + + *pxTopOfStack = ( StackType_t ) pvParameters; /* R1 */ + pxTopOfStack--; + *pxTopOfStack = portINITIAL_FPSW; + 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. */ + + #if ( configUSE_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 ( configUSE_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. */ + } + #elif ( configUSE_TASK_DPFPU_SUPPORT == 0 ) + { + /* Omit DPFPU support. */ + } + #else /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + { + #error Invalid configUSE_TASK_DPFPU_SUPPORT setting - configUSE_TASK_DPFPU_SUPPORT must be set to 0, 1, 2, or left undefined. + } + #endif /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + + return pxTopOfStack; +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_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 /* configUSE_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. */ + configASSERT( pxCurrentTCB == NULL ); + + /* The following line is just to prevent the symbol getting optimised away. */ + ( void ) vTaskSwitchContext(); +} +/*-----------------------------------------------------------*/ + +static void prvStartFirstTask( void ) +{ + __asm volatile + ( + + /* 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. */ + "SETPSW U \n"\ + + + /* Obtain the location of the stack associated with which ever task + * pxCurrentTCB is currently pointing to. */ + "MOV.L #_pxCurrentTCB, R15 \n"\ + "MOV.L [R15], R15 \n"\ + "MOV.L [R15], R0 \n"\ + + + /* Restore the registers from the stack of the task pointed to by + * pxCurrentTCB. */ + + #if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* The restored ulPortTaskHasDPFPUContext is to be zero here. + * So, it is never necessary to restore the DPFPU context here. */ + "POP R15 \n"\ + "MOV.L #_ulPortTaskHasDPFPUContext, R14 \n"\ + "MOV.L R15, [R14] \n"\ + + #elif ( configUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Restore the DPFPU context. */ + "DPOPM.L DPSW-DECNT \n"\ + "DPOPM.D DR0-DR15 \n"\ + + #endif /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + + "POP R15 \n"\ + + /* Accumulator low 32 bits. */ + "MVTACLO R15, A0 \n"\ + "POP R15 \n"\ + + /* Accumulator high 32 bits. */ + "MVTACHI R15, A0 \n"\ + "POP R15 \n"\ + + /* Accumulator guard. */ + "MVTACGU R15, A0 \n"\ + "POP R15 \n"\ + + /* Accumulator low 32 bits. */ + "MVTACLO R15, A1 \n"\ + "POP R15 \n"\ + + /* Accumulator high 32 bits. */ + "MVTACHI R15, A1 \n"\ + "POP R15 \n"\ + + /* Accumulator guard. */ + "MVTACGU R15, A1 \n"\ + "POP R15 \n"\ + + /* Floating point status word. */ + "MVTC R15, FPSW \n"\ + + /* R1 to R15 - R0 is not included as it is the SP. */ + "POPM R1-R15 \n"\ + + /* This pops the remaining registers. */ + "RTE \n"\ + "NOP \n"\ + "NOP \n" + ); +} +/*-----------------------------------------------------------*/ + +#pragma vector = VECT( ICU, SWINT ) +__interrupt void vSoftwareInterruptISR( void ) +{ + __asm volatile + ( + /* Re-enable interrupts. */ + "SETPSW I \n"\ + + + /* 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. */ + "PUSH.L R15 \n"\ + + /* Read the user stack pointer. */ + "MVFC USP, R15 \n"\ + + /* Move the address down to the data being moved. */ + "SUB #12, R15 \n"\ + "MVTC R15, USP \n"\ + + /* Copy the data across, R15, then PC, then PSW. */ + "MOV.L [ R0 ], [ R15 ] \n"\ + "MOV.L 4[ R0 ], 4[ R15 ] \n"\ + "MOV.L 8[ R0 ], 8[ R15 ] \n"\ + + /* Move the interrupt stack pointer to its new correct position. */ + "ADD #12, R0 \n"\ + + /* All the rest of the registers are saved directly to the user stack. */ + "SETPSW U \n"\ + + /* Save the rest of the general registers (R15 has been saved already). */ + "PUSHM R1-R14 \n"\ + + /* Save the FPSW and accumulators. */ + "MVFC FPSW, R15 \n"\ + "PUSH.L R15 \n"\ + "MVFACGU #0, A1, R15 \n"\ + "PUSH.L R15 \n"\ + "MVFACHI #0, A1, R15 \n"\ + "PUSH.L R15 \n"\ + "MVFACLO #0, A1, R15 \n" /* Low order word. */ \ + "PUSH.L R15 \n"\ + "MVFACGU #0, A0, R15 \n"\ + "PUSH.L R15 \n"\ + "MVFACHI #0, A0, R15 \n"\ + "PUSH.L R15 \n"\ + "MVFACLO #0, A0, R15 \n" /* Low order word. */ \ + "PUSH.L R15 \n"\ + + #if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* Does the task have a DPFPU context that needs saving? If + * ulPortTaskHasDPFPUContext is 0 then no. */ + "MOV.L #_ulPortTaskHasDPFPUContext, R15 \n"\ + "MOV.L [R15], R15 \n"\ + "CMP #0, R15 \n"\ + + /* Save the DPFPU context, if any. */ + "BEQ.B __lab1 \n"\ + "DPUSHM.D DR0-DR15 \n"\ + "DPUSHM.L DPSW-DECNT \n"\ + "__lab1: \n"\ + + /* Save ulPortTaskHasDPFPUContext itself. */ + "PUSH.L R15 \n"\ + + #elif ( configUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Save the DPFPU context, always. */ + "DPUSHM.D DR0-DR15 \n"\ + "DPUSHM.L DPSW-DECNT \n"\ + + #endif /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + + + /* Save the stack pointer to the TCB. */ + "MOV.L #_pxCurrentTCB, R15 \n"\ + "MOV.L [ R15 ], R15 \n"\ + "MOV.L R0, [ R15 ] \n"\ + + + /* Ensure the interrupt mask is set to the syscall priority while the kernel + * structures are being accessed. */ + "MVTIPL %0 \n"\ + + /* Select the next task to run. */ + "BSR.A _vTaskSwitchContext \n"\ + + /* Reset the interrupt mask as no more data structure access is required. */ + "MVTIPL %1 \n"\ + + + /* Load the stack pointer of the task that is now selected as the Running + * state task from its TCB. */ + "MOV.L #_pxCurrentTCB,R15 \n"\ + "MOV.L [ R15 ], R15 \n"\ + "MOV.L [ R15 ], R0 \n"\ + + + /* Restore the context of the new task. The PSW (Program Status Word) and + * PC will be popped by the RTE instruction. */ + + #if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* Is there a DPFPU context to restore? If the restored + * ulPortTaskHasDPFPUContext is zero then no. */ + "POP R15 \n"\ + "MOV.L #_ulPortTaskHasDPFPUContext, R14 \n"\ + "MOV.L R15, [R14] \n"\ + "CMP #0, R15 \n"\ + + /* Restore the DPFPU context, if any. */ + "BEQ.B __lab2 \n"\ + "DPOPM.L DPSW-DECNT \n"\ + "DPOPM.D DR0-DR15 \n"\ + "__lab2: \n"\ + + #elif ( configUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Restore the DPFPU context, always. */ + "DPOPM.L DPSW-DECNT \n"\ + "DPOPM.D DR0-DR15 \n"\ + + #endif /* if( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + + "POP R15 \n"\ + + /* Accumulator low 32 bits. */ + "MVTACLO R15, A0 \n"\ + "POP R15 \n"\ + + /* Accumulator high 32 bits. */ + "MVTACHI R15, A0 \n"\ + "POP R15 \n"\ + + /* Accumulator guard. */ + "MVTACGU R15, A0 \n"\ + "POP R15 \n"\ + + /* Accumulator low 32 bits. */ + "MVTACLO R15, A1 \n"\ + "POP R15 \n"\ + + /* Accumulator high 32 bits. */ + "MVTACHI R15, A1 \n"\ + "POP R15 \n"\ + + /* Accumulator guard. */ + "MVTACGU R15, A1 \n"\ + "POP R15 \n"\ + "MVTC R15, FPSW \n"\ + "POPM R1-R15 \n"\ + "RTE \n"\ + "NOP \n"\ + "NOP " + portCDT_NO_PARSE( :: ) "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ), "i" ( configKERNEL_INTERRUPT_PRIORITY ) + ); +} +/*-----------------------------------------------------------*/ + +#pragma vector = _VECT( configTICK_VECTOR ) +__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/RX700v3_DPFPU/portmacro.h b/portable/IAR/RX700v3_DPFPU/portmacro.h new file mode 100644 index 000000000..c93998bdb --- /dev/null +++ b/portable/IAR/RX700v3_DPFPU/portmacro.h @@ -0,0 +1,195 @@ +/* + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +#ifndef PORTMACRO_H + #define PORTMACRO_H + +/* Hardware specifics. */ + #include + + #ifdef __cplusplus + extern "C" { + #endif + +/*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the + * given hardware and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + +/* 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). */ + #ifndef configUSE_TASK_DPFPU_SUPPORT + #define configUSE_TASK_DPFPU_SUPPORT 1 + #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 + +/*-----------------------------------------------------------*/ + +/* 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;" + * where portITU_SWINTR is the location of the software interrupt register + * (0x000872E0). Don't rely on the assembler to select a register, so instead + * save and restore clobbered registers manually. */ + #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 \n"\ + portCDT_NO_PARSE( ::: ) "cc"\ + ) + + #define portYIELD_FROM_ISR( x ) if( ( x ) != pdFALSE ) portYIELD() + +/* 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 + +/* 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 configUSE_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 + * configUSE_TASK_DPFPU_SUPPORT is set to 2 then all tasks will have a DPFPU context + * by default. */ + #if( configUSE_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() + +/* 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 + + #ifdef __cplusplus + } + #endif + +#endif /* PORTMACRO_H */ diff --git a/portable/Renesas/RX700v3_DPFPU/port.c b/portable/Renesas/RX700v3_DPFPU/port.c new file mode 100644 index 000000000..5010eaad4 --- /dev/null +++ b/portable/Renesas/RX700v3_DPFPU/port.c @@ -0,0 +1,588 @@ +/* + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/*----------------------------------------------------------- +* Implementation of functions defined in portable.h for the RXv3 DPFPU port. +*----------------------------------------------------------*/ + +/* Scheduler includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Library includes. */ +#include "string.h" + +/* Hardware specifics. */ +#if ( configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H == 1 ) + + #include "platform.h" + +#else /* configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H */ + + #include "iodefine.h" + +#endif /* configINCLUDE_PLATFORM_H_INSTEAD_OF_IODEFINE_H */ + +/*-----------------------------------------------------------*/ + +/* 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 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 ); + +/* + * Software interrupt handler. Performs the actual context switch (saving and + * restoring of registers). Written in asm code as direct register access is + * required. + */ +static void prvYieldHandler( void ); + +/* + * The entry point for the software interrupt handler. This is the function + * that calls the inline asm function prvYieldHandler(). It is installed in + * the vector table, but the code that installs it is in prvYieldHandler rather + * than using a #pragma. + */ +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 ( configUSE_TASK_DPFPU_SUPPORT == 1 ) + + StackType_t ulPortTaskHasDPFPUContext = portNO_DPFPU_CONTEXT; + +#endif /* configUSE_TASK_DPFPU_SUPPORT */ + +/* 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. */ + + *pxTopOfStack = 0x00; + 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; + pxTopOfStack--; + } + #else /* ifdef USE_FULL_REGISTER_INITIALISATION */ + { + pxTopOfStack -= 15; + } + #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */ + + *pxTopOfStack = ( StackType_t ) pvParameters; /* R1 */ + pxTopOfStack--; + *pxTopOfStack = portINITIAL_FPSW; + 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. */ + + #if ( configUSE_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 ( configUSE_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. */ + } + #elif ( configUSE_TASK_DPFPU_SUPPORT == 0 ) + { + /* Omit DPFPU support. */ + } + #else /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + { + #error Invalid configUSE_TASK_DPFPU_SUPPORT setting - configUSE_TASK_DPFPU_SUPPORT must be set to 0, 1, 2, or left undefined. + } + #endif /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + + return pxTopOfStack; +} +/*-----------------------------------------------------------*/ + +#if ( configUSE_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 /* configUSE_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(); + } + + /* Just to make sure the function is not optimised away. */ + ( void ) vSoftwareInterruptISR(); + + /* Should not get here. */ + return pdFAIL; +} +/*-----------------------------------------------------------*/ + +void vPortEndScheduler( void ) +{ + /* Not implemented in ports where there is nothing to return to. + * Artificially force an assert. */ + configASSERT( pxCurrentTCB == NULL ); + + /* The following line is just to prevent the symbol getting optimised away. */ + ( void ) vTaskSwitchContext(); +} +/*-----------------------------------------------------------*/ + +#pragma inline_asm prvStartFirstTask +static void prvStartFirstTask( void ) +{ +#ifndef __CDT_PARSER__ + + /* 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. */ + SETPSW U + + + /* Obtain the location of the stack associated with which ever task + * pxCurrentTCB is currently pointing to. */ + MOV.L # _pxCurrentTCB, R15 + MOV.L [ R15 ], R15 + MOV.L [ R15 ], R0 + + + /* Restore the registers from the stack of the task pointed to by + * pxCurrentTCB. */ + + #if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* The restored ulPortTaskHasDPFPUContext is to be zero here. + * So, it is never necessary to restore the DPFPU context here. */ + POP R15 + MOV.L # _ulPortTaskHasDPFPUContext, R14 + MOV.L R15, [ R14 ] + + #elif ( configUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Restore the DPFPU context. */ + DPOPM.L DPSW-DECNT + DPOPM.D DR0-DR15 + + #endif /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + + POP R15 + + /* Accumulator low 32 bits. */ + MVTACLO R15, A0 + POP R15 + + /* Accumulator high 32 bits. */ + MVTACHI R15, A0 + POP R15 + + /* Accumulator guard. */ + MVTACGU R15, A0 + POP R15 + + /* Accumulator low 32 bits. */ + MVTACLO R15, A1 + POP R15 + + /* Accumulator high 32 bits. */ + MVTACHI R15, A1 + POP R15 + + /* Accumulator guard. */ + MVTACGU R15, A1 + POP R15 + + /* Floating point status word. */ + MVTC R15, FPSW + + /* R1 to R15 - R0 is not included as it is the SP. */ + POPM R1-R15 + + /* This pops the remaining registers. */ + RTE + NOP + NOP + +#endif /* ifndef __CDT_PARSER__ */ +} +/*-----------------------------------------------------------*/ + +void vSoftwareInterruptISR( void ) +{ + prvYieldHandler(); +} +/*-----------------------------------------------------------*/ + +#pragma inline_asm prvYieldHandler +static void prvYieldHandler( void ) +{ +#ifndef __CDT_PARSER__ + + /* Re-enable interrupts. */ + 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. */ + PUSH.L R15 + + /* Read the user stack pointer. */ + MVFC USP, R15 + + /* Move the address down to the data being moved. */ + SUB # 12, R15 + MVTC R15, USP + + /* Copy the data across, R15, then PC, then PSW. */ + MOV.L [ R0 ], [ R15 ] + MOV.L 4[ R0 ], 4[ R15 ] + MOV.L 8[ R0 ], 8[ R15 ] + + /* Move the interrupt stack pointer to its new correct position. */ + ADD # 12, R0 + + /* All the rest of the registers are saved directly to the user stack. */ + SETPSW U + + /* Save the rest of the general registers (R15 has been saved already). */ + PUSHM R1-R14 + + /* Save the FPSW and accumulators. */ + MVFC FPSW, R15 + PUSH.L R15 + MVFACGU # 0, A1, R15 + PUSH.L R15 + MVFACHI # 0, A1, R15 + PUSH.L R15 + MVFACLO # 0, A1, R15 /* Low order word. */ + PUSH.L R15 + MVFACGU # 0, A0, R15 + PUSH.L R15 + MVFACHI # 0, A0, R15 + PUSH.L R15 + MVFACLO # 0, A0, R15 /* Low order word. */ + PUSH.L R15 + + #if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* Does the task have a DPFPU context that needs saving? If + * ulPortTaskHasDPFPUContext is 0 then no. */ + MOV.L # _ulPortTaskHasDPFPUContext, R15 + MOV.L [ R15 ], R15 + CMP # 0, R15 + + /* Save the DPFPU context, if any. */ + BEQ.B ?+ + DPUSHM.D DR0-DR15 + DPUSHM.L DPSW-DECNT + ?: + + /* Save ulPortTaskHasDPFPUContext itself. */ + PUSH.L R15 + + #elif ( configUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Save the DPFPU context, always. */ + DPUSHM.D DR0-DR15 + DPUSHM.L DPSW-DECNT + + #endif /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + + + /* Save the stack pointer to the TCB. */ + MOV.L # _pxCurrentTCB, R15 + MOV.L [ R15 ], R15 + MOV.L R0, [ R15 ] + + + /* Ensure the interrupt mask is set to the syscall priority while the kernel + * structures are being accessed. */ + MVTIPL # configMAX_SYSCALL_INTERRUPT_PRIORITY + + /* Select the next task to run. */ + BSR.A _vTaskSwitchContext + + /* Reset the interrupt mask as no more data structure access is required. */ + MVTIPL # configKERNEL_INTERRUPT_PRIORITY + + + /* Load the stack pointer of the task that is now selected as the Running + * state task from its TCB. */ + MOV.L # _pxCurrentTCB, R15 + MOV.L [ R15 ], R15 + 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 ( configUSE_TASK_DPFPU_SUPPORT == 1 ) + + /* Is there a DPFPU context to restore? If the restored + * ulPortTaskHasDPFPUContext is zero then no. */ + POP R15 + MOV.L # _ulPortTaskHasDPFPUContext, R14 + MOV.L R15, [ R14 ] + CMP # 0, R15 + + /* Restore the DPFPU context, if any. */ + BEQ.B ?+ + DPOPM.L DPSW-DECNT + DPOPM.D DR0-DR15 + ?: + + #elif ( configUSE_TASK_DPFPU_SUPPORT == 2 ) + + /* Restore the DPFPU context, always. */ + DPOPM.L DPSW-DECNT + DPOPM.D DR0-DR15 + + #endif /* if ( configUSE_TASK_DPFPU_SUPPORT == 1 ) */ + + POP R15 + + /* Accumulator low 32 bits. */ + MVTACLO R15, A0 + POP R15 + + /* Accumulator high 32 bits. */ + MVTACHI R15, A0 + POP R15 + + /* Accumulator guard. */ + MVTACGU R15, A0 + POP R15 + + /* Accumulator low 32 bits. */ + MVTACLO R15, A1 + POP R15 + + /* Accumulator high 32 bits. */ + MVTACHI R15, A1 + POP R15 + + /* Accumulator guard. */ + MVTACGU R15, A1 + POP R15 + MVTC R15, FPSW + POPM R1-R15 + RTE + NOP + NOP + +#endif /* ifndef __CDT_PARSER__ */ +} +/*-----------------------------------------------------------*/ + +#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/RX700v3_DPFPU/port_asm.src b/portable/Renesas/RX700v3_DPFPU/port_asm.src new file mode 100644 index 000000000..f6518528e --- /dev/null +++ b/portable/Renesas/RX700v3_DPFPU/port_asm.src @@ -0,0 +1,41 @@ +;/* +; * FreeRTOS Kernel V10.3.1 +; * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. +; * +; * Permission is hereby granted, free of charge, to any person obtaining a copy of +; * this software and associated documentation files (the "Software"), to deal in +; * the Software without restriction, including without limitation the rights to +; * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +; * the Software, and to permit persons to whom the Software is furnished to do so, +; * subject to the following conditions: +; * +; * The above copyright notice and this permission notice shall be included in all +; * copies or substantial portions of the Software. +; * +; * 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. +; * +; * http://www.FreeRTOS.org +; * http://aws.amazon.com/freertos +; * +; * 1 tab == 4 spaces! +; */ + .GLB _vSoftwareInterruptISR + .GLB _vSoftwareInterruptEntry + + .SECTION P,CODE + +_vSoftwareInterruptEntry: + + BRA _vSoftwareInterruptISR + + .RVECTOR 27, _vSoftwareInterruptEntry + + .END + + + diff --git a/portable/Renesas/RX700v3_DPFPU/portmacro.h b/portable/Renesas/RX700v3_DPFPU/portmacro.h new file mode 100644 index 000000000..b2702bb0c --- /dev/null +++ b/portable/Renesas/RX700v3_DPFPU/portmacro.h @@ -0,0 +1,185 @@ +/* + * FreeRTOS Kernel V10.3.1 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +#ifndef PORTMACRO_H + #define PORTMACRO_H + + #ifdef __cplusplus + extern "C" { + #endif + +/* 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. + *----------------------------------------------------------- + */ + +/* 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). */ + #ifndef configUSE_TASK_DPFPU_SUPPORT + #define configUSE_TASK_DPFPU_SUPPORT 1 + #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 + +/*-----------------------------------------------------------*/ + +/* 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;" + * where portITU_SWINTR is the location of the software interrupt register + * (0x000872E0). Don't rely on the assembler to select a register, so instead + * save and restore clobbered registers manually. */ + #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 + } + + #define portYIELD() vPortYield() + #define portYIELD_FROM_ISR( x ) if( ( x ) != pdFALSE ) portYIELD() + +/* 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 configUSE_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 + * configUSE_TASK_DPFPU_SUPPORT is set to 2 then all tasks will have a DPFPU context + * by default. */ + #if( configUSE_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() + + #ifdef __cplusplus + } + #endif + +#endif /* PORTMACRO_H */