xref: /openbsd-src/lib/libm/arch/mips64/fenv.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: fenv.c,v 1.4 2014/04/18 15:09:52 guenther Exp $	*/
2 
3 /*
4  * Copyright (c) 2011 Martynas Venckus <martynas@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <fenv.h>
20 
21 /*
22  * The following constant represents the default floating-point environment
23  * (that is, the one installed at program startup) and has type pointer to
24  * const-qualified fenv_t.
25  *
26  * It can be used as an argument to the functions within the <fenv.h> header
27  * that manage the floating-point environment, namely fesetenv() and
28  * feupdateenv().
29  */
30 fenv_t __fe_dfl_env = 0;
31 
32 /*
33  * The feclearexcept() function clears the supported floating-point exceptions
34  * represented by `excepts'.
35  */
36 int
37 feclearexcept(int excepts)
38 {
39 	unsigned int fcsr;
40 
41 	excepts &= FE_ALL_EXCEPT;
42 
43 	/* Store the current floating-point control and status register */
44 	__asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr));
45 
46 	/* Clear the requested floating-point exceptions */
47 	fcsr &= ~excepts;
48 
49 	/* Load the floating-point control and status register */
50 	__asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr));
51 
52 	return (0);
53 }
54 
55 /*
56  * The fegetexceptflag() function stores an implementation-defined
57  * representation of the states of the floating-point status flags indicated by
58  * the argument excepts in the object pointed to by the argument flagp.
59  */
60 int
61 fegetexceptflag(fexcept_t *flagp, int excepts)
62 {
63 	unsigned int fcsr;
64 
65 	excepts &= FE_ALL_EXCEPT;
66 
67 	/* Store the current floating-point control and status register */
68 	__asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr));
69 
70 	/* Store the results in flagp */
71 	*flagp = fcsr & excepts;
72 
73 	return (0);
74 }
75 
76 /*
77  * The feraiseexcept() function raises the supported floating-point exceptions
78  * represented by the argument `excepts'.
79  */
80 int
81 feraiseexcept(int excepts)
82 {
83 	unsigned int fcsr;
84 
85 	excepts &= FE_ALL_EXCEPT;
86 
87 	/* Store the current floating-point control and status register */
88 	__asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr));
89 
90 	fcsr |= excepts | (excepts << 10);
91 
92 	/* Load the floating-point control and status register */
93 	__asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr));
94 
95 	return (0);
96 }
97 
98 /*
99  * This function sets the floating-point status flags indicated by the argument
100  * `excepts' to the states stored in the object pointed to by `flagp'. It does
101  * NOT raise any floating-point exceptions, but only sets the state of the flags.
102  */
103 int
104 fesetexceptflag(const fexcept_t *flagp, int excepts)
105 {
106 	unsigned int fcsr;
107 
108 	excepts &= FE_ALL_EXCEPT;
109 
110 	/* Store the current floating-point control and status register */
111 	__asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr));
112 
113 	/* Set the requested status flags */
114 	fcsr &= ~excepts;
115 	fcsr |= *flagp & excepts;
116 
117 	/* Load the floating-point control and status register */
118 	__asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr));
119 
120 	return (0);
121 }
122 
123 /*
124  * The fetestexcept() function determines which of a specified subset of the
125  * floating-point exception flags are currently set. The `excepts' argument
126  * specifies the floating-point status flags to be queried.
127  */
128 int
129 fetestexcept(int excepts)
130 {
131 	unsigned int fcsr;
132 
133 	excepts &= FE_ALL_EXCEPT;
134 
135 	/* Store the current floating-point control and status register */
136 	__asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr));
137 
138 	return (fcsr & excepts);
139 }
140 
141 /*
142  * The fegetround() function gets the current rounding direction.
143  */
144 int
145 fegetround(void)
146 {
147 	unsigned int fcsr;
148 
149 	/* Store the current floating-point control and status register */
150 	__asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr));
151 
152 	return (fcsr & _ROUND_MASK);
153 }
154 
155 /*
156  * The fesetround() function establishes the rounding direction represented by
157  * its argument `round'. If the argument is not equal to the value of a rounding
158  * direction macro, the rounding direction is not changed.
159  */
160 int
161 fesetround(int round)
162 {
163 	unsigned int fcsr;
164 
165 	/* Check whether requested rounding direction is supported */
166 	if (round & ~_ROUND_MASK)
167 		return (-1);
168 
169 	/* Store the current floating-point control and status register */
170 	__asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr));
171 
172 	/* Set the rounding direction */
173 	fcsr &= ~_ROUND_MASK;
174 	fcsr |= round;
175 
176 	/* Load the floating-point control and status register */
177 	__asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr));
178 
179 	return (0);
180 }
181 
182 /*
183  * The fegetenv() function attempts to store the current floating-point
184  * environment in the object pointed to by envp.
185  */
186 int
187 fegetenv(fenv_t *envp)
188 {
189 	/* Store the current floating-point control and status register */
190 	__asm__ volatile ("cfc1 %0, $31" : "=r" (*envp));
191 
192 	return (0);
193 }
194 
195 /*
196  * The feholdexcept() function saves the current floating-point environment
197  * in the object pointed to by envp, clears the floating-point status flags, and
198  * then installs a non-stop (continue on floating-point exceptions) mode, if
199  * available, for all floating-point exceptions.
200  */
201 int
202 feholdexcept(fenv_t *envp)
203 {
204 	unsigned int fcsr;
205 
206 	/* Store the current floating-point control and status register */
207 	__asm__ volatile ("cfc1 %0, $31" : "=r" (*envp));
208 
209 	/* Clear exception flags in FCSR */
210 	fcsr = *envp;
211 	fcsr &= ~FE_ALL_EXCEPT;
212 
213 	/* Mask all exceptions */
214 	fcsr &= ~(FE_ALL_EXCEPT << _MASK_SHIFT);
215 	__asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr));
216 
217 	return (0);
218 }
219 
220 /*
221  * The fesetenv() function attempts to establish the floating-point environment
222  * represented by the object pointed to by envp. The argument `envp' points
223  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
224  * floating-point environment macro. The fesetenv() function does not raise
225  * floating-point exceptions, but only installs the state of the floating-point
226  * status flags represented through its argument.
227  */
228 int
229 fesetenv(const fenv_t *envp)
230 {
231 	/* Load the floating-point control and status register */
232 	__asm__ volatile ("ctc1 %0, $31" : : "r" (*envp));
233 
234 	return (0);
235 }
236 
237 /*
238  * The feupdateenv() function saves the currently raised floating-point
239  * exceptions in its automatic storage, installs the floating-point environment
240  * represented by the object pointed to by `envp', and then raises the saved
241  * floating-point exceptions. The argument `envp' shall point to an object set
242  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
243  * environment macro.
244  */
245 int
246 feupdateenv(const fenv_t *envp)
247 {
248 	unsigned int fcsr;
249 
250 	/* Store the current floating-point control and status register */
251 	__asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr));
252 
253 	/* Install new floating-point environment */
254 	fesetenv(envp);
255 
256 	/* Raise any previously accumulated exceptions */
257 	feraiseexcept(fcsr);
258 
259 	return (0);
260 }
261 
262 /*
263  * The following functions are extentions to the standard
264  */
265 int
266 feenableexcept(int mask)
267 {
268 	unsigned int fcsr, omask;
269 
270 	mask &= FE_ALL_EXCEPT;
271 
272 	/* Store the current floating-point control and status register */
273 	__asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr));
274 
275 	omask = (fcsr >> _MASK_SHIFT) & FE_ALL_EXCEPT;
276 	fcsr |= mask << _MASK_SHIFT;
277 
278 	/* Load the floating-point control and status register */
279 	__asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr));
280 
281 	return (omask);
282 
283 }
284 
285 int
286 fedisableexcept(int mask)
287 {
288 	unsigned int fcsr, omask;
289 
290 	mask &= FE_ALL_EXCEPT;
291 
292 	/* Store the current floating-point control and status register */
293 	__asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr));
294 
295 	omask = (fcsr >> _MASK_SHIFT) & FE_ALL_EXCEPT;
296 	fcsr &= ~(mask << _MASK_SHIFT);
297 
298 	/* Load the floating-point control and status register */
299 	__asm__ volatile ("ctc1 %0, $31" : : "r" (fcsr));
300 
301 	return (omask);
302 }
303 
304 int
305 fegetexcept(void)
306 {
307 	unsigned int fcsr;
308 
309 	/* Store the current floating-point control and status register */
310 	__asm__ volatile ("cfc1 %0, $31" : "=r" (fcsr));
311 
312 	return ((fcsr >> _MASK_SHIFT) & FE_ALL_EXCEPT);
313 }
314