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#include <picolibc.h>
22
23#ifdef __mips16
24/* This file contains 32 bit assembly code.  */
25	.set nomips16
26#endif
27
28#define GPR_LAYOUT		\
29	GPR_OFFSET ($16, 0);	\
30	GPR_OFFSET ($17, 1);	\
31	GPR_OFFSET ($18, 2);	\
32	GPR_OFFSET ($19, 3);	\
33	GPR_OFFSET ($20, 4);	\
34	GPR_OFFSET ($21, 5);	\
35	GPR_OFFSET ($22, 6);	\
36	GPR_OFFSET ($23, 7);	\
37	GPR_OFFSET ($29, 8);	\
38	GPR_OFFSET ($30, 9);	\
39	GPR_OFFSET ($31, 10)
40
41#define NUM_GPRS_SAVED 11
42
43#ifdef __mips_hard_float
44#if _MIPS_SIM == _ABIN32
45#define FPR_LAYOUT		\
46	FPR_OFFSET ($f20, 0);	\
47	FPR_OFFSET ($f22, 1);	\
48	FPR_OFFSET ($f24, 2);	\
49	FPR_OFFSET ($f26, 3);	\
50	FPR_OFFSET ($f28, 4);	\
51	FPR_OFFSET ($f30, 5);
52#elif _MIPS_SIM == _ABI64
53#define FPR_LAYOUT		\
54	FPR_OFFSET ($f24, 0);	\
55	FPR_OFFSET ($f25, 1);	\
56	FPR_OFFSET ($f26, 2);	\
57	FPR_OFFSET ($f27, 3);	\
58	FPR_OFFSET ($f28, 4);	\
59	FPR_OFFSET ($f29, 5);	\
60	FPR_OFFSET ($f30, 6);	\
61	FPR_OFFSET ($f31, 7);
62#elif __mips_fpr == 0 || __mips_fpr == 64
63
64/* This deals with the o32 FPXX and FP64 cases.  Here we must use
65   SDC1 and LDC1 to access the FPRs.  These instructions require
66   8-byte aligned addresses.
67   Unfortunately, the MIPS jmp_buf only guarantees 4-byte alignment
68   and this cannot be increased without breaking compatibility with
69   pre-existing objects built against newlib.  There are 11 GPRS
70   saved in the jmp_buf so a buffer that happens to be 8-byte aligned
71   ends up leaving the FPR slots 4-byte aligned and an (only) 4-byte
72   aligned buffer leads to the FPR slots being 8-byte aligned!
73
74   To resolve this, we move the location of $31 to the last slot
75   in the jmp_buf when the overall buffer is 8-byte aligned.  $31
76   is simply loaded/stored twice to avoid adding complexity to the
77   GPR_LAYOUT macro above as well as FPR_LAYOUT.
78
79   The location of the last slot is index 22 which is calculated
80   from there being 11 GPRs saved and then 12 FPRs saved so the
81   index of the last FPR is 11+11.
82
83   The base of the jmp_buf is modified in $4 to allow the
84   FPR_OFFSET macros to just use the usual constant slot numbers
85   regardless of whether the realignment happened or not.  */
86
87#define FPR_LAYOUT		\
88	and $8, $4, 4;	 	\
89	beq $8, $0, 1f;		\
90	GPR_OFFSET ($31, 22);	\
91	addiu $4, $4, -4;	\
921:				\
93	FPR_OFFSET ($f20, 0);  	\
94	FPR_OFFSET ($f22, 2);	\
95	FPR_OFFSET ($f24, 4);	\
96	FPR_OFFSET ($f26, 6);	\
97	FPR_OFFSET ($f28, 8);	\
98	FPR_OFFSET ($f30, 10);
99#else /* Assuming _MIPS_SIM == _ABIO32 */
100#define FPR_LAYOUT		\
101	FPR_OFFSET ($f20, 0);	\
102	FPR_OFFSET ($f21, 1);	\
103	FPR_OFFSET ($f22, 2);	\
104	FPR_OFFSET ($f23, 3);	\
105	FPR_OFFSET ($f24, 4);	\
106	FPR_OFFSET ($f25, 5);	\
107	FPR_OFFSET ($f26, 6);	\
108	FPR_OFFSET ($f27, 7);	\
109	FPR_OFFSET ($f28, 8);	\
110	FPR_OFFSET ($f29, 9);	\
111	FPR_OFFSET ($f30, 10);	\
112	FPR_OFFSET ($f31, 11);
113#endif
114#else
115#define FPR_LAYOUT
116#endif
117
118#ifdef __mips64
119#define BYTES_PER_WORD 8
120#define LOAD_GPR ld
121#define LOAD_FPR ldc1
122#define STORE_GPR sd
123#define STORE_FPR sdc1
124#else
125#define LOAD_GPR lw
126#define STORE_GPR sw
127#define BYTES_PER_WORD 4
128#if __mips_fpr == 0 || __mips_fpr == 64
129#define LOAD_FPR ldc1
130#define STORE_FPR sdc1
131#else
132#define LOAD_FPR lwc1
133#define STORE_FPR swc1
134#endif
135#endif
136
137#define GPOFF(INDEX) (INDEX * BYTES_PER_WORD)
138#define FPOFF(INDEX) ((INDEX + NUM_GPRS_SAVED) * BYTES_PER_WORD)
139
140/* int setjmp (jmp_buf);  */
141	.globl	setjmp
142	.ent	setjmp
143setjmp:
144	.frame	$sp,0,$31
145
146#define GPR_OFFSET(REG, INDEX) STORE_GPR REG,GPOFF(INDEX)($4)
147#define FPR_OFFSET(REG, INDEX) STORE_FPR REG,FPOFF(INDEX)($4)
148	GPR_LAYOUT
149	FPR_LAYOUT
150#undef GPR_OFFSET
151#undef FPR_OFFSET
152
153	move	$2,$0
154	j	$31
155
156	.end	setjmp
157
158/* volatile void longjmp (jmp_buf, int);  */
159	.globl	longjmp
160	.ent	longjmp
161longjmp:
162	.frame	$sp,0,$31
163
164#define GPR_OFFSET(REG, INDEX) LOAD_GPR REG,GPOFF(INDEX)($4)
165#define FPR_OFFSET(REG, INDEX) LOAD_FPR REG,FPOFF(INDEX)($4)
166	GPR_LAYOUT
167	FPR_LAYOUT
168#undef GPR_OFFSET
169#undef FPR_OFFSET
170
171	bne	$5,$0,1f
172	li	$5,1
1731:
174	move	$2,$5
175	j	$31
176
177	.end longjmp
178