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	.text
50	.align	2
51	.global	setjmp
52	.type	setjmp, @function
53setjmp:
54#if __NDS32_REDUCED_REGS__
55	smw.bim	$r6, [$r0], $r10, #0b0000
56	addi	$r0, $r0, #32	/* Leave room to keep jum_buf all the same.  */
57	smw.bim	$r31, [$r0], $r31, #0b1111
58#else
59	smw.bim	$r6, [$r0], $r14, #0b0000
60	smw.bim	$r16, [$r0], $r19, #0b1111
61#endif
62
63#if __NDS32_EXT_FPU_SP__ || __NDS32_EXT_FPU_DP__
64
65	/* Extract $fpcfg.freg (b[3:2]), then save into jmp_buf.  */
66	fmfcfg	$r2
67	slli	$r2, $r2, #28
68	srli	$r2, $r2, #30
69	swi.bi	$r2, [$r0], #4
70
71	/* Make sure $r0 is double-word-aligned.  */
72	addi	$r0, $r0, #7
73	bitci	$r0, $r0, #7
74
75	/* Case switch according to $fpcfg.freg  */
76	beqz	$r2, .LCFG0_save	/* Branch if $fpcfg.freg = 0b00.  */
77	xori	$r15, $r2, #0b10
78	beqz	$r15, .LCFG2_save	/* Branch $fpcfg.freg = 0b10.  */
79	srli	$r2, $r2, #0b01
80	beqz	$r2, .LCFG1_save	/* Branch if $fpcfg.freg = 0b01.  */
81	 /* Fall-through if $fpcfg.freg = 0b11.  */
82.LCFG3_save:
83	fsdi.bi $fd31, [$r0], #8
84	fsdi.bi $fd29, [$r0], #8
85	fsdi.bi $fd27, [$r0], #8
86	fsdi.bi $fd25, [$r0], #8
87	fsdi.bi $fd23, [$r0], #8
88	fsdi.bi $fd21, [$r0], #8
89	fsdi.bi $fd19, [$r0], #8
90	fsdi.bi $fd17, [$r0], #8
91.LCFG2_save:
92	fsdi.bi $fd15, [$r0], #8
93	fsdi.bi $fd13, [$r0], #8
94	fsdi.bi $fd11, [$r0], #8
95	fsdi.bi $fd9, [$r0], #8
96.LCFG1_save:
97	fsdi.bi $fd7, [$r0], #8
98	fsdi.bi $fd5, [$r0], #8
99.LCFG0_save:
100	fsdi.bi $fd3, [$r0], #8
101#endif
102
103	/* Set return value to zero.  */
104	movi	$r0, 0
105	ret
106	.size	setjmp, .-setjmp
107
108
109/* void longjmp(jmp_buf env, int val);  */
110	.text
111	.align	2
112	.global	longjmp
113	.type	longjmp, @function
114longjmp:
115#if __NDS32_REDUCED_REGS__
116	lmw.bim	$r6, [$r0], $r10, #0b0000
117	addi    $r0, $r0, #32
118	lmw.bim	$r31, [$r0], $r31, #0b1111
119#else
120	lmw.bim	$r6, [$r0], $r14, #0b0000
121	lmw.bim	$r16, [$r0], $r19, #0b1111
122#endif
123
124#if __NDS32_EXT_FPU_SP__ || __NDS32_EXT_FPU_DP__
125
126	/* Restore value of $fpcfg.freg (b[3:2]).  */
127	lwi.bi	$r2, [$r0], #4
128
129	/* Make sure $r0 is double-word-aligned.  */
130	addi	$r0, $r0, #7
131	bitci	$r0, $r0, #7
132
133	/* Case switch according to $fpcfg.freg  */
134	beqz	$r2, .LCFG0_restore	/* Branch if $fpcfg.freg = 0b00.  */
135	xori	$r15, $r2, #0b10
136	beqz	$r15, .LCFG2_restore	/* Branch $fpcfg.freg = 0b10.  */
137	srli	$r2, $r2, #0b01
138	beqz	$r2, .LCFG1_restore	/* Branch if $fpcfg.freg = 0b01.  */
139	 /* Fall-through if $fpcfg.freg = 0b11.  */
140.LCFG3_restore:
141	fldi.bi $fd31, [$r0], #8
142	fldi.bi $fd29, [$r0], #8
143	fldi.bi $fd27, [$r0], #8
144	fldi.bi $fd25, [$r0], #8
145	fldi.bi $fd23, [$r0], #8
146	fldi.bi $fd21, [$r0], #8
147	fldi.bi $fd19, [$r0], #8
148	fldi.bi $fd17, [$r0], #8
149.LCFG2_restore:
150	fldi.bi $fd15, [$r0], #8
151	fldi.bi $fd13, [$r0], #8
152	fldi.bi $fd11, [$r0], #8
153	fldi.bi $fd9, [$r0], #8
154.LCFG1_restore:
155	fldi.bi $fd7, [$r0], #8
156	fldi.bi $fd5, [$r0], #8
157.LCFG0_restore:
158	fldi.bi $fd3, [$r0], #8
159#endif
160
161	/* Set val as return value.  If the value val is 0, 1 will be returned
162	   instead.  */
163	movi	$r0, 1
164	cmovn	$r0, $r1, $r1	/* r0=(r1!=0)? r1: r0  */
165	ret
166	.size	longjmp, .-longjmp
167