1 /*
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright © 2023 Keith Packard
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above
14  *    copyright notice, this list of conditions and the following
15  *    disclaimer in the documentation and/or other materials provided
16  *    with the distribution.
17  *
18  * 3. Neither the name of the copyright holder nor the names of its
19  *    contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33  * OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #define	_vmrs_fpscr(__r)	__asm __volatile("vmrs %0, fpscr" : "=&r"(__r))
37 #define	_vmsr_fpscr(__r)	__asm __volatile("vmsr fpscr, %0" : : "r"(__r))
38 #define	_FPU_MASK_SHIFT	8
39 #define	_ROUND_MASK	(FE_TONEAREST | FE_DOWNWARD | \
40 			 FE_UPWARD | FE_TOWARDZERO)
41 
feclearexcept(int excepts)42 __declare_fenv_inline(int) feclearexcept(int excepts)
43 {
44 	fexcept_t __fpsr;
45 
46 	_vmrs_fpscr(__fpsr);
47 	__fpsr &= ~excepts;
48 	_vmsr_fpscr(__fpsr);
49 	return (0);
50 }
51 
fedisableexcept(int __mask)52 __declare_fenv_inline(int) fedisableexcept(int __mask)
53 {
54 	fenv_t __old_fpsr, __new_fpsr;
55 
56 	_vmrs_fpscr(__old_fpsr);
57 	__new_fpsr = __old_fpsr &
58 	    ~((__mask & FE_ALL_EXCEPT) << _FPU_MASK_SHIFT);
59 	_vmsr_fpscr(__new_fpsr);
60 	return ((__old_fpsr >> _FPU_MASK_SHIFT) & FE_ALL_EXCEPT);
61 }
feenableexcept(int __mask)62 __declare_fenv_inline(int) feenableexcept(int __mask)
63 {
64         fenv_t __old_fpsr, __new_fpsr, __check_fpsr;
65 
66 	_vmrs_fpscr(__old_fpsr);
67 	__new_fpsr = __old_fpsr |
68 	    ((__mask & FE_ALL_EXCEPT) << _FPU_MASK_SHIFT);
69 	_vmsr_fpscr(__new_fpsr);
70         _vmrs_fpscr(__check_fpsr);
71         if (__check_fpsr != __new_fpsr)
72                 return -1;
73 	return ((__old_fpsr >> _FPU_MASK_SHIFT) & FE_ALL_EXCEPT);
74 }
75 
fegetenv(fenv_t * envp)76 __declare_fenv_inline(int) fegetenv(fenv_t *envp)
77 {
78 	_vmrs_fpscr(*envp);
79 	return (0);
80 }
81 
fegetexcept(void)82 __declare_fenv_inline(int) fegetexcept(void)
83 {
84 	fenv_t __fpsr;
85 
86 	_vmrs_fpscr(__fpsr);
87 	return (__fpsr & FE_ALL_EXCEPT);
88 }
89 
fegetexceptflag(fexcept_t * flagp,int excepts)90 __declare_fenv_inline(int) fegetexceptflag(fexcept_t *flagp, int excepts)
91 {
92 	fexcept_t __fpsr;
93 
94 	_vmrs_fpscr(__fpsr);
95         *flagp = __fpsr & excepts;
96 	return (0);
97 }
98 
fegetround(void)99 __declare_fenv_inline(int) fegetround(void)
100 {
101 	fenv_t __fpsr;
102 
103 	_vmrs_fpscr(__fpsr);
104 	return (__fpsr & _ROUND_MASK);
105 }
feholdexcept(fenv_t * envp)106 __declare_fenv_inline(int) feholdexcept(fenv_t *envp)
107 {
108 	fenv_t __env;
109 
110 	_vmrs_fpscr(__env);
111 	*envp = __env;
112 	__env &= ~(FE_ALL_EXCEPT);
113 	_vmsr_fpscr(__env);
114 	return (0);
115 }
116 
fesetenv(const fenv_t * envp)117 __declare_fenv_inline(int) fesetenv(const fenv_t *envp)
118 {
119 	_vmsr_fpscr(*envp);
120 	return (0);
121 }
122 
fesetexceptflag(const fexcept_t * flagp,int excepts)123 __declare_fenv_inline(int) fesetexceptflag(const fexcept_t *flagp, int excepts)
124 {
125 	fexcept_t __fpsr;
126 
127 	_vmrs_fpscr(__fpsr);
128 	__fpsr &= ~excepts;
129 	__fpsr |= *flagp & excepts;
130 	_vmsr_fpscr(__fpsr);
131 	return (0);
132 }
133 
feraiseexcept(int excepts)134 __declare_fenv_inline(int) feraiseexcept(int excepts)
135 {
136 	fexcept_t __ex = excepts;
137 
138 	return fesetexceptflag(&__ex, excepts);
139 }
140 
fesetexcept(int excepts)141 __declare_fenv_inline(int) fesetexcept(int excepts)
142 {
143         return feraiseexcept(excepts);
144 }
145 
fesetround(int round)146 __declare_fenv_inline(int) fesetround(int round)
147 {
148 	fenv_t __fpsr;
149 
150 	_vmrs_fpscr(__fpsr);
151 	__fpsr &= ~(_ROUND_MASK);
152 	__fpsr |= round;
153 	_vmsr_fpscr(__fpsr);
154 	return (0);
155 }
156 
fetestexcept(int excepts)157 __declare_fenv_inline(int) fetestexcept(int excepts)
158 {
159 	fexcept_t __fpsr;
160 
161 	_vmrs_fpscr(__fpsr);
162 	return (__fpsr & excepts);
163 }
164 
feupdateenv(const fenv_t * envp)165 __declare_fenv_inline(int) feupdateenv(const fenv_t *envp)
166 {
167 	fexcept_t __fpsr;
168 
169 	_vmrs_fpscr(__fpsr);
170 	_vmsr_fpscr(*envp);
171 	feraiseexcept(__fpsr & FE_ALL_EXCEPT);
172 	return (0);
173 }
174