2016-12-06 02:16:19 +00:00
/*
* This file is subject to the terms of the GFX License . If a copy of
* the license was not distributed with this file , you can obtain one at :
*
* http : //ugfx.org/license.html
*/
/**
* Thread Switching Functions for the Cortex M4 & M7 with hardware floating point
*
* Use the EABI calling standard ( ARM ' s AAPCS ) - Save r4 - r11 and floating point
* The context is saved at the current stack location and a pointer is maintained in the thread structure .
*/
# if !CORTEX_USE_FPU
# warning "GOS Threads: You have specified GFX_CPU=GFX_CPU_CORTX_M?_FP with hardware floating point support but CORTEX_USE_FPU is FALSE. Try using GFX_CPU_GFX_CPU_CORTEX_M? instead"
# endif
# if GFX_COMPILER == GFX_COMPILER_GCC || GFX_COMPILER == GFX_COMPILER_CYGWIN || GFX_COMPILER == GFX_COMPILER_MINGW32 || GFX_COMPILER == GFX_COMPILER_MINGW64
# define GFX_THREADS_DONE
# define _gfxThreadsInit()
static __attribute__ ( ( pcs ( " aapcs-vfp " ) , naked ) ) void _gfxTaskSwitch ( thread * oldt , thread * newt ) {
__asm__ volatile ( " push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n \t "
" vpush {s16-s31} \n \t "
" str sp, %[oldtcxt] \n \t "
" ldr sp, %[newtcxt] \n \t "
" vpop {s16-s31} \n \t "
" pop {r4, r5, r6, r7, r8, r9, r10, r11, pc} \n \t "
: [ newtcxt ] " =m " ( newt - > cxt )
: [ oldtcxt ] " m " ( oldt - > cxt )
: " memory " ) ;
}
static __attribute__ ( ( pcs ( " aapcs-vfp " ) , naked ) ) void _gfxStartThread ( thread * oldt , thread * newt ) {
newt - > cxt = ( char * ) newt + newt - > size ;
__asm__ volatile ( " push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n \t "
" vpush {s16-s31} \n \t "
" str sp, %[oldtcxt] \n \t "
" ldr sp, %[newtcxt] \n \t "
: [ newtcxt ] " =m " ( newt - > cxt )
: [ oldtcxt ] " m " ( oldt - > cxt )
: " memory " ) ;
// Run the users function
2016-12-08 00:12:23 +00:00
gfxThreadExit ( _gfxCurrentThread - > fn ( _gfxCurrentThread - > param ) ) ;
2016-12-06 02:16:19 +00:00
}
# elif GFX_COMPILER == GFX_COMPILER_KEIL || GFX_COMPILER == GFX_COMPILER_ARMCC
2016-12-06 03:47:33 +00:00
static __asm void _gfxTaskSwitch ( thread * oldt , thread * newt ) {
// Save the old context
push { r4 , r5 , r6 , r7 , r8 , r9 , r10 , r11 , lr }
2016-12-06 02:16:19 +00:00
vpush { s16 - s31 }
2016-12-06 03:47:33 +00:00
str sp , [ r0 , # __cpp ( offsetof ( thread , cxt ) ) ] // oldt->cxt
// Load the new context
ldr sp , [ r1 , # __cpp ( offsetof ( thread , cxt ) ) ] // newt->cxt
2016-12-06 02:16:19 +00:00
vpop { s16 - s31 }
pop { r4 , r5 , r6 , r7 , r8 , r9 , r10 , r11 , pc }
2016-12-06 03:47:33 +00:00
}
2016-12-06 02:16:19 +00:00
2016-12-06 03:47:33 +00:00
static __asm void _gfxStartThread ( thread * oldt , thread * newt ) {
// Calculate where to generate the new context
// newt->cxt = (char *)newt + newt->size;
ldr r2 , [ r1 , # __cpp ( offsetof ( thread , size ) ) ]
add r2 , r2 , r1
str r2 , [ r1 , # __cpp ( offsetof ( thread , cxt ) ) ]
// Save the old context
push { r4 , r5 , r6 , r7 , r8 , r9 , r10 , r11 , lr }
2016-12-06 02:16:19 +00:00
vpush { s16 - s31 }
2016-12-06 03:47:33 +00:00
str sp , [ r0 , # __cpp ( offsetof ( thread , cxt ) ) ] // oldt->cxt
// Load the new (imcomplete) context
ldr sp , [ r1 , # __cpp ( offsetof ( thread , cxt ) ) ] // newt->cxt
// Run the users function - we save some code because gfxThreadExit() never returns
2016-12-08 00:12:23 +00:00
// gfxThreadExit(_gfxCurrentThread->fn(_gfxCurrentThread->param));
2016-12-06 03:47:33 +00:00
LDR r2 , __cpp ( & _gfxCurrentThread )
LDR r2 , [ r2 , # 0 ]
LDR r0 , [ r2 , # __cpp ( offsetof ( thread , param ) ) ]
LDR r1 , [ r2 , # __cpp ( offsetof ( thread , fn ) ) ]
BLX r1
MOV r4 , r0
BL gfxThreadExit
2016-12-06 02:16:19 +00:00
}
# else
# warning "GOS: Threads: You have specified a specific CPU but your compiler is not supported. Defaulting to CLIB switching"
# endif