µGFX  2.9
version 2.9
gos_x_threads_cortexm47fp.h
1 /*
2  * This file is subject to the terms of the GFX License. If a copy of
3  * the license was not distributed with this file, you can obtain one at:
4  *
5  * http://ugfx.io/license.html
6  */
7 
8 /**
9  * Thread Switching Functions for the Cortex M4 & M7 with hardware floating point
10  *
11  * Use the EABI calling standard (ARM's AAPCS) - Save r4 - r11 and floating point
12  * The context is saved at the current stack location and a pointer is maintained in the thread structure.
13  */
14 
15 #if GFX_COMPILER == GFX_COMPILER_GCC || GFX_COMPILER == GFX_COMPILER_CYGWIN || GFX_COMPILER == GFX_COMPILER_MINGW32 || GFX_COMPILER == GFX_COMPILER_MINGW64
16  #define GFX_THREADS_DONE
17  #define _gfxThreadsInit()
18 
19  static __attribute__((pcs("aapcs-vfp"),naked)) void _gfxTaskSwitch(thread *oldt, thread *newt) {
20  __asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t"
21  "vpush {s16-s31} \n\t"
22  "str sp, %[oldtcxt] \n\t"
23  "ldr sp, %[newtcxt] \n\t"
24  "vpop {s16-s31} \n\t"
25  "pop {r4, r5, r6, r7, r8, r9, r10, r11, pc} \n\t"
26  : [newtcxt] "=m" (newt->cxt)
27  : [oldtcxt] "m" (oldt->cxt)
28  : "memory");
29  }
30 
31  static __attribute__((pcs("aapcs-vfp"),naked)) void _gfxStartThread(thread *oldt, thread *newt) {
32  newt->cxt = (void *)(((unsigned)newt + newt->size) & ~7);
33  __asm__ volatile ( "push {r4, r5, r6, r7, r8, r9, r10, r11, lr} \n\t"
34  "vpush {s16-s31} \n\t"
35  "str sp, %[oldtcxt] \n\t"
36  "ldr sp, %[newtcxt] \n\t"
37  : [newtcxt] "=m" (newt->cxt)
38  : [oldtcxt] "m" (oldt->cxt)
39  : "memory");
40 
41  // Run the users function
42  gfxThreadExit(_gfxCurrentThread->fn(_gfxCurrentThread->param));
43  }
44 
45 #elif GFX_COMPILER == GFX_COMPILER_KEIL || GFX_COMPILER == GFX_COMPILER_ARMCC
46  #define GFX_THREADS_DONE
47  #define _gfxThreadsInit()
48 
49  static __asm void _gfxTaskSwitch(thread *oldt, thread *newt) {
50  PRESERVE8
51 
52  // Save the old context
53  push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
54  vpush {s16-s31}
55  str sp, [r0,#__cpp(offsetof(thread,cxt))] // oldt->cxt
56 
57  // Load the new context
58  ldr sp, [r1,#__cpp(offsetof(thread,cxt))] // newt->cxt
59  vpop {s16-s31}
60  pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}
61  }
62 
63  static __asm void _gfxStartThread(thread *oldt, thread *newt) {
64  PRESERVE8
65 
66  // Calculate where to generate the new context
67  // newt->cxt = (void *)(((unsigned)newt + newt->size) & ~7);
68  ldr r2,[r1,#__cpp(offsetof(thread,size))]
69  add r2,r2,r1
70  and r2, r2, #0xFFFFFFF8
71  str r2,[r1,#__cpp(offsetof(thread,cxt))]
72 
73  // Save the old context
74  push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
75  vpush {s16-s31}
76  str sp, [r0,#__cpp(offsetof(thread,cxt))] // oldt->cxt
77 
78  // Load the new (imcomplete) context
79  ldr sp, [r1,#__cpp(offsetof(thread,cxt))] // newt->cxt
80 
81  // Run the users function - we save some code because gfxThreadExit() never returns
82  // gfxThreadExit(_gfxCurrentThread->fn(_gfxCurrentThread->param));
83  ldr r2,=__cpp(&_gfxCurrentThread)
84  ldr r2,[r2,#0]
85  ldr r0,[r2,#__cpp(offsetof(thread,param))]
86  ldr r1,[r2,#__cpp(offsetof(thread,fn))]
87  blx r1
88  mov r4,r0
89  bl __cpp(gfxThreadExit)
90 
91  ALIGN
92  }
93 
94 #else
95  #if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
96  #warning "GOS Threads: You have specified a specific CPU but your compiler is not supported. Defaulting to CLIB switching"
97  #elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
98  COMPILER_WARNING("GOS Threads: You have specified a specific CPU but your compiler is not supported. Defaulting to CLIB switching")
99  #endif
100 #endif