1/*
2Copyright (c) 2013 Andes Technology Corporation.
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
8    Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10
11    Redistributions in binary form must reproduce the above copyright
12    notice, this list of conditions and the following disclaimer in the
13    documentation and/or other materials provided with the distribution.
14
15    The name of the company may not be used to endorse or promote
16    products derived from this software without specific prior written
17    permission.
18
19THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22DISCLAIMED.  IN NO EVENT SHALL RED HAT INCORPORATED BE LIABLE FOR ANY
23DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30
31The setjmp/longjmp for nds32.
32The usage of thirty-two 32-bit General Purpose Registers (GPR):
33  $r28 : $fp
34  $r29 : $gp
35  $r30 : $lp
36  $r31 : $sp
37
38  caller-save registers: $r0 ~ $r5, $r16 ~ $r23
39  callee-save registers: $r6 ~ $r10, $r11 ~ $r14
40  reserved for assembler : $r15
41  reserved for other use : $r24, $r25, $r26, $r27
42
43Save all callee-save registers and $fp, $gp, $lp and $sp is enough in theory.
44For debugging issue, the layout of jum_buf in here should be in sync with GDB.
45The $r16 ~ $r19 are used to store D0/D1, keep them for backward-compatible.
46*/
47
48/* int setjmp(jmp_buf env);  */
49#include <picolibc.h>
50
51	.text
52	.align	2
53	.global	setjmp
54	.type	setjmp, @function
55setjmp:
56#if __NDS32_REDUCED_REGS__
57	smw.bim	$r6, [$r0], $r10, #0b0000
58	addi	$r0, $r0, #32	/* Leave room to keep jum_buf all the same.  */
59	smw.bim	$r31, [$r0], $r31, #0b1111
60#else
61	smw.bim	$r6, [$r0], $r14, #0b0000
62	smw.bim	$r16, [$r0], $r19, #0b1111
63#endif
64
65#if __NDS32_EXT_FPU_SP__ || __NDS32_EXT_FPU_DP__
66
67	/* Extract $fpcfg.freg (b[3:2]), then save into jmp_buf.  */
68	fmfcfg	$r2
69	slli	$r2, $r2, #28
70	srli	$r2, $r2, #30
71	swi.bi	$r2, [$r0], #4
72
73	/* Make sure $r0 is double-word-aligned.  */
74	addi	$r0, $r0, #7
75	bitci	$r0, $r0, #7
76
77	/* Case switch according to $fpcfg.freg  */
78	beqz	$r2, .LCFG0_save	/* Branch if $fpcfg.freg = 0b00.  */
79	xori	$r15, $r2, #0b10
80	beqz	$r15, .LCFG2_save	/* Branch $fpcfg.freg = 0b10.  */
81	srli	$r2, $r2, #0b01
82	beqz	$r2, .LCFG1_save	/* Branch if $fpcfg.freg = 0b01.  */
83	 /* Fall-through if $fpcfg.freg = 0b11.  */
84.LCFG3_save:
85	fsdi.bi $fd31, [$r0], #8
86	fsdi.bi $fd29, [$r0], #8
87	fsdi.bi $fd27, [$r0], #8
88	fsdi.bi $fd25, [$r0], #8
89	fsdi.bi $fd23, [$r0], #8
90	fsdi.bi $fd21, [$r0], #8
91	fsdi.bi $fd19, [$r0], #8
92	fsdi.bi $fd17, [$r0], #8
93.LCFG2_save:
94	fsdi.bi $fd15, [$r0], #8
95	fsdi.bi $fd13, [$r0], #8
96	fsdi.bi $fd11, [$r0], #8
97	fsdi.bi $fd9, [$r0], #8
98.LCFG1_save:
99	fsdi.bi $fd7, [$r0], #8
100	fsdi.bi $fd5, [$r0], #8
101.LCFG0_save:
102	fsdi.bi $fd3, [$r0], #8
103#endif
104
105	/* Set return value to zero.  */
106	movi	$r0, 0
107	ret
108	.size	setjmp, .-setjmp
109
110
111/* void longjmp(jmp_buf env, int val);  */
112	.text
113	.align	2
114	.global	longjmp
115	.type	longjmp, @function
116longjmp:
117#if __NDS32_REDUCED_REGS__
118	lmw.bim	$r6, [$r0], $r10, #0b0000
119	addi    $r0, $r0, #32
120	lmw.bim	$r31, [$r0], $r31, #0b1111
121#else
122	lmw.bim	$r6, [$r0], $r14, #0b0000
123	lmw.bim	$r16, [$r0], $r19, #0b1111
124#endif
125
126#if __NDS32_EXT_FPU_SP__ || __NDS32_EXT_FPU_DP__
127
128	/* Restore value of $fpcfg.freg (b[3:2]).  */
129	lwi.bi	$r2, [$r0], #4
130
131	/* Make sure $r0 is double-word-aligned.  */
132	addi	$r0, $r0, #7
133	bitci	$r0, $r0, #7
134
135	/* Case switch according to $fpcfg.freg  */
136	beqz	$r2, .LCFG0_restore	/* Branch if $fpcfg.freg = 0b00.  */
137	xori	$r15, $r2, #0b10
138	beqz	$r15, .LCFG2_restore	/* Branch $fpcfg.freg = 0b10.  */
139	srli	$r2, $r2, #0b01
140	beqz	$r2, .LCFG1_restore	/* Branch if $fpcfg.freg = 0b01.  */
141	 /* Fall-through if $fpcfg.freg = 0b11.  */
142.LCFG3_restore:
143	fldi.bi $fd31, [$r0], #8
144	fldi.bi $fd29, [$r0], #8
145	fldi.bi $fd27, [$r0], #8
146	fldi.bi $fd25, [$r0], #8
147	fldi.bi $fd23, [$r0], #8
148	fldi.bi $fd21, [$r0], #8
149	fldi.bi $fd19, [$r0], #8
150	fldi.bi $fd17, [$r0], #8
151.LCFG2_restore:
152	fldi.bi $fd15, [$r0], #8
153	fldi.bi $fd13, [$r0], #8
154	fldi.bi $fd11, [$r0], #8
155	fldi.bi $fd9, [$r0], #8
156.LCFG1_restore:
157	fldi.bi $fd7, [$r0], #8
158	fldi.bi $fd5, [$r0], #8
159.LCFG0_restore:
160	fldi.bi $fd3, [$r0], #8
161#endif
162
163	/* Set val as return value.  If the value val is 0, 1 will be returned
164	   instead.  */
165	movi	$r0, 1
166	cmovn	$r0, $r1, $r1	/* r0=(r1!=0)? r1: r0  */
167	ret
168	.size	longjmp, .-longjmp
169