xref: /openbsd/lib/libm/arch/m88k/fenv.c (revision d89ec533)
1 /*	$OpenBSD: fenv.c,v 1.7 2016/09/12 19:47:02 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 = {
31 	0x00000000,				/* Control register */
32 	0x00000000				/* Status register */
33 };
34 
35 /*
36  * The feclearexcept() function clears the supported floating-point exceptions
37  * represented by `excepts'.
38  */
39 int
40 feclearexcept(int excepts)
41 {
42 	unsigned int fpsr;
43 
44 	excepts &= FE_ALL_EXCEPT;
45 
46 	/* Store the current floating-point status register */
47 	__asm__ volatile ("fldcr %0, %%fcr62" : "=r" (fpsr));
48 
49 	/* Clear the requested floating-point exceptions */
50 	fpsr &= ~excepts;
51 
52 	/* Load the floating-point status register */
53 	__asm__ volatile ("fstcr %0, %%fcr62" : : "r" (fpsr));
54 
55 	return (0);
56 }
57 DEF_STD(feclearexcept);
58 
59 /*
60  * The fegetexceptflag() function stores an implementation-defined
61  * representation of the states of the floating-point status flags indicated by
62  * the argument excepts in the object pointed to by the argument flagp.
63  */
64 int
65 fegetexceptflag(fexcept_t *flagp, int excepts)
66 {
67 	unsigned int fpsr;
68 
69 	excepts &= FE_ALL_EXCEPT;
70 
71 	/* Store the current floating-point status register */
72 	__asm__ volatile ("fldcr %0, %%fcr62" : "=r" (fpsr));
73 
74 	/* Store the results in flagp */
75 	*flagp = fpsr & excepts;
76 
77 	return (0);
78 }
79 
80 /*
81  * The feraiseexcept() function raises the supported floating-point exceptions
82  * represented by the argument `excepts'.
83  */
84 int
85 feraiseexcept(int excepts)
86 {
87 	volatile double d;
88 
89 	excepts &= FE_ALL_EXCEPT;
90 
91 	/*
92 	 * With a compiler that supports the FENV_ACCESS pragma
93 	 * properly, simple expressions like '0.0 / 0.0' should
94 	 * be sufficient to generate traps.  Unfortunately, we
95 	 * need to bring a volatile variable into the equation
96 	 * to prevent incorrect optimizations.
97 	 */
98 	if (excepts & FE_INVALID) {
99 		d = 0.0;
100 		d = 0.0 / d;
101 	}
102 	if (excepts & FE_DIVBYZERO) {
103 		d = 0.0;
104 		d = 1.0 / d;
105 	}
106 	if (excepts & FE_OVERFLOW) {
107 		d = 0x1.ffp1023;
108 		d *= 2.0;
109 	}
110 	if (excepts & FE_UNDERFLOW) {
111 		d = 0x1p1023;
112 		d = 0x1p-1022 / d;
113 	}
114 	if (excepts & FE_INEXACT) {
115 		d = 0x1p-1022;
116 		d += 1.0;
117 	}
118 	return (0);
119 }
120 DEF_STD(feraiseexcept);
121 
122 /*
123  * This function sets the floating-point status flags indicated by the argument
124  * `excepts' to the states stored in the object pointed to by `flagp'. It does
125  * NOT raise any floating-point exceptions, but only sets the state of the flags.
126  */
127 int
128 fesetexceptflag(const fexcept_t *flagp, int excepts)
129 {
130 	unsigned int fpsr;
131 
132 	excepts &= FE_ALL_EXCEPT;
133 
134 	/* Store the current floating-point status register */
135 	__asm__ volatile ("fldcr %0, %%fcr62" : "=r" (fpsr));
136 
137 	/* Set the requested status flags */
138 	fpsr &= ~excepts;
139 	fpsr |= *flagp & excepts;
140 
141 	/* Load the floating-point status register */
142 	__asm__ volatile ("fstcr %0, %%fcr62" : : "r" (fpsr));
143 
144 	return (0);
145 }
146 DEF_STD(fesetexceptflag);
147 
148 /*
149  * The fetestexcept() function determines which of a specified subset of the
150  * floating-point exception flags are currently set. The `excepts' argument
151  * specifies the floating-point status flags to be queried.
152  */
153 int
154 fetestexcept(int excepts)
155 {
156 	unsigned int fpsr;
157 
158 	excepts &= FE_ALL_EXCEPT;
159 
160 	/* Store the current floating-point status register */
161 	__asm__ volatile ("fldcr %0, %%fcr62" : "=r" (fpsr));
162 
163 	return (fpsr & excepts);
164 }
165 DEF_STD(fetestexcept);
166 
167 /*
168  * The fegetround() function gets the current rounding direction.
169  */
170 int
171 fegetround(void)
172 {
173 	unsigned int fpcr;
174 
175 	/* Store the current floating-point control register */
176 	__asm__ volatile ("fldcr %0, %%fcr63" : "=r" (fpcr));
177 
178 	return (fpcr & _ROUND_MASK);
179 }
180 DEF_STD(fegetround);
181 
182 /*
183  * The fesetround() function establishes the rounding direction represented by
184  * its argument `round'. If the argument is not equal to the value of a rounding
185  * direction macro, the rounding direction is not changed.
186  */
187 int
188 fesetround(int round)
189 {
190 	unsigned int fpcr;
191 
192 	/* Check whether requested rounding direction is supported */
193 	if (round & ~_ROUND_MASK)
194 		return (-1);
195 
196 	/* Store the current floating-point control register */
197 	__asm__ volatile ("fldcr %0, %%fcr63" : "=r" (fpcr));
198 
199 	/* Set the rounding direction */
200 	fpcr &= ~_ROUND_MASK;
201 	fpcr |= round;
202 
203 	/* Load the floating-point control register */
204 	__asm__ volatile ("fstcr %0, %%fcr63" : : "r" (fpcr));
205 
206 	return (0);
207 }
208 DEF_STD(fesetround);
209 
210 /*
211  * The fegetenv() function attempts to store the current floating-point
212  * environment in the object pointed to by envp.
213  */
214 int
215 fegetenv(fenv_t *envp)
216 {
217 	/* Store the current floating-point control and status registers */
218 	__asm__ volatile ("fldcr %0, %%fcr63" : "=r" (envp->__control));
219 	__asm__ volatile ("fldcr %0, %%fcr62" : "=r" (envp->__status));
220 
221 	return (0);
222 }
223 DEF_STD(fegetenv);
224 
225 /*
226  * The feholdexcept() function saves the current floating-point environment
227  * in the object pointed to by envp, clears the floating-point status flags, and
228  * then installs a non-stop (continue on floating-point exceptions) mode, if
229  * available, for all floating-point exceptions.
230  */
231 int
232 feholdexcept(fenv_t *envp)
233 {
234 	unsigned int fpsr, fpcr;
235 
236 	/* Store the current floating-point control and status registers */
237 	__asm__ volatile ("fldcr %0, %%fcr63" : "=r" (envp->__control));
238 	__asm__ volatile ("fldcr %0, %%fcr62" : "=r" (envp->__status));
239 
240 	/* Clear exception flags in FPSR */
241 	fpsr = envp->__status;
242 	fpsr &= ~FE_ALL_EXCEPT;
243 	__asm__ volatile ("fstcr %0, %%fcr62" : : "r" (fpsr));
244 
245 	/* Mask all exceptions */
246 	fpcr = envp->__control;
247 	fpcr &= ~FE_ALL_EXCEPT;
248 	__asm__ volatile ("fstcr %0, %%fcr63" : : "r" (fpcr));
249 
250 	return (0);
251 }
252 DEF_STD(feholdexcept);
253 
254 /*
255  * The fesetenv() function attempts to establish the floating-point environment
256  * represented by the object pointed to by envp. The argument `envp' points
257  * to an object set by a call to fegetenv() or feholdexcept(), or equal a
258  * floating-point environment macro. The fesetenv() function does not raise
259  * floating-point exceptions, but only installs the state of the floating-point
260  * status flags represented through its argument.
261  */
262 int
263 fesetenv(const fenv_t *envp)
264 {
265 	fenv_t fenv;
266 
267 	/* Store the current floating-point control and status registers */
268 	__asm__ volatile ("fldcr %0, %%fcr63" : "=r" (fenv.__control));
269 	__asm__ volatile ("fldcr %0, %%fcr62" : "=r" (fenv.__status));
270 
271 	/* Set the requested control flags */
272 	fenv.__control &= ~(FE_ALL_EXCEPT | _ROUND_MASK);
273 	fenv.__control |= envp->__control & (FE_ALL_EXCEPT | _ROUND_MASK);
274 
275 	/* Set the requested status flags */
276 	fenv.__status &= ~FE_ALL_EXCEPT;
277 	fenv.__status |= envp->__status & FE_ALL_EXCEPT;
278 
279 	/* Load the floating-point control and status registers */
280 	__asm__ volatile ("fstcr %0, %%fcr63" : : "r" (fenv.__control));
281 	__asm__ volatile ("fstcr %0, %%fcr62" : : "r" (fenv.__status));
282 
283 	return (0);
284 }
285 DEF_STD(fesetenv);
286 
287 /*
288  * The feupdateenv() function saves the currently raised floating-point
289  * exceptions in its automatic storage, installs the floating-point environment
290  * represented by the object pointed to by `envp', and then raises the saved
291  * floating-point exceptions. The argument `envp' shall point to an object set
292  * by a call to feholdexcept() or fegetenv(), or equal a floating-point
293  * environment macro.
294  */
295 int
296 feupdateenv(const fenv_t *envp)
297 {
298 	unsigned int fpsr;
299 
300 	/* Store the current floating-point status register */
301 	__asm__ volatile ("fldcr %0, %%fcr62" : "=r" (fpsr));
302 
303 	/* Install new floating-point environment */
304 	fesetenv(envp);
305 
306 	/* Raise any previously accumulated exceptions */
307 	feraiseexcept(fpsr);
308 
309 	return (0);
310 }
311 DEF_STD(feupdateenv);
312 
313 /*
314  * The following functions are extentions to the standard
315  */
316 int
317 feenableexcept(int mask)
318 {
319 	unsigned int fpcr, omask;
320 
321 	mask &= FE_ALL_EXCEPT;
322 
323 	/* Store the current floating-point control register */
324 	__asm__ volatile ("fldcr %0, %%fcr63" : "=r" (fpcr));
325 
326 	omask = fpcr & FE_ALL_EXCEPT;
327 	fpcr |= mask;
328 
329 	/* Load the floating-point control register */
330 	__asm__ volatile ("fstcr %0, %%fcr63" : : "r" (fpcr));
331 
332 	return (omask);
333 
334 }
335 
336 int
337 fedisableexcept(int mask)
338 {
339 	unsigned int fpcr, omask;
340 
341 	mask &= FE_ALL_EXCEPT;
342 
343 	/* Store the current floating-point control register */
344 	__asm__ volatile ("fldcr %0, %%fcr63" : "=r" (fpcr));
345 
346 	omask = fpcr & FE_ALL_EXCEPT;
347 	fpcr &= ~mask;
348 
349 	/* Load the floating-point control register */
350 	__asm__ volatile ("fstcr %0, %%fcr63" : : "r" (fpcr));
351 
352 	return (omask);
353 }
354 
355 int
356 fegetexcept(void)
357 {
358 	unsigned int fpcr;
359 
360 	/* Store the current floating-point control register */
361 	__asm__ volatile ("fldcr %0, %%fcr63" : "=r" (fpcr));
362 
363 	return (fpcr & FE_ALL_EXCEPT);
364 }
365