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 M0 & M1
*
* Use the EABI calling standard ( ARM ' s AAPCS ) - Save r4 - r11
* The context is saved at the current stack location and a pointer is maintained in the thread structure .
*/
# if CORTEX_USE_FPU
2017-06-30 09:43:51 +00:00
# if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
2018-02-27 07:44:21 +00:00
# warning "GOS Threads: You have specified GFX_CPU=GFX_CPU_CORTX_M? with no hardware floating point support but CORTEX_USE_FPU is GFXON. Try using GFX_CPU_GFX_CPU_CORTEX_M?_FP instead"
2017-06-30 09:43:51 +00:00
# elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
2018-02-27 07:44:21 +00:00
COMPILER_WARNING ( " GOS Threads: You have specified GFX_CPU=GFX_CPU_CORTX_M? with no hardware floating point support but CORTEX_USE_FPU is GFXON. Try using GFX_CPU_GFX_CPU_CORTEX_M?_FP instead " )
2017-06-30 09:43:51 +00:00
# endif
2016-12-06 02:16:19 +00:00
# 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 " ) , naked ) ) void _gfxTaskSwitch ( thread * oldt , thread * newt ) {
__asm__ volatile ( " push {r4, r5, r6, r7, lr} \n \t "
" mov r4, r8 \n \t "
" mov r5, r9 \n \t "
" mov r6, r10 \n \t "
" mov r7, r11 \n \t "
" push {r4, r5, r6, r7} \n \t "
2016-12-30 08:57:09 +00:00
" mov r4, sp \n \t "
" str r4, %[oldtcxt] \n \t "
" ldr r4, %[newtcxt] \n \t "
" mov sp, r4 \n \t "
2016-12-06 02:16:19 +00:00
" pop {r4, r5, r6, r7} \n \t "
" mov r8, r4 \n \t "
" mov r9, r5 \n \t "
" mov r10, r6 \n \t "
" mov r11, r7 \n \t "
" pop {r4, r5, r6, r7, pc} \n \t "
: [ newtcxt ] " =m " ( newt - > cxt )
: [ oldtcxt ] " m " ( oldt - > cxt )
: " memory " ) ;
}
static __attribute__ ( ( pcs ( " aapcs " ) , naked ) ) void _gfxStartThread ( thread * oldt , thread * newt ) {
2016-12-30 08:57:09 +00:00
newt - > cxt = ( void * ) ( ( ( unsigned ) newt + newt - > size ) & ~ 7 ) ;
2016-12-06 02:16:19 +00:00
__asm__ volatile ( " push {r4, r5, r6, r7, lr} \n \t "
" mov r4, r8 \n \t "
" mov r5, r9 \n \t "
" mov r6, r10 \n \t "
" mov r7, r11 \n \t "
" push {r4, r5, r6, r7} \n \t "
2016-12-30 08:57:09 +00:00
" mov r4, sp \n \t "
" str r4, %[oldtcxt] \n \t "
" ldr r4, %[newtcxt] \n \t "
" mov sp, r4 \n \t "
2016-12-06 02:16:19 +00:00
: [ 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-22 22:56:16 +00:00
# define GFX_THREADS_DONE
# define _gfxThreadsInit()
2016-12-06 02:16:19 +00:00
2016-12-06 03:47:33 +00:00
static __asm void _gfxTaskSwitch ( thread * oldt , thread * newt ) {
2016-12-22 22:56:16 +00:00
PRESERVE8
2016-12-06 03:47:33 +00:00
// Save the old context
push { r4 , r5 , r6 , r7 , lr }
2016-12-06 02:16:19 +00:00
mov r4 , r8
mov r5 , r9
mov r6 , r10
mov r7 , r11
push { r4 , r5 , r6 , r7 }
2016-12-30 08:57:09 +00:00
mov r4 , sp
str r4 , [ r0 , # __cpp ( offsetof ( thread , cxt ) ) ] // oldt->cxt
2016-12-06 03:47:33 +00:00
// Load the new context
2016-12-30 08:57:09 +00:00
ldr r4 , [ r1 , # __cpp ( offsetof ( thread , cxt ) ) ] // newt->cxt
mov sp , r4
2016-12-06 02:16:19 +00:00
pop { r4 , r5 , r6 , r7 }
mov r8 , r4
mov r9 , r5
mov r10 , r6
mov r11 , r7
pop { r4 , r5 , r6 , r7 , 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 ) {
2016-12-22 22:56:16 +00:00
PRESERVE8
2016-12-06 03:47:33 +00:00
// Calculate where to generate the new context
2016-12-30 08:57:09 +00:00
// newt->cxt = (void *)(((unsigned)newt + newt->size) & ~7);
2016-12-12 19:02:34 +00:00
ldr r2 , [ r1 , # __cpp ( offsetof ( thread , size ) ) ]
add r2 , r2 , r1
2016-12-30 08:57:09 +00:00
and r2 , r2 , # 0xFFFFFFF8
2016-12-12 19:02:34 +00:00
str r2 , [ r1 , # __cpp ( offsetof ( thread , cxt ) ) ]
2016-12-06 03:47:33 +00:00
// Save the old context
push { r4 , r5 , r6 , r7 , lr }
2016-12-06 02:16:19 +00:00
mov r4 , r8
mov r5 , r9
mov r6 , r10
mov r7 , r11
push { r4 , r5 , r6 , r7 }
2016-12-30 08:57:09 +00:00
mov r4 , sp
str r4 , [ r0 , # __cpp ( offsetof ( thread , cxt ) ) ] // oldt->cxt
2016-12-06 03:47:33 +00:00
// Load the new (imcomplete) context
2016-12-30 08:57:09 +00:00
ldr r4 , [ r1 , # __cpp ( offsetof ( thread , cxt ) ) ] // newt->cxt
mov sp , r4
2016-12-06 03:47:33 +00:00
// 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-22 22:56:16 +00:00
ldr r2 , = __cpp ( & _gfxCurrentThread )
2016-12-12 19:02:34 +00:00
ldr r2 , [ r2 , # 0 ]
ldr r0 , [ r2 , # __cpp ( offsetof ( thread , param ) ) ]
ldr r1 , [ r2 , # __cpp ( offsetof ( thread , fn ) ) ]
blx r1
mov r4 , r0
2016-12-12 19:03:17 +00:00
bl __cpp ( gfxThreadExit )
2016-12-22 22:56:16 +00:00
ALIGN
2016-12-06 02:16:19 +00:00
}
# else
2017-06-30 09:43:51 +00:00
# if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
# warning "GOS Threads: You have specified a specific CPU but your compiler is not supported. Defaulting to CLIB switching"
# elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
COMPILER_WARNING ( " GOS Threads: You have specified a specific CPU but your compiler is not supported. Defaulting to CLIB switching " )
# endif
2016-12-06 02:16:19 +00:00
# endif