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