µGFX  2.9
version 2.9
gos_x_threads_cortexm01.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 M0 & M1
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 #if defined(CORTEX_USE_FPU) && CORTEX_USE_FPU
16  #if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
17  #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"
18  #elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
19  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")
20  #endif
21 #endif
22 
23 #if GFX_COMPILER == GFX_COMPILER_GCC || GFX_COMPILER == GFX_COMPILER_CYGWIN || GFX_COMPILER == GFX_COMPILER_MINGW32 || GFX_COMPILER == GFX_COMPILER_MINGW64
24  #define GFX_THREADS_DONE
25  #define _gfxThreadsInit()
26 
27  static __attribute__((pcs("aapcs"),naked)) void _gfxTaskSwitch(thread *oldt, thread *newt) {
28  __asm__ volatile ( "push {r4, r5, r6, r7, lr} \n\t"
29  "mov r4, r8 \n\t"
30  "mov r5, r9 \n\t"
31  "mov r6, r10 \n\t"
32  "mov r7, r11 \n\t"
33  "push {r4, r5, r6, r7} \n\t"
34  "mov r4, sp \n\t"
35  "str r4, %[oldtcxt] \n\t"
36  "ldr r4, %[newtcxt] \n\t"
37  "mov sp, r4 \n\t"
38  "pop {r4, r5, r6, r7} \n\t"
39  "mov r8, r4 \n\t"
40  "mov r9, r5 \n\t"
41  "mov r10, r6 \n\t"
42  "mov r11, r7 \n\t"
43  "pop {r4, r5, r6, r7, pc} \n\t"
44  : [newtcxt] "=m" (newt->cxt)
45  : [oldtcxt] "m" (oldt->cxt)
46  : "memory");
47  }
48 
49  static __attribute__((pcs("aapcs"),naked)) void _gfxStartThread(thread *oldt, thread *newt) {
50  newt->cxt = (void *)(((unsigned)newt + newt->size) & ~7);
51  __asm__ volatile ( "push {r4, r5, r6, r7, lr} \n\t"
52  "mov r4, r8 \n\t"
53  "mov r5, r9 \n\t"
54  "mov r6, r10 \n\t"
55  "mov r7, r11 \n\t"
56  "push {r4, r5, r6, r7} \n\t"
57  "mov r4, sp \n\t"
58  "str r4, %[oldtcxt] \n\t"
59  "ldr r4, %[newtcxt] \n\t"
60  "mov sp, r4 \n\t"
61  : [newtcxt] "=m" (newt->cxt)
62  : [oldtcxt] "m" (oldt->cxt)
63  : "memory");
64 
65  // Run the users function
66  gfxThreadExit(_gfxCurrentThread->fn(_gfxCurrentThread->param));
67  }
68 
69 #elif GFX_COMPILER == GFX_COMPILER_KEIL || GFX_COMPILER == GFX_COMPILER_ARMCC
70  #define GFX_THREADS_DONE
71  #define _gfxThreadsInit()
72 
73  static __asm void _gfxTaskSwitch(thread *oldt, thread *newt) {
74  PRESERVE8
75 
76  // Save the old context
77  push {r4, r5, r6, r7, lr}
78  mov r4, r8
79  mov r5, r9
80  mov r6, r10
81  mov r7, r11
82  push {r4, r5, r6, r7}
83  mov r4, sp
84  str r4, [r0,#__cpp(offsetof(thread,cxt))] // oldt->cxt
85 
86  // Load the new context
87  ldr r4, [r1,#__cpp(offsetof(thread,cxt))] // newt->cxt
88  mov sp, r4
89  pop {r4, r5, r6, r7}
90  mov r8, r4
91  mov r9, r5
92  mov r10, r6
93  mov r11, r7
94  pop {r4, r5, r6, r7, pc}
95  }
96 
97  static __asm void _gfxStartThread(thread *oldt, thread *newt) {
98  PRESERVE8
99 
100  // Calculate where to generate the new context
101  // newt->cxt = (void *)(((unsigned)newt + newt->size) & ~7);
102  ldr r2,[r1,#__cpp(offsetof(thread,size))]
103  add r2,r2,r1
104  and r2, r2, #0xFFFFFFF8
105  str r2,[r1,#__cpp(offsetof(thread,cxt))]
106 
107  // Save the old context
108  push {r4, r5, r6, r7, lr}
109  mov r4, r8
110  mov r5, r9
111  mov r6, r10
112  mov r7, r11
113  push {r4, r5, r6, r7}
114  mov r4, sp
115  str r4, [r0,#__cpp(offsetof(thread,cxt))] // oldt->cxt
116 
117  // Load the new (imcomplete) context
118  ldr r4, [r1,#__cpp(offsetof(thread,cxt))] // newt->cxt
119  mov sp, r4
120 
121  // Run the users function - we save some code because gfxThreadExit() never returns
122  // gfxThreadExit(_gfxCurrentThread->fn(_gfxCurrentThread->param));
123  ldr r2,=__cpp(&_gfxCurrentThread)
124  ldr r2,[r2,#0]
125  ldr r0,[r2,#__cpp(offsetof(thread,param))]
126  ldr r1,[r2,#__cpp(offsetof(thread,fn))]
127  blx r1
128  mov r4,r0
129  bl __cpp(gfxThreadExit)
130 
131  ALIGN
132  }
133 
134 #else
135  #if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
136  #warning "GOS Threads: You have specified a specific CPU but your compiler is not supported. Defaulting to CLIB switching"
137  #elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
138  COMPILER_WARNING("GOS Threads: You have specified a specific CPU but your compiler is not supported. Defaulting to CLIB switching")
139  #endif
140 #endif