1/*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright © 2019 Keith Packard
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above
14 *    copyright notice, this list of conditions and the following
15 *    disclaimer in the documentation and/or other materials provided
16 *    with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 *    contributors may be used to endorse or promote products derived
20 *    from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#include <picolibc.h>
37
38#define SPARC_NWIN	8
39
40#define PSR_VER_BIT                     24
41#define PSR_PIL_BIT                      8
42
43#define PSR_VER                         (0xf << PSR_VER_BIT)
44#define PSR_EF                          (1 << 12)
45#define PSR_S                           (1 <<  7)
46#define PSR_PS                          (1 <<  6)
47#define PSR_ET                          (1 <<  5)
48#define PSR_PIL                         (0xf << PSR_PIL_BIT)
49#define PSR_CWP                         0x1f
50
51#define TRAP(func) \
52	rd	%psr, %l0				; \
53	sethi	%hi(_sparc_ ## func ## _isr), %l4 	;\
54	jmp	%l4+%lo(_sparc_ ## func ## _isr) 	;\
55	rd	%tbr, %l6 				;
56
57#define TRAP_IN_TRAP \
58	ta	0x00		; \
59	nop			; \
60	nop			; \
61	nop			;
62
63#define TRAP_HALT(name) \
64	TRAP(name) 	      ; \
65	.weak	_sparc_ ## name ## _isr	      ; \
66	.equ	_sparc_ ## name ## _isr, _sparc_halt_isr ;
67
68	.section	.data.init.enter
69	.globl		__weak_interrupt_vector
70__weak_interrupt_vector:
71	TRAP(reset)
72	TRAP_HALT(instruction_access_exception)
73	TRAP_HALT(illegal_instruction)
74	TRAP_HALT(priveledged_instruction)
75	TRAP_HALT(fp_disabled)
76#ifdef _FLAT
77	TRAP_HALT(window_overflow)
78	TRAP_HALT(window_underflow)
79#else
80	TRAP(window_overflow)
81	TRAP(window_underflow)
82#endif
83	TRAP_HALT(mem_address_not_aligned)
84	TRAP_HALT(fp_exception)
85	TRAP_HALT(data_access_exception)
86	TRAP_HALT(tag_overflow)
87	TRAP_HALT(watchpoint_detected)
88	TRAP_HALT(trap_0c)
89	TRAP_HALT(trap_0d)
90	TRAP_HALT(trap_0e)
91	TRAP_HALT(trap_0f)
92	TRAP_HALT(trap_10)
93
94	. = __weak_interrupt_vector + 0x80 * 16
95
96	TRAP_HALT(syscall)
97	TRAP_HALT(breakpoint)
98	TRAP_HALT(divide_by_zero)
99#ifdef _FLAT
100	TRAP_HALT(window_flush)
101#else
102	TRAP(window_flush)
103#endif
104	TRAP_HALT(clean_windows)
105	.size	__weak_interrupt_vector, . - __weak_interrupt_vector
106	.weak	__interrupt_vector
107	.equ	__interrupt_vector, __weak_interrupt_vector
108
109	.text
110	.align 4
111
112	.global _sparc_reset_isr
113	.type 	_sparc_reset_isr, #function
114_sparc_reset_isr:
115	sethi	%hi(_start), %g4
116	jmp	%g4+%lo(_start)
117	nop
118	.size	_sparc_reset_isr, .-_sparc_reset_isr
119
120	.global	_sparc_halt_isr
121	.type	_sparc_halt_isr, #function
122_sparc_halt_isr:
123	ta	0x00
124	ba	_sparc_halt_isr
125	nop
126	.size	_sparc_halt_isr, .-_sparc_halt_isr
127
128	.global _sparc_window_overflow_isr
129	.type 	_sparc_window_overflow_isr, #function
130_sparc_window_overflow_isr:
131	/* Enter the window to be stored. */
132	save
133	/* Save local register set. */
134	std	%l0, [%sp + 0x00]
135	std	%l2, [%sp + 0x08]
136	std	%l4, [%sp + 0x10]
137	rd	%wim, %l3
138	std	%l6, [%sp + 0x18]
139	/* l2 := WIM << (NWIN-1) */
140	sll	%l3, (SPARC_NWIN-1), %l2
141	/* Save input register set. */
142	std	%i0, [%sp + 0x20]
143	/* l3 := WIM >> 1 */
144	srl	%l3, 1, %l3
145	std	%i2, [%sp + 0x28]
146	/* WIM := (WIM >> 1) ^ (WIM << (NWIN-1)) */
147	wr	%l3, %l2, %wim
148	/* NOTE: 3 instruction before restore (delayed write instruction) */
149	std	%i4, [%sp + 0x30]
150	nop
151	std	%i6, [%sp + 0x38]
152	/* Go back to trap window. */
153	restore
154	/* Re-execute save. */
155	jmp	%l1
156	rett	%l2
157	.size	_sparc_window_overflow_isr, .-_sparc_window_overflow_isr
158
159	.global _sparc_window_underflow_isr
160	.type 	_sparc_window_underflow_isr, #function
161_sparc_window_underflow_isr:
162	rd	%wim, %l3
163	/* l4 := WIM << 1 */
164	sll	%l3, 1, %l4
165	/* l5 := WIM >> (NWIN-1) */
166	srl	%l3, (SPARC_NWIN-1), %l5
167	/* WIM := (WIM << 1) ^ (WIM >> (NWIN-1)) */
168	wr	%l4, %l5, %wim
169	/* WIM is implicitly read so nops are needed. */
170	nop
171	nop
172	nop
173
174	/* Enter the window to restore requires two restore instructions. */
175	restore
176	restore
177	ldd	[%sp + 0x00], %l0
178	ldd	[%sp + 0x08], %l2
179	ldd	[%sp + 0x10], %l4
180	ldd	[%sp + 0x18], %l6
181	ldd	[%sp + 0x20], %i0
182	ldd	[%sp + 0x28], %i2
183	ldd	[%sp + 0x30], %i4
184	ldd	[%sp + 0x38], %i6
185	/* Go back to the trap window. */
186	save
187	save
188	/* Re-execute restore. */
189	jmp	%l1
190	rett	%l2
191	.size	_sparc_window_underflow_isr, .-_sparc_window_underflow_isr
192
193	.global _sparc_window_flush_isr
194	.type 	_sparc_window_flush_isr, #function
195_sparc_window_flush_isr:
196	/*
197	 * push a few registers which are needed later to the stack using
198	 * sp from the window we trapped from (which is fp in this window)
199	 */
200	sub	%fp, 0x10, %fp
201	std	%l0, [%fp + 0x40 + 0x00]
202	st	%l2, [%fp + 0x40 + 0x08]
203	st	%g1, [%fp + 0x40 + 0x0c]
204
205	restore
206	/* In window where we trapped from. This window will not be flushed. */
207
208	/* Set highest processor interrupt level and enable traps. */
209	rd	%psr, %g1
210	or	%g1, PSR_PIL, %g1
211	wr	%g1, PSR_ET, %psr
212	nop
213	nop
214
215	/* Execute "save" NWINDOWS-1 times. */
216	set     SPARC_NWIN-2, %g1
2171:
218	save
219	cmp	%g1, %g0
220	bne	1b
221	sub	%g1, 1, %g1
222
223	/* Execute "restore" NWINDOWS-1 times. */
224	set     SPARC_NWIN-2, %g1
2252:
226	restore
227	cmp	%g1, %g0
228	bne	2b
229	sub	%g1, 1, %g1
230
231	save
232
233	/* pop registers from stack which are used for the trap return */
234	ldd	[%fp + 0x40 + 0x00], %l0
235	ld	[%fp + 0x40 + 0x08], %l2
236	ld	[%fp + 0x40 + 0x0c], %g1
237	add	%fp, 0x10, %fp
238
239	/* Restore %psr as it was on trap entry. */
240	wr	%l0, %psr
241	nop
242	nop
243	nop
244
245	jmp	%l2
246	rett	%l2 + 4
247	.size	_sparc_window_flush_isr, .-_sparc_window_flush_isr
248