1/* Assembly functions for libgcc2.
2   Copyright (C) 2001 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 2, or (at your option) any later
10version.
11
12In addition to the permissions in the GNU General Public License, the
13Free Software Foundation gives you unlimited permission to link the
14compiled version of this file into combinations with other programs,
15and to distribute those combinations without any restriction coming
16from the use of this file.  (The General Public License restrictions
17do apply in other respects; for example, they cover modification of
18the file, and distribution when not linked into a combine
19executable.)
20
21GCC is distributed in the hope that it will be useful, but WITHOUT ANY
22WARRANTY; without even the implied warranty of MERCHANTABILITY or
23FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24for more details.
25
26You should have received a copy of the GNU General Public License
27along with GCC; see the file COPYING.  If not, write to the Free
28Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2902110-1301, USA.  */
30
31#include "xtensa-config.h"
32
33/* __xtensa_libgcc_window_spill: This function flushes out all but the
34   current register window.  This is used to set up the stack so that
35   arbitrary frames can be accessed.  */
36
37	.align	4
38	.global	__xtensa_libgcc_window_spill
39	.type	__xtensa_libgcc_window_spill,@function
40__xtensa_libgcc_window_spill:
41	entry	sp, 32
42	movi	a2, 0
43	syscall
44	retw
45	.size	__xtensa_libgcc_window_spill,.-__xtensa_libgcc_window_spill
46
47
48/* __xtensa_nonlocal_goto: This code does all the hard work of a
49   nonlocal goto on Xtensa.  It is here in the library to avoid the
50   code size bloat of generating it in-line.  There are two
51   arguments:
52
53	a2 = frame pointer for the procedure containing the label
54	a3 = goto handler address
55
56  This function never returns to its caller but instead goes directly
57  to the address of the specified goto handler.  */
58
59	.align	4
60	.global	__xtensa_nonlocal_goto
61	.type	__xtensa_nonlocal_goto,@function
62__xtensa_nonlocal_goto:
63	entry	sp, 32
64
65	/* flush registers */
66	mov	a5, a2
67	movi	a2, 0
68	syscall
69	mov	a2, a5
70
71	/* Because the save area for a0-a3 is stored one frame below
72	   the one identified by a2, the only way to restore those
73	   registers is to unwind the stack.  If alloca() were never
74	   called, we could just unwind until finding the sp value
75	   matching a2.  However, a2 is a frame pointer, not a stack
76	   pointer, and may not be encountered during the unwinding.
77	   The solution is to unwind until going _past_ the value
78	   given by a2.  This involves keeping three stack pointer
79	   values during the unwinding:
80
81		next = sp of frame N-1
82		cur = sp of frame N
83		prev = sp of frame N+1
84
85	   When next > a2, the desired save area is stored relative
86	   to prev.  At this point, cur will be the same as a2
87	   except in the alloca() case.
88
89	   Besides finding the values to be restored to a0-a3, we also
90	   need to find the current window size for the target
91	   function.  This can be extracted from the high bits of the
92	   return address, initially in a0.  As the unwinding
93	   proceeds, the window size is taken from the value of a0
94	   saved _two_ frames below the current frame.  */
95
96	addi	a5, sp, -16		# a5 = prev - save area
97	l32i	a6, a5, 4
98	addi	a6, a6, -16		# a6 = cur - save area
99	mov	a8, a0			# a8 = return address (for window size)
100	j	.Lfirstframe
101
102.Lnextframe:
103	l32i	a8, a5, 0		# next return address (for window size)
104	mov	a5, a6			# advance prev
105	addi	a6, a7, -16		# advance cur
106.Lfirstframe:
107	l32i	a7, a6, 4		# a7 = next
108	bge	a2, a7, .Lnextframe
109
110	/* At this point, prev (a5) points to the save area with the saved
111	   values of a0-a3.  Copy those values into the save area at the
112	   current sp so they will be reloaded when the return from this
113	   function underflows.  We don't have to worry about exceptions
114	   while updating the current save area, because the windows have
115	   already been flushed.  */
116
117	addi	a4, sp, -16		# a4 = save area of this function
118	l32i	a6, a5, 0
119	l32i	a7, a5, 4
120	s32i	a6, a4, 0
121	s32i	a7, a4, 4
122	l32i	a6, a5, 8
123	l32i	a7, a5, 12
124	s32i	a6, a4, 8
125	s32i	a7, a4, 12
126
127	/* Set return address to goto handler.  Use the window size bits
128	   from the return address two frames below the target.  */
129	extui	a8, a8, 30, 2		# get window size from return addr.
130	slli	a3, a3, 2		# get goto handler addr. << 2
131	ssai	2
132	src	a0, a8, a3		# combine them with a funnel shift
133
134	retw
135	.size	__xtensa_nonlocal_goto,.-__xtensa_nonlocal_goto
136
137
138/* __xtensa_sync_caches: This function is called after writing a trampoline
139   on the stack to force all the data writes to memory and invalidate the
140   instruction cache. a2 is the address of the new trampoline.
141
142   After the trampoline data is written out, it must be flushed out of
143   the data cache into memory.  We use DHWB in case we have a writeback
144   cache.  At least one DHWB instruction is needed for each data cache
145   line which may be touched by the trampoline.  An ISYNC instruction
146   must follow the DHWBs.
147
148   We have to flush the i-cache to make sure that the new values get used.
149   At least one IHI instruction is needed for each i-cache line which may
150   be touched by the trampoline.  An ISYNC instruction is also needed to
151   make sure that the modified instructions are loaded into the instruction
152   fetch buffer.  */
153
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	entry 	sp, 32
162#if XCHAL_DCACHE_SIZE > 0
163	# Flush the trampoline from the data cache
164	extui	a4, a2, 0, XCHAL_DCACHE_LINEWIDTH
165	addi	a4, a4, TRAMPOLINE_SIZE
166	addi	a4, a4, (1 << XCHAL_DCACHE_LINEWIDTH) - 1
167	srli	a4, a4, XCHAL_DCACHE_LINEWIDTH
168	mov	a3, a2
169.Ldcache_loop:
170	dhwb	a3, 0
171	addi	a3, a3, (1 << XCHAL_DCACHE_LINEWIDTH)
172	addi	a4, a4, -1
173	bnez	a4, .Ldcache_loop
174	isync
175#endif
176#if XCHAL_ICACHE_SIZE > 0
177	# Invalidate the corresponding lines in the instruction cache
178	extui	a4, a2, 0, XCHAL_ICACHE_LINEWIDTH
179	addi	a4, a4, TRAMPOLINE_SIZE
180	addi	a4, a4, (1 << XCHAL_ICACHE_LINEWIDTH) - 1
181	srli	a4, a4, XCHAL_ICACHE_LINEWIDTH
182.Licache_loop:
183	ihi	a2, 0
184	addi	a2, a2, (1 << XCHAL_ICACHE_LINEWIDTH)
185	addi	a4, a4, -1
186	bnez	a4, .Licache_loop
187	isync
188#endif
189	retw
190	.size	__xtensa_sync_caches,.-__xtensa_sync_caches
191