OSDN Git Service

- fixup asm. No object-code changes
[uclinux-h8/uClibc.git] / libc / sysdeps / linux / e1 / bits / fenvinline.h
1 /* 
2    Inline floating-point environment handling functions for Hyperstone e1-32X.
3    Copyright (C) 2002-2003,    George Thanos <george.thanos@gdt.gr>
4                                Yannis Mitsos <yannis.mitsos@gdt.gr>
5
6    Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
7
8    The GNU C Library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public
10    License as published by the Free Software Foundation; either
11    version 2.1 of the License, or (at your option) any later version.
12
13    The GNU C Library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the GNU C Library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307 USA.  */
22
23 #if defined __GNUC__ && !defined _SOFT_FLOAT && !defined __NO_MATH_INLINES
24
25 /********************************************************** 
26  *  --- A small description of the E1-16/32X FP unit. ---
27  * FP exceptions can be enabled and disabled through 
28  * <feenableexcept>, <fedisableexcept>.
29  *
30  * - When an enabled exception takes place a SIGFPE signal
31  * is sent to the process by the exception handler. User
32  * can test for the exception that took place through
33  * <fetestexcept>.
34  * feraiseexcept works only for accrued exceptions.
35  *
36  * - When a disabld exception takes place it does not generate
37  * a trap. The user can check if any exception took place after
38  * an FP instruction by issuing an <fetestexcept> command.
39  * User should first clear the G2 register by issuing an
40  * <feclearexcept> function. 
41  * The following program is a typical example of how the user
42  * should check for exceptions that did not generate a SIGFPE
43  * signal :
44  * {
45  *   double f;
46  *   int raised;
47  *   feclearexcept (FE_ALL_EXCEPT);
48  *   f = compute ();
49  *   raised = fetestexcept (FE_OVERFLOW | FE_INVALID);
50  *   if (raised & FE_OVERFLOW) {  ...  }
51  *   if (raised & FE_INVALID) {  ...  }
52  *    ... 
53  * }
54  ***********************************************************/
55
56 /* Get FPU rounding mode  */
57 #define fegetround()                     \
58 ({                                       \
59         unsigned int tmp;                \
60         __asm__ __volatile__("mov %0, SR"        \
61                         :"=l"(tmp)       \
62                         :/*no input*/);  \
63         tmp &= (3<<13);                  \
64         (tmp);                           \
65 })
66
67 /* Set FPU rounding mode  */
68 #define fesetround(round)                \
69 ({                                       \
70         unsigned int tmp = (3 << 13);    \
71         while(1) {                       \
72         /* Clear SR.FRM field */         \
73         __asm__ __volatile__("andn SR, %0"       \
74                         :/*no output*/   \
75                         :"l"(tmp) );     \
76         tmp &= round;                    \
77                                          \
78         if(tmp) {                        \
79                 tmp = -1;                \
80                 break;                   \
81         }                                \
82                                          \
83         __asm__ __volatile__("or SR, %0"         \
84                         :/*no input*/    \
85                         :"l"(round) );   \
86         tmp = 0;                         \
87         break;                           \
88         }                                \
89         (tmp);                           \
90 })
91
92 /* The following functions test for accrued exceptions.
93  * No trap is generated on an FP exception.
94  */
95 static inline feclearexcept(int __excepts)
96 {
97         unsigned int enabled_excepts, disabled_excepts;
98
99         /* Check that __excepts is correctly set */
100         if( __excepts & (~0x1F00) )
101                 return -1;
102
103         __asm__ __volatile__("mov %0, SR"
104                      :"=l"(enabled_excepts)
105                      :/*no input*/ ); 
106
107         enabled_excepts  &= 0x1F00;
108         disabled_excepts = ~enabled_excepts;
109         disabled_excepts &= 0x1F00;
110
111         enabled_excepts  &= __excepts;
112         disabled_excepts &= __excepts;
113
114         /* Clear accrued exceptions */
115         __asm__ __volatile__("andn G2, %0\n\t"
116                      "andn G2, %1\n\t"
117                         :/*no output*/
118                         :"l"(enabled_excepts),
119                          "l"(disabled_excepts >> 8) );
120         return 0;
121 }
122
123 /* fetestexcepts tests both for actual and accrued
124  * excepts. You can test for an exception either after
125  * an FP instruction or within a SIGFPE handler
126  */ 
127 inline int fetestexcept(int __excepts)
128 {       
129         unsigned int G2, G2en, G2dis;
130         unsigned int enabled_excepts, disabled_excepts;
131
132         /* Check that __excepts is correctly set */
133         if( __excepts & (~0x1F00) )
134                 return -1;
135
136         __asm__ __volatile__("mov %0, SR"
137                      :"=l"(enabled_excepts)
138                      :/*no input*/ ); 
139
140         enabled_excepts &= 0x1F00;
141         disabled_excepts = ~enabled_excepts;
142         disabled_excepts &= 0x1F00;
143
144         __asm__ __volatile__("mov %0, G2"
145                     :"=l"(G2)
146                     :/*no input*/ );
147
148         G2en  = G2 & 0x1F00;
149         G2dis = G2 & 0x1F;
150         G2en  &= enabled_excepts;
151         G2dis &= (disabled_excepts >> 8);
152         return ( G2en | (G2dis << 8) );
153 }
154
155 static inline int feraiseexcept(int __excepts)
156 {
157         __asm__ __volatile__("or G2, %0"
158                         :/*no output*/
159                         :"l"( __excepts >> 8  ) );
160         return 0;
161 }
162
163 /* The following functions enable/disable individual exceptions.
164  * If enabling an exception trap is going to occur, in case of error.
165  */
166 #define feenableexcept(__excepts)          \
167 ({                                         \
168         int __retval, __pexcepts;          \
169         int __tmpexcepts = __excepts;      \
170                                            \
171         while(1) {                         \
172             __asm__ __volatile__("mov %0, SR"      \
173                      :"=l"(__pexcepts)     \
174                      :/*no input*/ );      \
175             __pexcepts &= 0x1F00;          \
176                                            \
177 /* Check if __except values are valid */   \
178             if( __tmpexcepts & ~0x1F00 ) { \
179                 __retval = -1;             \
180                 fprintf(stderr,"Non valid excepts\n");\
181                 break;                     \
182             }                              \
183                                            \
184             __asm__ __volatile__("or SR, %0"       \
185                         :/*no output*/     \
186                         :"l"(__tmpexcepts) ); \
187             __retval = __pexcepts;         \
188             break;                         \
189         }                                  \
190         (__retval);                        \
191 })
192
193
194 #define fedisableexcept(__excepts)         \
195 ({                                         \
196         int __retval, __pexcepts;          \
197         int __tmpexcepts = __excepts;      \
198                                            \
199         while(1) {                         \
200             __asm__ __volatile__("mov %0, SR"      \
201                      :"=l"(__pexcepts)     \
202                      :/*no input*/ );      \
203             __pexcepts &= 0x1F00;          \
204                                            \
205 /* Check if __except values are valid */   \
206             if( __tmpexcepts & ~0x1F00 ) { \
207                 __retval = -1;             \
208                 fprintf(stderr,"Non valid excepts\n");\
209                 break;                     \
210             }                              \
211                                            \
212             __asm__ __volatile__("andn SR, %0"     \
213                         :/*no output*/     \
214                         :"l"(__tmpexcepts) ); \
215             __retval = __pexcepts;         \
216             break;                         \
217         }                                  \
218         (__retval);                        \
219 })
220
221 static inline int fegetexcept(int excepts)
222 {
223         unsigned int tmp;
224         __asm__ __volatile__("mov %0, SR"
225                     :"=l"(tmp)
226                     :/*no input*/ );
227         tmp &= 0x1F00;
228         return tmp;
229 }
230
231 static inline int fegetenv(fenv_t *envp)
232 {
233         __asm__ __volatile__("mov %0, SR\n\t
234                       mov %1, SR\n\t
235                       mov %2, G2\n\t
236                       mov %3, G2\n\t"
237                      :"=l"(envp->round_mode),
238                       "=l"(envp->trap_enabled),
239                       "=l"(envp->accrued_except),
240                       "=l"(envp->actual_except)
241                      :/*no input*/ );
242         envp->round_mode &= (3<<13);
243         envp->trap_enabled &= 0x1F00;
244         envp->accrued_except &= 0x1F;
245         envp->accrued_except <<= 8;
246         envp->actual_except &= 0x1F00;
247 }
248
249 #define feholdexcept(envp)        \
250 (                                         \
251         fegetenv(envp);                   \
252         fedisableexcept(FE_ALL_EXCEPT);   \
253         feclearexcept(FE_ALL_EXCEPT);     \
254         (0);                              \
255 )
256
257 #define fesetenv(envp)                \
258 ({                                                  \
259         /* Clear FRM & FTE field of SR */           \
260         unsigned long clearSR = ( 127<<8 );         \
261         __asm__ __volatile__("andn SR, %0\n\t"              \
262                      "or   SR, %1\n\t"              \
263                      "or   SR, %2\n\t"              \
264                      :/*no output*/                 \
265                      :"l"(clearSR),                 \
266                       "l"(envp->round_mode),        \
267                       "l"(envp->trap_enabled) );    \
268         __asm__ __volatile__("andn G2, 0x1F1F\n\t"          \
269                      "or   G2, %0\n\t"              \
270                      "or   G2, %1\n\t"              \
271                      :/*no output*/                 \
272                      :"l"( envp->accrued_except >> 8),\
273                      :"l"( envp->actual_except ) ); \
274         (0); /* return 0 */                         \
275 })
276                      
277 #define feupdateenv(envp)                           \
278 ({                                                  \
279         /* Clear FRM & FTE field of SR */           \
280         __asm__ __volatile__(/* We dont clear the prev SR*/ \
281                      "or   SR, %1\n\t"              \
282                      "or   SR, %2\n\t"              \
283                      :/*no output*/                 \
284                      :"l"(clearSR),                 \
285                       "l"(envp->round_mode),        \
286                       "l"(envp->accrued_except) );  \
287         __asm__ __volatile__(/* We dont clear the prev SR*/ \
288                      "or   G2, %0\n\t"              \
289                      "or   G2, %1\n\t"              \
290                      :/*no output*/                 \
291                      :"l"( envp->accrued_except >> 8),\
292                      :"l"( envp->actual_except ) ); \
293         (0); /* return 0 */                         \
294 })
295                      
296
297 #endif /* __GNUC__ && !_SOFT_FLOAT */
298