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