1 | /* |
2 | * This file is part of the MicroPython project, http://micropython.org/ |
3 | * |
4 | * The MIT License (MIT) |
5 | * |
6 | * Copyright (c) 2013-2017 Damien P. George |
7 | * |
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
9 | * of this software and associated documentation files (the "Software"), to deal |
10 | * in the Software without restriction, including without limitation the rights |
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
12 | * copies of the Software, and to permit persons to whom the Software is |
13 | * furnished to do so, subject to the following conditions: |
14 | * |
15 | * The above copyright notice and this permission notice shall be included in |
16 | * all copies or substantial portions of the Software. |
17 | * |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
24 | * THE SOFTWARE. |
25 | */ |
26 | |
27 | #include "py/mpstate.h" |
28 | |
29 | #if MICROPY_NLR_THUMB |
30 | |
31 | #undef nlr_push |
32 | |
33 | // We only need the functions here if we are on arm/thumb, and we are not |
34 | // using setjmp/longjmp. |
35 | // |
36 | // For reference, arm/thumb callee save regs are: |
37 | // r4-r11, r13=sp |
38 | |
39 | __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { |
40 | |
41 | __asm volatile ( |
42 | "str r4, [r0, #12] \n" // store r4 into nlr_buf |
43 | "str r5, [r0, #16] \n" // store r5 into nlr_buf |
44 | "str r6, [r0, #20] \n" // store r6 into nlr_buf |
45 | "str r7, [r0, #24] \n" // store r7 into nlr_buf |
46 | |
47 | #if !defined(__thumb2__) |
48 | "mov r1, r8 \n" |
49 | "str r1, [r0, #28] \n" // store r8 into nlr_buf |
50 | "mov r1, r9 \n" |
51 | "str r1, [r0, #32] \n" // store r9 into nlr_buf |
52 | "mov r1, r10 \n" |
53 | "str r1, [r0, #36] \n" // store r10 into nlr_buf |
54 | "mov r1, r11 \n" |
55 | "str r1, [r0, #40] \n" // store r11 into nlr_buf |
56 | "mov r1, r13 \n" |
57 | "str r1, [r0, #44] \n" // store r13=sp into nlr_buf |
58 | "mov r1, lr \n" |
59 | "str r1, [r0, #8] \n" // store lr into nlr_buf |
60 | #else |
61 | "str r8, [r0, #28] \n" // store r8 into nlr_buf |
62 | "str r9, [r0, #32] \n" // store r9 into nlr_buf |
63 | "str r10, [r0, #36] \n" // store r10 into nlr_buf |
64 | "str r11, [r0, #40] \n" // store r11 into nlr_buf |
65 | "str r13, [r0, #44] \n" // store r13=sp into nlr_buf |
66 | #if MICROPY_NLR_NUM_REGS == 16 |
67 | "vstr d8, [r0, #48] \n" // store s16-s17 into nlr_buf |
68 | "vstr d9, [r0, #56] \n" // store s18-s19 into nlr_buf |
69 | "vstr d10, [r0, #64] \n" // store s20-s21 into nlr_buf |
70 | #endif |
71 | "str lr, [r0, #8] \n" // store lr into nlr_buf |
72 | #endif |
73 | |
74 | #if !defined(__thumb2__) |
75 | "ldr r1, nlr_push_tail_var \n" |
76 | "bx r1 \n" // do the rest in C |
77 | ".align 2 \n" |
78 | "nlr_push_tail_var: .word nlr_push_tail \n" |
79 | #else |
80 | #if defined(__APPLE__) || defined(__MACH__) |
81 | "b _nlr_push_tail \n" // do the rest in C |
82 | #else |
83 | "b nlr_push_tail \n" // do the rest in C |
84 | #endif |
85 | #endif |
86 | ); |
87 | |
88 | #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) |
89 | // Older versions of gcc give an error when naked functions don't return a value |
90 | // Additionally exclude Clang as it also defines __GNUC__ but doesn't need this statement |
91 | return 0; |
92 | #endif |
93 | } |
94 | |
95 | NORETURN void nlr_jump(void *val) { |
96 | MP_NLR_JUMP_HEAD(val, top) |
97 | |
98 | __asm volatile ( |
99 | "mov r0, %0 \n" // r0 points to nlr_buf |
100 | "ldr r4, [r0, #12] \n" // load r4 from nlr_buf |
101 | "ldr r5, [r0, #16] \n" // load r5 from nlr_buf |
102 | "ldr r6, [r0, #20] \n" // load r6 from nlr_buf |
103 | "ldr r7, [r0, #24] \n" // load r7 from nlr_buf |
104 | |
105 | #if !defined(__thumb2__) |
106 | "ldr r1, [r0, #28] \n" // load r8 from nlr_buf |
107 | "mov r8, r1 \n" |
108 | "ldr r1, [r0, #32] \n" // load r9 from nlr_buf |
109 | "mov r9, r1 \n" |
110 | "ldr r1, [r0, #36] \n" // load r10 from nlr_buf |
111 | "mov r10, r1 \n" |
112 | "ldr r1, [r0, #40] \n" // load r11 from nlr_buf |
113 | "mov r11, r1 \n" |
114 | "ldr r1, [r0, #44] \n" // load r13=sp from nlr_buf |
115 | "mov r13, r1 \n" |
116 | "ldr r1, [r0, #8] \n" // load lr from nlr_buf |
117 | "mov lr, r1 \n" |
118 | #else |
119 | "ldr r8, [r0, #28] \n" // load r8 from nlr_buf |
120 | "ldr r9, [r0, #32] \n" // load r9 from nlr_buf |
121 | "ldr r10, [r0, #36] \n" // load r10 from nlr_buf |
122 | "ldr r11, [r0, #40] \n" // load r11 from nlr_buf |
123 | "ldr r13, [r0, #44] \n" // load r13=sp from nlr_buf |
124 | #if MICROPY_NLR_NUM_REGS == 16 |
125 | "vldr d8, [r0, #48] \n" // load s16-s17 from nlr_buf |
126 | "vldr d9, [r0, #56] \n" // load s18-s19 from nlr_buf |
127 | "vldr d10, [r0, #64] \n" // load s20-s21 from nlr_buf |
128 | #endif |
129 | "ldr lr, [r0, #8] \n" // load lr from nlr_buf |
130 | #endif |
131 | "movs r0, #1 \n" // return 1, non-local return |
132 | "bx lr \n" // return |
133 | : // output operands |
134 | : "r" (top) // input operands |
135 | : // clobbered registers |
136 | ); |
137 | |
138 | MP_UNREACHABLE |
139 | } |
140 | |
141 | #endif // MICROPY_NLR_THUMB |
142 | |