git subrepo clone https://github.com/libretro/libretro-common.git deps/libretro-common
[pcsx_rearmed.git] / deps / libretro-common / libco / armeabi.c
1 /*
2   libco.armeabi (2013-04-05)
3   author: Themaister
4   license: public domain
5 */
6
7 #define LIBCO_C
8 #include <libco.h>
9 #include <assert.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdint.h>
13
14 #ifndef __APPLE__
15 #include <malloc.h>
16 #endif
17
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21
22 static thread_local uint32_t co_active_buffer[64];
23 static thread_local cothread_t co_active_handle;
24
25 __asm__ (
26 #if defined(__thumb2__)
27       ".align 2\n"
28       ".globl co_switch_arm\n"
29       ".globl _co_switch_arm\n"
30       ".thumb\n"
31       ".thumb_func\n"
32       ".type   co_switch_arm, %function\n"
33       ".type   _co_switch_arm, %function\n"
34       "co_switch_arm:\n"
35       "_co_switch_arm:\n"
36       " mov r3, sp\n"
37       " stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
38       " stmia r1!, {r3, lr}\n"
39       " ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11}\n"
40       " ldmfd r0!, { r3 }\n"
41       " mov sp, r3\n"
42       " ldmfd r0!, { r3 }\n"
43       " mov pc, r3\n"
44 #else
45       ".arm\n"
46       ".align 4\n"
47       ".globl co_switch_arm\n"
48       ".globl _co_switch_arm\n"
49       "co_switch_arm:\n"
50       "_co_switch_arm:\n"
51       "  stmia r1!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, lr}\n"
52       "  ldmia r0!, {r4, r5, r6, r7, r8, r9, r10, r11, sp, pc}\n"
53 #endif
54     );
55
56 /* ASM */
57 void co_switch_arm(cothread_t handle, cothread_t current);
58
59 cothread_t co_create(unsigned int size, void (*entrypoint)(void))
60 {
61    uint32_t *ptr     = NULL;
62    cothread_t handle = 0;
63    size              = (size + 1023) & ~1023;
64 #if defined(__APPLE__) || HAVE_POSIX_MEMALIGN >= 1
65    if (posix_memalign(&handle, 1024, size + 256) < 0)
66       return 0;
67 #else
68    handle = memalign(1024, size + 256);
69 #endif
70
71    if (!handle)
72       return handle;
73
74    ptr    = (uint32_t*)handle;
75    /* Non-volatiles.  */
76    ptr[0] = 0; /* r4  */
77    ptr[1] = 0; /* r5  */
78    ptr[2] = 0; /* r6  */
79    ptr[3] = 0; /* r7  */
80    ptr[4] = 0; /* r8  */
81    ptr[5] = 0; /* r9  */
82    ptr[6] = 0; /* r10 */
83    ptr[7] = 0; /* r11 */
84    /* Align stack to 64-bit */
85    ptr[8] = (uintptr_t)ptr + size + 256 - 8; /* r13, stack pointer */
86    ptr[9] = (uintptr_t)entrypoint; /* r15, PC (link register r14 gets saved here). */
87    return handle;
88 }
89
90 cothread_t co_active(void)
91 {
92    if (!co_active_handle)
93       co_active_handle = co_active_buffer;
94    return co_active_handle;
95 }
96
97 void co_delete(cothread_t handle)
98 {
99    free(handle);
100 }
101
102 void co_switch(cothread_t handle)
103 {
104    cothread_t co_previous_handle = co_active();
105    co_switch_arm(co_active_handle = handle, co_previous_handle);
106 }
107
108 #ifdef __cplusplus
109 }
110 #endif