111
|
1 /* Assembly functions for libgcc2.
|
145
|
2 Copyright (C) 2001-2020 Free Software Foundation, Inc.
|
111
|
3 Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
|
|
4
|
|
5 This file is part of GCC.
|
|
6
|
|
7 GCC is free software; you can redistribute it and/or modify it under
|
|
8 the terms of the GNU General Public License as published by the Free
|
|
9 Software Foundation; either version 3, or (at your option) any later
|
|
10 version.
|
|
11
|
|
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
15 for more details.
|
|
16
|
|
17 Under Section 7 of GPL version 3, you are granted additional
|
|
18 permissions described in the GCC Runtime Library Exception, version
|
|
19 3.1, as published by the Free Software Foundation.
|
|
20
|
|
21 You should have received a copy of the GNU General Public License and
|
|
22 a copy of the GCC Runtime Library Exception along with this program;
|
|
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
24 <http://www.gnu.org/licenses/>. */
|
|
25
|
|
26 #include "xtensa-config.h"
|
|
27
|
|
28 /* __xtensa_libgcc_window_spill: This function flushes out all but the
|
|
29 current register window. This is used to set up the stack so that
|
|
30 arbitrary frames can be accessed. */
|
|
31
|
|
32 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
|
|
33 .align 4
|
|
34 .global __xtensa_libgcc_window_spill
|
|
35 .type __xtensa_libgcc_window_spill,@function
|
|
36 __xtensa_libgcc_window_spill:
|
|
37 entry sp, 48
|
|
38 #if XCHAL_NUM_AREGS > 16
|
|
39 call12 1f
|
|
40 retw
|
|
41 .align 4
|
|
42 1:
|
|
43 .rept (XCHAL_NUM_AREGS - 24) / 12
|
|
44 _entry sp, 48
|
|
45 mov a12, a0
|
|
46 .endr
|
|
47 _entry sp, 16
|
|
48 #if XCHAL_NUM_AREGS % 12 == 0
|
|
49 mov a4, a4
|
|
50 #elif XCHAL_NUM_AREGS % 12 == 4
|
|
51 mov a8, a8
|
|
52 #elif XCHAL_NUM_AREGS % 12 == 8
|
|
53 mov a12, a12
|
|
54 #endif
|
|
55 retw
|
|
56 #else
|
|
57 mov a8, a8
|
|
58 retw
|
|
59 #endif
|
|
60 .size __xtensa_libgcc_window_spill, .-__xtensa_libgcc_window_spill
|
|
61 #endif
|
|
62
|
|
63
|
|
64 /* __xtensa_nonlocal_goto: This code does all the hard work of a
|
|
65 nonlocal goto on Xtensa. It is here in the library to avoid the
|
|
66 code size bloat of generating it in-line. There are two
|
|
67 arguments:
|
|
68
|
|
69 a2 = frame pointer for the procedure containing the label
|
|
70 a3 = goto handler address
|
|
71
|
|
72 This function never returns to its caller but instead goes directly
|
|
73 to the address of the specified goto handler. */
|
|
74
|
|
75 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
|
|
76 .align 4
|
|
77 .global __xtensa_nonlocal_goto
|
|
78 .type __xtensa_nonlocal_goto,@function
|
|
79 __xtensa_nonlocal_goto:
|
|
80 entry sp, 32
|
|
81
|
|
82 /* Flush registers. */
|
|
83 call8 __xtensa_libgcc_window_spill
|
|
84
|
|
85 /* Because the save area for a0-a3 is stored one frame below
|
|
86 the one identified by a2, the only way to restore those
|
|
87 registers is to unwind the stack. If alloca() were never
|
|
88 called, we could just unwind until finding the sp value
|
|
89 matching a2. However, a2 is a frame pointer, not a stack
|
|
90 pointer, and may not be encountered during the unwinding.
|
|
91 The solution is to unwind until going _past_ the value
|
|
92 given by a2. This involves keeping three stack pointer
|
|
93 values during the unwinding:
|
|
94
|
|
95 next = sp of frame N-1
|
|
96 cur = sp of frame N
|
|
97 prev = sp of frame N+1
|
|
98
|
|
99 When next > a2, the desired save area is stored relative
|
|
100 to prev. At this point, cur will be the same as a2
|
|
101 except in the alloca() case.
|
|
102
|
|
103 Besides finding the values to be restored to a0-a3, we also
|
|
104 need to find the current window size for the target
|
|
105 function. This can be extracted from the high bits of the
|
|
106 return address, initially in a0. As the unwinding
|
|
107 proceeds, the window size is taken from the value of a0
|
|
108 saved _two_ frames below the current frame. */
|
|
109
|
|
110 addi a5, sp, -16 /* a5 = prev - save area */
|
|
111 l32i a6, a5, 4
|
|
112 addi a6, a6, -16 /* a6 = cur - save area */
|
|
113 mov a8, a0 /* a8 = return address (for window size) */
|
|
114 j .Lfirstframe
|
|
115
|
|
116 .Lnextframe:
|
|
117 l32i a8, a5, 0 /* next return address (for window size) */
|
|
118 mov a5, a6 /* advance prev */
|
|
119 addi a6, a7, -16 /* advance cur */
|
|
120 .Lfirstframe:
|
|
121 l32i a7, a6, 4 /* a7 = next */
|
|
122 bgeu a2, a7, .Lnextframe
|
|
123
|
|
124 /* At this point, prev (a5) points to the save area with the saved
|
|
125 values of a0-a3. Copy those values into the save area at the
|
|
126 current sp so they will be reloaded when the return from this
|
|
127 function underflows. We don't have to worry about exceptions
|
|
128 while updating the current save area, because the windows have
|
|
129 already been flushed. */
|
|
130
|
|
131 addi a4, sp, -16 /* a4 = save area of this function */
|
|
132 l32i a6, a5, 0
|
|
133 l32i a7, a5, 4
|
|
134 s32i a6, a4, 0
|
|
135 s32i a7, a4, 4
|
|
136 l32i a6, a5, 8
|
|
137 l32i a7, a5, 12
|
|
138 s32i a6, a4, 8
|
|
139 s32i a7, a4, 12
|
|
140
|
|
141 /* Set return address to goto handler. Use the window size bits
|
|
142 from the return address two frames below the target. */
|
|
143 extui a8, a8, 30, 2 /* get window size from return addr. */
|
|
144 slli a3, a3, 2 /* get goto handler addr. << 2 */
|
|
145 ssai 2
|
|
146 src a0, a8, a3 /* combine them with a funnel shift */
|
|
147
|
|
148 retw
|
|
149 .size __xtensa_nonlocal_goto, .-__xtensa_nonlocal_goto
|
|
150 #endif
|
|
151
|
|
152
|
|
153 /* __xtensa_sync_caches: This function is called after writing a trampoline
|
|
154 on the stack to force all the data writes to memory and invalidate the
|
|
155 instruction cache. a2 is the address of the new trampoline.
|
|
156
|
|
157 After the trampoline data is written out, it must be flushed out of
|
|
158 the data cache into memory. We use DHWB in case we have a writeback
|
|
159 cache. At least one DHWB instruction is needed for each data cache
|
|
160 line which may be touched by the trampoline. An ISYNC instruction
|
|
161 must follow the DHWBs.
|
|
162
|
|
163 We have to flush the i-cache to make sure that the new values get used.
|
|
164 At least one IHI instruction is needed for each i-cache line which may
|
|
165 be touched by the trampoline. An ISYNC instruction is also needed to
|
|
166 make sure that the modified instructions are loaded into the instruction
|
|
167 fetch buffer. */
|
|
168
|
|
169 /* Use the maximum trampoline size. Flushing a bit extra is OK. */
|
|
170 #define TRAMPOLINE_SIZE 60
|
|
171
|
|
172 .text
|
|
173 .align 4
|
|
174 .global __xtensa_sync_caches
|
|
175 .type __xtensa_sync_caches,@function
|
|
176 __xtensa_sync_caches:
|
|
177 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
|
|
178 entry sp, 32
|
|
179 #endif
|
|
180 #if XCHAL_DCACHE_SIZE > 0
|
|
181 /* Flush the trampoline from the data cache. */
|
|
182 extui a4, a2, 0, XCHAL_DCACHE_LINEWIDTH
|
|
183 addi a4, a4, TRAMPOLINE_SIZE
|
|
184 addi a4, a4, (1 << XCHAL_DCACHE_LINEWIDTH) - 1
|
|
185 srli a4, a4, XCHAL_DCACHE_LINEWIDTH
|
|
186 mov a3, a2
|
|
187 .Ldcache_loop:
|
|
188 dhwb a3, 0
|
|
189 addi a3, a3, (1 << XCHAL_DCACHE_LINEWIDTH)
|
|
190 addi a4, a4, -1
|
|
191 bnez a4, .Ldcache_loop
|
|
192 isync
|
|
193 #endif
|
|
194 #if XCHAL_ICACHE_SIZE > 0
|
|
195 /* Invalidate the corresponding lines in the instruction cache. */
|
|
196 extui a4, a2, 0, XCHAL_ICACHE_LINEWIDTH
|
|
197 addi a4, a4, TRAMPOLINE_SIZE
|
|
198 addi a4, a4, (1 << XCHAL_ICACHE_LINEWIDTH) - 1
|
|
199 srli a4, a4, XCHAL_ICACHE_LINEWIDTH
|
|
200 .Licache_loop:
|
|
201 ihi a2, 0
|
|
202 addi a2, a2, (1 << XCHAL_ICACHE_LINEWIDTH)
|
|
203 addi a4, a4, -1
|
|
204 bnez a4, .Licache_loop
|
|
205 #endif
|
|
206 isync
|
|
207 #if XCHAL_HAVE_WINDOWED && !__XTENSA_CALL0_ABI__
|
|
208 retw
|
|
209 #else
|
|
210 ret
|
|
211 #endif
|
|
212 .size __xtensa_sync_caches, .-__xtensa_sync_caches
|