1 |
282 |
jeremybenn |
/* Assembly functions for libgcc2.
|
2 |
|
|
Copyright (C) 2001, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
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 |
|
|
. */
|
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 |
|
|
.align 4
|
33 |
|
|
.global __xtensa_libgcc_window_spill
|
34 |
|
|
.type __xtensa_libgcc_window_spill,@function
|
35 |
|
|
__xtensa_libgcc_window_spill:
|
36 |
|
|
entry sp, 32
|
37 |
|
|
movi a2, 0
|
38 |
|
|
syscall
|
39 |
|
|
retw
|
40 |
|
|
.size __xtensa_libgcc_window_spill, .-__xtensa_libgcc_window_spill
|
41 |
|
|
|
42 |
|
|
|
43 |
|
|
/* __xtensa_nonlocal_goto: This code does all the hard work of a
|
44 |
|
|
nonlocal goto on Xtensa. It is here in the library to avoid the
|
45 |
|
|
code size bloat of generating it in-line. There are two
|
46 |
|
|
arguments:
|
47 |
|
|
|
48 |
|
|
a2 = frame pointer for the procedure containing the label
|
49 |
|
|
a3 = goto handler address
|
50 |
|
|
|
51 |
|
|
This function never returns to its caller but instead goes directly
|
52 |
|
|
to the address of the specified goto handler. */
|
53 |
|
|
|
54 |
|
|
.align 4
|
55 |
|
|
.global __xtensa_nonlocal_goto
|
56 |
|
|
.type __xtensa_nonlocal_goto,@function
|
57 |
|
|
__xtensa_nonlocal_goto:
|
58 |
|
|
entry sp, 32
|
59 |
|
|
|
60 |
|
|
/* Flush registers. */
|
61 |
|
|
mov a5, a2
|
62 |
|
|
movi a2, 0
|
63 |
|
|
syscall
|
64 |
|
|
mov a2, a5
|
65 |
|
|
|
66 |
|
|
/* Because the save area for a0-a3 is stored one frame below
|
67 |
|
|
the one identified by a2, the only way to restore those
|
68 |
|
|
registers is to unwind the stack. If alloca() were never
|
69 |
|
|
called, we could just unwind until finding the sp value
|
70 |
|
|
matching a2. However, a2 is a frame pointer, not a stack
|
71 |
|
|
pointer, and may not be encountered during the unwinding.
|
72 |
|
|
The solution is to unwind until going _past_ the value
|
73 |
|
|
given by a2. This involves keeping three stack pointer
|
74 |
|
|
values during the unwinding:
|
75 |
|
|
|
76 |
|
|
next = sp of frame N-1
|
77 |
|
|
cur = sp of frame N
|
78 |
|
|
prev = sp of frame N+1
|
79 |
|
|
|
80 |
|
|
When next > a2, the desired save area is stored relative
|
81 |
|
|
to prev. At this point, cur will be the same as a2
|
82 |
|
|
except in the alloca() case.
|
83 |
|
|
|
84 |
|
|
Besides finding the values to be restored to a0-a3, we also
|
85 |
|
|
need to find the current window size for the target
|
86 |
|
|
function. This can be extracted from the high bits of the
|
87 |
|
|
return address, initially in a0. As the unwinding
|
88 |
|
|
proceeds, the window size is taken from the value of a0
|
89 |
|
|
saved _two_ frames below the current frame. */
|
90 |
|
|
|
91 |
|
|
addi a5, sp, -16 /* a5 = prev - save area */
|
92 |
|
|
l32i a6, a5, 4
|
93 |
|
|
addi a6, a6, -16 /* a6 = cur - save area */
|
94 |
|
|
mov a8, a0 /* a8 = return address (for window size) */
|
95 |
|
|
j .Lfirstframe
|
96 |
|
|
|
97 |
|
|
.Lnextframe:
|
98 |
|
|
l32i a8, a5, 0 /* next return address (for window size) */
|
99 |
|
|
mov a5, a6 /* advance prev */
|
100 |
|
|
addi a6, a7, -16 /* advance cur */
|
101 |
|
|
.Lfirstframe:
|
102 |
|
|
l32i a7, a6, 4 /* a7 = next */
|
103 |
|
|
bgeu a2, a7, .Lnextframe
|
104 |
|
|
|
105 |
|
|
/* At this point, prev (a5) points to the save area with the saved
|
106 |
|
|
values of a0-a3. Copy those values into the save area at the
|
107 |
|
|
current sp so they will be reloaded when the return from this
|
108 |
|
|
function underflows. We don't have to worry about exceptions
|
109 |
|
|
while updating the current save area, because the windows have
|
110 |
|
|
already been flushed. */
|
111 |
|
|
|
112 |
|
|
addi a4, sp, -16 /* a4 = save area of this function */
|
113 |
|
|
l32i a6, a5, 0
|
114 |
|
|
l32i a7, a5, 4
|
115 |
|
|
s32i a6, a4, 0
|
116 |
|
|
s32i a7, a4, 4
|
117 |
|
|
l32i a6, a5, 8
|
118 |
|
|
l32i a7, a5, 12
|
119 |
|
|
s32i a6, a4, 8
|
120 |
|
|
s32i a7, a4, 12
|
121 |
|
|
|
122 |
|
|
/* Set return address to goto handler. Use the window size bits
|
123 |
|
|
from the return address two frames below the target. */
|
124 |
|
|
extui a8, a8, 30, 2 /* get window size from return addr. */
|
125 |
|
|
slli a3, a3, 2 /* get goto handler addr. << 2 */
|
126 |
|
|
ssai 2
|
127 |
|
|
src a0, a8, a3 /* combine them with a funnel shift */
|
128 |
|
|
|
129 |
|
|
retw
|
130 |
|
|
.size __xtensa_nonlocal_goto, .-__xtensa_nonlocal_goto
|
131 |
|
|
|
132 |
|
|
|
133 |
|
|
/* __xtensa_sync_caches: This function is called after writing a trampoline
|
134 |
|
|
on the stack to force all the data writes to memory and invalidate the
|
135 |
|
|
instruction cache. a2 is the address of the new trampoline.
|
136 |
|
|
|
137 |
|
|
After the trampoline data is written out, it must be flushed out of
|
138 |
|
|
the data cache into memory. We use DHWB in case we have a writeback
|
139 |
|
|
cache. At least one DHWB instruction is needed for each data cache
|
140 |
|
|
line which may be touched by the trampoline. An ISYNC instruction
|
141 |
|
|
must follow the DHWBs.
|
142 |
|
|
|
143 |
|
|
We have to flush the i-cache to make sure that the new values get used.
|
144 |
|
|
At least one IHI instruction is needed for each i-cache line which may
|
145 |
|
|
be touched by the trampoline. An ISYNC instruction is also needed to
|
146 |
|
|
make sure that the modified instructions are loaded into the instruction
|
147 |
|
|
fetch buffer. */
|
148 |
|
|
|
149 |
|
|
/* Use the maximum trampoline size. Flushing a bit extra is OK. */
|
150 |
|
|
#define TRAMPOLINE_SIZE 60
|
151 |
|
|
|
152 |
|
|
.text
|
153 |
|
|
.align 4
|
154 |
|
|
.global __xtensa_sync_caches
|
155 |
|
|
.type __xtensa_sync_caches,@function
|
156 |
|
|
__xtensa_sync_caches:
|
157 |
|
|
entry sp, 32
|
158 |
|
|
#if XCHAL_DCACHE_SIZE > 0
|
159 |
|
|
/* Flush the trampoline from the data cache. */
|
160 |
|
|
extui a4, a2, 0, XCHAL_DCACHE_LINEWIDTH
|
161 |
|
|
addi a4, a4, TRAMPOLINE_SIZE
|
162 |
|
|
addi a4, a4, (1 << XCHAL_DCACHE_LINEWIDTH) - 1
|
163 |
|
|
srli a4, a4, XCHAL_DCACHE_LINEWIDTH
|
164 |
|
|
mov a3, a2
|
165 |
|
|
.Ldcache_loop:
|
166 |
|
|
dhwb a3, 0
|
167 |
|
|
addi a3, a3, (1 << XCHAL_DCACHE_LINEWIDTH)
|
168 |
|
|
addi a4, a4, -1
|
169 |
|
|
bnez a4, .Ldcache_loop
|
170 |
|
|
isync
|
171 |
|
|
#endif
|
172 |
|
|
#if XCHAL_ICACHE_SIZE > 0
|
173 |
|
|
/* Invalidate the corresponding lines in the instruction cache. */
|
174 |
|
|
extui a4, a2, 0, XCHAL_ICACHE_LINEWIDTH
|
175 |
|
|
addi a4, a4, TRAMPOLINE_SIZE
|
176 |
|
|
addi a4, a4, (1 << XCHAL_ICACHE_LINEWIDTH) - 1
|
177 |
|
|
srli a4, a4, XCHAL_ICACHE_LINEWIDTH
|
178 |
|
|
.Licache_loop:
|
179 |
|
|
ihi a2, 0
|
180 |
|
|
addi a2, a2, (1 << XCHAL_ICACHE_LINEWIDTH)
|
181 |
|
|
addi a4, a4, -1
|
182 |
|
|
bnez a4, .Licache_loop
|
183 |
|
|
#endif
|
184 |
|
|
isync
|
185 |
|
|
retw
|
186 |
|
|
.size __xtensa_sync_caches, .-__xtensa_sync_caches
|