xref: /netbsd-src/sys/arch/mips/include/fenv.h (revision d909946ca08dceb44d7d0f22ec9488679695d976)
1 /*	$NetBSD: fenv.h,v 1.1 2015/12/21 17:02:33 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2004-2005 David Schultz <das@FreeBSD.ORG>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: head/lib/msun/mips/fenv.h 226218 2011-10-10 15:43:09Z das $
29  */
30 
31 #ifndef	_MIPS_FENV_H_
32 #define	_MIPS_FENV_H_
33 
34 #include <sys/stdint.h>
35 
36 #ifndef	__fenv_static
37 #define	__fenv_static	static
38 #endif
39 
40 typedef	uint32_t	fenv_t;
41 typedef	uint32_t	fexcept_t;
42 
43 /* Exception flags */
44 #define	FE_INVALID	0x0001
45 #define	FE_DIVBYZERO	0x0002
46 #define	FE_OVERFLOW	0x0004
47 #define	FE_UNDERFLOW	0x0008
48 #define	FE_INEXACT	0x0010
49 #define	FE_ALL_EXCEPT	(FE_DIVBYZERO | FE_INEXACT | \
50 			 FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)
51 
52 /* Rounding modes */
53 #define	FE_TONEAREST	0x0000
54 #define	FE_TOWARDZERO	0x0001
55 #define	FE_UPWARD	0x0002
56 #define	FE_DOWNWARD	0x0003
57 #define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
58 			 FE_UPWARD | FE_TOWARDZERO)
59 __BEGIN_DECLS
60 
61 /* Default floating-point environment */
62 extern const fenv_t	__fe_dfl_env;
63 #define	FE_DFL_ENV	(&__fe_dfl_env)
64 
65 /* We need to be able to map status flag positions to mask flag positions */
66 #define _FPUSW_SHIFT	16
67 #define	_ENABLE_MASK	(FE_ALL_EXCEPT << _FPUSW_SHIFT)
68 
69 #ifdef	ARM_HARD_FLOAT
70 #define	__rfs(__fpsr)	__asm __volatile("rfs %0" : "=r" (*(__fpsr)))
71 #define	__wfs(__fpsr)	__asm __volatile("wfs %0" : : "r" (__fpsr))
72 #else
73 #define __rfs(__fpsr)
74 #define __wfs(__fpsr)
75 #endif
76 
77 __fenv_static inline int
78 feclearexcept(int __excepts)
79 {
80 	fexcept_t __fpsr;
81 
82 	__rfs(&__fpsr);
83 	__fpsr &= ~__excepts;
84 	__wfs(__fpsr);
85 	return (0);
86 }
87 
88 __fenv_static inline int
89 fegetexceptflag(fexcept_t *__flagp, int __excepts)
90 {
91 	fexcept_t __fpsr;
92 
93 	__rfs(&__fpsr);
94 	*__flagp = __fpsr & __excepts;
95 	return (0);
96 }
97 
98 __fenv_static inline int
99 fesetexceptflag(const fexcept_t *__flagp, int __excepts)
100 {
101 	fexcept_t __fpsr;
102 
103 	__rfs(&__fpsr);
104 	__fpsr &= ~__excepts;
105 	__fpsr |= *__flagp & __excepts;
106 	__wfs(__fpsr);
107 	return (0);
108 }
109 
110 __fenv_static inline int
111 feraiseexcept(int __excepts)
112 {
113 	fexcept_t __ex = __excepts;
114 
115 	fesetexceptflag(&__ex, __excepts);	/* XXX */
116 	return (0);
117 }
118 
119 __fenv_static inline int
120 fetestexcept(int __excepts)
121 {
122 	fexcept_t __fpsr;
123 
124 	__rfs(&__fpsr);
125 	return (__fpsr & __excepts);
126 }
127 
128 __fenv_static inline int
129 fegetround(void)
130 {
131 
132 	/*
133 	 * Apparently, the rounding mode is specified as part of the
134 	 * instruction format on ARM, so the dynamic rounding mode is
135 	 * indeterminate.  Some FPUs may differ.
136 	 */
137 	return (-1);
138 }
139 
140 __fenv_static inline int
141 fesetround(int __round)
142 {
143 
144 	return (-1);
145 }
146 
147 __fenv_static inline int
148 fegetenv(fenv_t *__envp)
149 {
150 
151 	__rfs(__envp);
152 	return (0);
153 }
154 
155 __fenv_static inline int
156 feholdexcept(fenv_t *__envp)
157 {
158 	fenv_t __env;
159 
160 	__rfs(&__env);
161 	*__envp = __env;
162 	__env &= ~(FE_ALL_EXCEPT | _ENABLE_MASK);
163 	__wfs(__env);
164 	return (0);
165 }
166 
167 __fenv_static inline int
168 fesetenv(const fenv_t *__envp)
169 {
170 
171 	__wfs(*__envp);
172 	return (0);
173 }
174 
175 __fenv_static inline int
176 feupdateenv(const fenv_t *__envp)
177 {
178 	fexcept_t __fpsr;
179 
180 	__rfs(&__fpsr);
181 	__wfs(*__envp);
182 	feraiseexcept(__fpsr & FE_ALL_EXCEPT);
183 	return (0);
184 }
185 
186 #if defined(_NETBSD_SOURCE) || defined(_GNU_SOURCE)
187 
188 /* We currently provide no external definitions of the functions below. */
189 
190 static inline int
191 feenableexcept(int __mask)
192 {
193 	fenv_t __old_fpsr, __new_fpsr;
194 
195 	__rfs(&__old_fpsr);
196 	__new_fpsr = __old_fpsr | (__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT;
197 	__wfs(__new_fpsr);
198 	return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
199 }
200 
201 static inline int
202 fedisableexcept(int __mask)
203 {
204 	fenv_t __old_fpsr, __new_fpsr;
205 
206 	__rfs(&__old_fpsr);
207 	__new_fpsr = __old_fpsr & ~((__mask & FE_ALL_EXCEPT) << _FPUSW_SHIFT);
208 	__wfs(__new_fpsr);
209 	return ((__old_fpsr >> _FPUSW_SHIFT) & FE_ALL_EXCEPT);
210 }
211 
212 static inline int
213 fegetexcept(void)
214 {
215 	fenv_t __fpsr;
216 
217 	__rfs(&__fpsr);
218 	return ((__fpsr & _ENABLE_MASK) >> _FPUSW_SHIFT);
219 }
220 
221 #endif /* _NETBSD_SOURCE || _GNU_SOURCE */
222 
223 __END_DECLS
224 
225 #endif	/* !_FENV_H_ */
226