1/* Assembly functions for libgcc2.
2   Copyright (C) 2001-2021 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, 48
38#if XCHAL_NUM_AREGS > 16
39	call12	1f
40	retw
41	.align	4
421:
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
213