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