1/*
2Copyright (c) 1990 The Regents of the University of California.
3All rights reserved.
4
5Redistribution and use in source and binary forms are permitted
6provided that the above copyright notice and this paragraph are
7duplicated in all such forms and that any documentation,
8and/or other materials related to such
9distribution and use acknowledge that the software was developed
10by the University of California, Berkeley.  The name of the
11University may not be used to endorse or promote products derived
12from this software without specific prior written permission.
13THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17/* This is a simple version of setjmp and longjmp for MIPS 32 and 64.
18
19   Ian Lance Taylor, Cygnus Support, 13 May 1993.  */
20
21#ifdef __mips16
22/* This file contains 32 bit assembly code.  */
23	.set nomips16
24#endif
25
26#define GPR_LAYOUT		\
27	GPR_OFFSET ($16, 0);	\
28	GPR_OFFSET ($17, 1);	\
29	GPR_OFFSET ($18, 2);	\
30	GPR_OFFSET ($19, 3);	\
31	GPR_OFFSET ($20, 4);	\
32	GPR_OFFSET ($21, 5);	\
33	GPR_OFFSET ($22, 6);	\
34	GPR_OFFSET ($23, 7);	\
35	GPR_OFFSET ($29, 8);	\
36	GPR_OFFSET ($30, 9);	\
37	GPR_OFFSET ($31, 10)
38
39#define NUM_GPRS_SAVED 11
40
41#ifdef __mips_hard_float
42#if _MIPS_SIM == _ABIN32
43#define FPR_LAYOUT		\
44	FPR_OFFSET ($f20, 0);	\
45	FPR_OFFSET ($f22, 1);	\
46	FPR_OFFSET ($f24, 2);	\
47	FPR_OFFSET ($f26, 3);	\
48	FPR_OFFSET ($f28, 4);	\
49	FPR_OFFSET ($f30, 5);
50#elif _MIPS_SIM == _ABI64
51#define FPR_LAYOUT		\
52	FPR_OFFSET ($f24, 0);	\
53	FPR_OFFSET ($f25, 1);	\
54	FPR_OFFSET ($f26, 2);	\
55	FPR_OFFSET ($f27, 3);	\
56	FPR_OFFSET ($f28, 4);	\
57	FPR_OFFSET ($f29, 5);	\
58	FPR_OFFSET ($f30, 6);	\
59	FPR_OFFSET ($f31, 7);
60#elif __mips_fpr == 0 || __mips_fpr == 64
61
62/* This deals with the o32 FPXX and FP64 cases.  Here we must use
63   SDC1 and LDC1 to access the FPRs.  These instructions require
64   8-byte aligned addresses.
65   Unfortunately, the MIPS jmp_buf only guarantees 4-byte alignment
66   and this cannot be increased without breaking compatibility with
67   pre-existing objects built against newlib.  There are 11 GPRS
68   saved in the jmp_buf so a buffer that happens to be 8-byte aligned
69   ends up leaving the FPR slots 4-byte aligned and an (only) 4-byte
70   aligned buffer leads to the FPR slots being 8-byte aligned!
71
72   To resolve this, we move the location of $31 to the last slot
73   in the jmp_buf when the overall buffer is 8-byte aligned.  $31
74   is simply loaded/stored twice to avoid adding complexity to the
75   GPR_LAYOUT macro above as well as FPR_LAYOUT.
76
77   The location of the last slot is index 22 which is calculated
78   from there being 11 GPRs saved and then 12 FPRs saved so the
79   index of the last FPR is 11+11.
80
81   The base of the jmp_buf is modified in $4 to allow the
82   FPR_OFFSET macros to just use the usual constant slot numbers
83   regardless of whether the realignment happened or not.  */
84
85#define FPR_LAYOUT		\
86	and $8, $4, 4;	 	\
87	beq $8, $0, 1f;		\
88	GPR_OFFSET ($31, 22);	\
89	addiu $4, $4, -4;	\
901:				\
91	FPR_OFFSET ($f20, 0);  	\
92	FPR_OFFSET ($f22, 2);	\
93	FPR_OFFSET ($f24, 4);	\
94	FPR_OFFSET ($f26, 6);	\
95	FPR_OFFSET ($f28, 8);	\
96	FPR_OFFSET ($f30, 10);
97#else /* Assuming _MIPS_SIM == _ABIO32 */
98#define FPR_LAYOUT		\
99	FPR_OFFSET ($f20, 0);	\
100	FPR_OFFSET ($f21, 1);	\
101	FPR_OFFSET ($f22, 2);	\
102	FPR_OFFSET ($f23, 3);	\
103	FPR_OFFSET ($f24, 4);	\
104	FPR_OFFSET ($f25, 5);	\
105	FPR_OFFSET ($f26, 6);	\
106	FPR_OFFSET ($f27, 7);	\
107	FPR_OFFSET ($f28, 8);	\
108	FPR_OFFSET ($f29, 9);	\
109	FPR_OFFSET ($f30, 10);	\
110	FPR_OFFSET ($f31, 11);
111#endif
112#else
113#define FPR_LAYOUT
114#endif
115
116#ifdef __mips64
117#define BYTES_PER_WORD 8
118#define LOAD_GPR ld
119#define LOAD_FPR ldc1
120#define STORE_GPR sd
121#define STORE_FPR sdc1
122#else
123#define LOAD_GPR lw
124#define STORE_GPR sw
125#define BYTES_PER_WORD 4
126#if __mips_fpr == 0 || __mips_fpr == 64
127#define LOAD_FPR ldc1
128#define STORE_FPR sdc1
129#else
130#define LOAD_FPR lwc1
131#define STORE_FPR swc1
132#endif
133#endif
134
135#define GPOFF(INDEX) (INDEX * BYTES_PER_WORD)
136#define FPOFF(INDEX) ((INDEX + NUM_GPRS_SAVED) * BYTES_PER_WORD)
137
138/* int setjmp (jmp_buf);  */
139	.globl	setjmp
140	.ent	setjmp
141setjmp:
142	.frame	$sp,0,$31
143
144#define GPR_OFFSET(REG, INDEX) STORE_GPR REG,GPOFF(INDEX)($4)
145#define FPR_OFFSET(REG, INDEX) STORE_FPR REG,FPOFF(INDEX)($4)
146	GPR_LAYOUT
147	FPR_LAYOUT
148#undef GPR_OFFSET
149#undef FPR_OFFSET
150
151	move	$2,$0
152	j	$31
153
154	.end	setjmp
155
156/* volatile void longjmp (jmp_buf, int);  */
157	.globl	longjmp
158	.ent	longjmp
159longjmp:
160	.frame	$sp,0,$31
161
162#define GPR_OFFSET(REG, INDEX) LOAD_GPR REG,GPOFF(INDEX)($4)
163#define FPR_OFFSET(REG, INDEX) LOAD_FPR REG,FPOFF(INDEX)($4)
164	GPR_LAYOUT
165	FPR_LAYOUT
166#undef GPR_OFFSET
167#undef FPR_OFFSET
168
169	bne	$5,$0,1f
170	li	$5,1
1711:
172	move	$2,$5
173	j	$31
174
175	.end longjmp
176