~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/m68k/math-emu/fp_arith.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /arch/m68k/math-emu/fp_arith.c (Architecture alpha) and /arch/m68k/math-emu/fp_arith.c (Architecture m68k)


  1 // SPDX-License-Identifier: GPL-2.0-or-later        1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*                                                  2 /*
  3                                                     3 
  4    fp_arith.c: floating-point math routines fo      4    fp_arith.c: floating-point math routines for the Linux-m68k
  5    floating point emulator.                         5    floating point emulator.
  6                                                     6 
  7    Copyright (c) 1998-1999 David Huggins-Daine      7    Copyright (c) 1998-1999 David Huggins-Daines.
  8                                                     8 
  9    Somewhat based on the AlphaLinux floating p      9    Somewhat based on the AlphaLinux floating point emulator, by David
 10    Mosberger-Tang.                                 10    Mosberger-Tang.
 11                                                    11 
 12  */                                                12  */
 13                                                    13 
 14 #include "fp_emu.h"                                14 #include "fp_emu.h"
 15 #include "multi_arith.h"                           15 #include "multi_arith.h"
 16 #include "fp_arith.h"                              16 #include "fp_arith.h"
 17                                                    17 
 18 const struct fp_ext fp_QNaN =                      18 const struct fp_ext fp_QNaN =
 19 {                                                  19 {
 20         .exp = 0x7fff,                             20         .exp = 0x7fff,
 21         .mant = { .m64 = ~0 }                      21         .mant = { .m64 = ~0 }
 22 };                                                 22 };
 23                                                    23 
 24 const struct fp_ext fp_Inf =                       24 const struct fp_ext fp_Inf =
 25 {                                                  25 {
 26         .exp = 0x7fff,                             26         .exp = 0x7fff,
 27 };                                                 27 };
 28                                                    28 
 29 /* let's start with the easy ones */               29 /* let's start with the easy ones */
 30                                                    30 
 31 struct fp_ext *fp_fabs(struct fp_ext *dest, st     31 struct fp_ext *fp_fabs(struct fp_ext *dest, struct fp_ext *src)
 32 {                                                  32 {
 33         dprint(PINSTR, "fabs\n");                  33         dprint(PINSTR, "fabs\n");
 34                                                    34 
 35         fp_monadic_check(dest, src);               35         fp_monadic_check(dest, src);
 36                                                    36 
 37         dest->sign = 0;                            37         dest->sign = 0;
 38                                                    38 
 39         return dest;                               39         return dest;
 40 }                                                  40 }
 41                                                    41 
 42 struct fp_ext *fp_fneg(struct fp_ext *dest, st     42 struct fp_ext *fp_fneg(struct fp_ext *dest, struct fp_ext *src)
 43 {                                                  43 {
 44         dprint(PINSTR, "fneg\n");                  44         dprint(PINSTR, "fneg\n");
 45                                                    45 
 46         fp_monadic_check(dest, src);               46         fp_monadic_check(dest, src);
 47                                                    47 
 48         dest->sign = !dest->sign;                  48         dest->sign = !dest->sign;
 49                                                    49 
 50         return dest;                               50         return dest;
 51 }                                                  51 }
 52                                                    52 
 53 /* Now, the slightly harder ones */                53 /* Now, the slightly harder ones */
 54                                                    54 
 55 /* fp_fadd: Implements the kernel of the FADD,     55 /* fp_fadd: Implements the kernel of the FADD, FSADD, FDADD, FSUB,
 56    FDSUB, and FCMP instructions. */                56    FDSUB, and FCMP instructions. */
 57                                                    57 
 58 struct fp_ext *fp_fadd(struct fp_ext *dest, st     58 struct fp_ext *fp_fadd(struct fp_ext *dest, struct fp_ext *src)
 59 {                                                  59 {
 60         int diff;                                  60         int diff;
 61                                                    61 
 62         dprint(PINSTR, "fadd\n");                  62         dprint(PINSTR, "fadd\n");
 63                                                    63 
 64         fp_dyadic_check(dest, src);                64         fp_dyadic_check(dest, src);
 65                                                    65 
 66         if (IS_INF(dest)) {                        66         if (IS_INF(dest)) {
 67                 /* infinity - infinity == NaN      67                 /* infinity - infinity == NaN */
 68                 if (IS_INF(src) && (src->sign      68                 if (IS_INF(src) && (src->sign != dest->sign))
 69                         fp_set_nan(dest);          69                         fp_set_nan(dest);
 70                 return dest;                       70                 return dest;
 71         }                                          71         }
 72         if (IS_INF(src)) {                         72         if (IS_INF(src)) {
 73                 fp_copy_ext(dest, src);            73                 fp_copy_ext(dest, src);
 74                 return dest;                       74                 return dest;
 75         }                                          75         }
 76                                                    76 
 77         if (IS_ZERO(dest)) {                       77         if (IS_ZERO(dest)) {
 78                 if (IS_ZERO(src)) {                78                 if (IS_ZERO(src)) {
 79                         if (src->sign != dest-     79                         if (src->sign != dest->sign) {
 80                                 if (FPDATA->rn     80                                 if (FPDATA->rnd == FPCR_ROUND_RM)
 81                                         dest->     81                                         dest->sign = 1;
 82                                 else               82                                 else
 83                                         dest->     83                                         dest->sign = 0;
 84                         }                          84                         }
 85                 } else                             85                 } else
 86                         fp_copy_ext(dest, src)     86                         fp_copy_ext(dest, src);
 87                 return dest;                       87                 return dest;
 88         }                                          88         }
 89                                                    89 
 90         dest->lowmant = src->lowmant = 0;          90         dest->lowmant = src->lowmant = 0;
 91                                                    91 
 92         if ((diff = dest->exp - src->exp) > 0)     92         if ((diff = dest->exp - src->exp) > 0)
 93                 fp_denormalize(src, diff);         93                 fp_denormalize(src, diff);
 94         else if ((diff = -diff) > 0)               94         else if ((diff = -diff) > 0)
 95                 fp_denormalize(dest, diff);        95                 fp_denormalize(dest, diff);
 96                                                    96 
 97         if (dest->sign == src->sign) {             97         if (dest->sign == src->sign) {
 98                 if (fp_addmant(dest, src))         98                 if (fp_addmant(dest, src))
 99                         if (!fp_addcarry(dest)     99                         if (!fp_addcarry(dest))
100                                 return dest;      100                                 return dest;
101         } else {                                  101         } else {
102                 if (dest->mant.m64 < src->mant    102                 if (dest->mant.m64 < src->mant.m64) {
103                         fp_submant(dest, src,     103                         fp_submant(dest, src, dest);
104                         dest->sign = !dest->si    104                         dest->sign = !dest->sign;
105                 } else                            105                 } else
106                         fp_submant(dest, dest,    106                         fp_submant(dest, dest, src);
107         }                                         107         }
108                                                   108 
109         return dest;                              109         return dest;
110 }                                                 110 }
111                                                   111 
112 /* fp_fsub: Implements the kernel of the FSUB,    112 /* fp_fsub: Implements the kernel of the FSUB, FSSUB, and FDSUB
113    instructions.                                  113    instructions.
114                                                   114 
115    Remember that the arguments are in assemble    115    Remember that the arguments are in assembler-syntax order! */
116                                                   116 
117 struct fp_ext *fp_fsub(struct fp_ext *dest, st    117 struct fp_ext *fp_fsub(struct fp_ext *dest, struct fp_ext *src)
118 {                                                 118 {
119         dprint(PINSTR, "fsub ");                  119         dprint(PINSTR, "fsub ");
120                                                   120 
121         src->sign = !src->sign;                   121         src->sign = !src->sign;
122         return fp_fadd(dest, src);                122         return fp_fadd(dest, src);
123 }                                                 123 }
124                                                   124 
125                                                   125 
126 struct fp_ext *fp_fcmp(struct fp_ext *dest, st    126 struct fp_ext *fp_fcmp(struct fp_ext *dest, struct fp_ext *src)
127 {                                                 127 {
128         dprint(PINSTR, "fcmp ");                  128         dprint(PINSTR, "fcmp ");
129                                                   129 
130         FPDATA->temp[1] = *dest;                  130         FPDATA->temp[1] = *dest;
131         src->sign = !src->sign;                   131         src->sign = !src->sign;
132         return fp_fadd(&FPDATA->temp[1], src);    132         return fp_fadd(&FPDATA->temp[1], src);
133 }                                                 133 }
134                                                   134 
135 struct fp_ext *fp_ftst(struct fp_ext *dest, st    135 struct fp_ext *fp_ftst(struct fp_ext *dest, struct fp_ext *src)
136 {                                                 136 {
137         dprint(PINSTR, "ftst\n");                 137         dprint(PINSTR, "ftst\n");
138                                                   138 
139         (void)dest;                               139         (void)dest;
140                                                   140 
141         return src;                               141         return src;
142 }                                                 142 }
143                                                   143 
144 struct fp_ext *fp_fmul(struct fp_ext *dest, st    144 struct fp_ext *fp_fmul(struct fp_ext *dest, struct fp_ext *src)
145 {                                                 145 {
146         union fp_mant128 temp;                    146         union fp_mant128 temp;
147         int exp;                                  147         int exp;
148                                                   148 
149         dprint(PINSTR, "fmul\n");                 149         dprint(PINSTR, "fmul\n");
150                                                   150 
151         fp_dyadic_check(dest, src);               151         fp_dyadic_check(dest, src);
152                                                   152 
153         /* calculate the correct sign now, as     153         /* calculate the correct sign now, as it's necessary for infinities */
154         dest->sign = src->sign ^ dest->sign;      154         dest->sign = src->sign ^ dest->sign;
155                                                   155 
156         /* Handle infinities */                   156         /* Handle infinities */
157         if (IS_INF(dest)) {                       157         if (IS_INF(dest)) {
158                 if (IS_ZERO(src))                 158                 if (IS_ZERO(src))
159                         fp_set_nan(dest);         159                         fp_set_nan(dest);
160                 return dest;                      160                 return dest;
161         }                                         161         }
162         if (IS_INF(src)) {                        162         if (IS_INF(src)) {
163                 if (IS_ZERO(dest))                163                 if (IS_ZERO(dest))
164                         fp_set_nan(dest);         164                         fp_set_nan(dest);
165                 else                              165                 else
166                         fp_copy_ext(dest, src)    166                         fp_copy_ext(dest, src);
167                 return dest;                      167                 return dest;
168         }                                         168         }
169                                                   169 
170         /* Of course, as we all know, zero * a    170         /* Of course, as we all know, zero * anything = zero.  You may
171            not have known that it might be a p    171            not have known that it might be a positive or negative
172            zero... */                             172            zero... */
173         if (IS_ZERO(dest) || IS_ZERO(src)) {      173         if (IS_ZERO(dest) || IS_ZERO(src)) {
174                 dest->exp = 0;                    174                 dest->exp = 0;
175                 dest->mant.m64 = 0;               175                 dest->mant.m64 = 0;
176                 dest->lowmant = 0;                176                 dest->lowmant = 0;
177                                                   177 
178                 return dest;                      178                 return dest;
179         }                                         179         }
180                                                   180 
181         exp = dest->exp + src->exp - 0x3ffe;      181         exp = dest->exp + src->exp - 0x3ffe;
182                                                   182 
183         /* shift up the mantissa for denormali    183         /* shift up the mantissa for denormalized numbers,
184            so that the highest bit is set, thi    184            so that the highest bit is set, this makes the
185            shift of the result below easier */    185            shift of the result below easier */
186         if ((long)dest->mant.m32[0] >= 0)         186         if ((long)dest->mant.m32[0] >= 0)
187                 exp -= fp_overnormalize(dest);    187                 exp -= fp_overnormalize(dest);
188         if ((long)src->mant.m32[0] >= 0)          188         if ((long)src->mant.m32[0] >= 0)
189                 exp -= fp_overnormalize(src);     189                 exp -= fp_overnormalize(src);
190                                                   190 
191         /* now, do a 64-bit multiply with expa    191         /* now, do a 64-bit multiply with expansion */
192         fp_multiplymant(&temp, dest, src);        192         fp_multiplymant(&temp, dest, src);
193                                                   193 
194         /* normalize it back to 64 bits and st    194         /* normalize it back to 64 bits and stuff it back into the
195            destination struct */                  195            destination struct */
196         if ((long)temp.m32[0] > 0) {              196         if ((long)temp.m32[0] > 0) {
197                 exp--;                            197                 exp--;
198                 fp_putmant128(dest, &temp, 1);    198                 fp_putmant128(dest, &temp, 1);
199         } else                                    199         } else
200                 fp_putmant128(dest, &temp, 0);    200                 fp_putmant128(dest, &temp, 0);
201                                                   201 
202         if (exp >= 0x7fff) {                      202         if (exp >= 0x7fff) {
203                 fp_set_ovrflw(dest);              203                 fp_set_ovrflw(dest);
204                 return dest;                      204                 return dest;
205         }                                         205         }
206         dest->exp = exp;                          206         dest->exp = exp;
207         if (exp < 0) {                            207         if (exp < 0) {
208                 fp_set_sr(FPSR_EXC_UNFL);         208                 fp_set_sr(FPSR_EXC_UNFL);
209                 fp_denormalize(dest, -exp);       209                 fp_denormalize(dest, -exp);
210         }                                         210         }
211                                                   211 
212         return dest;                              212         return dest;
213 }                                                 213 }
214                                                   214 
215 /* fp_fdiv: Implements the "kernel" of the FDI    215 /* fp_fdiv: Implements the "kernel" of the FDIV, FSDIV, FDDIV and
216    FSGLDIV instructions.                          216    FSGLDIV instructions.
217                                                   217 
218    Note that the order of the operands is coun    218    Note that the order of the operands is counter-intuitive: instead
219    of src / dest, the result is actually dest     219    of src / dest, the result is actually dest / src. */
220                                                   220 
221 struct fp_ext *fp_fdiv(struct fp_ext *dest, st    221 struct fp_ext *fp_fdiv(struct fp_ext *dest, struct fp_ext *src)
222 {                                                 222 {
223         union fp_mant128 temp;                    223         union fp_mant128 temp;
224         int exp;                                  224         int exp;
225                                                   225 
226         dprint(PINSTR, "fdiv\n");                 226         dprint(PINSTR, "fdiv\n");
227                                                   227 
228         fp_dyadic_check(dest, src);               228         fp_dyadic_check(dest, src);
229                                                   229 
230         /* calculate the correct sign now, as     230         /* calculate the correct sign now, as it's necessary for infinities */
231         dest->sign = src->sign ^ dest->sign;      231         dest->sign = src->sign ^ dest->sign;
232                                                   232 
233         /* Handle infinities */                   233         /* Handle infinities */
234         if (IS_INF(dest)) {                       234         if (IS_INF(dest)) {
235                 /* infinity / infinity = NaN (    235                 /* infinity / infinity = NaN (quiet, as always) */
236                 if (IS_INF(src))                  236                 if (IS_INF(src))
237                         fp_set_nan(dest);         237                         fp_set_nan(dest);
238                 /* infinity / anything else =     238                 /* infinity / anything else = infinity (with appropriate sign) */
239                 return dest;                      239                 return dest;
240         }                                         240         }
241         if (IS_INF(src)) {                        241         if (IS_INF(src)) {
242                 /* anything / infinity = zero     242                 /* anything / infinity = zero (with appropriate sign) */
243                 dest->exp = 0;                    243                 dest->exp = 0;
244                 dest->mant.m64 = 0;               244                 dest->mant.m64 = 0;
245                 dest->lowmant = 0;                245                 dest->lowmant = 0;
246                                                   246 
247                 return dest;                      247                 return dest;
248         }                                         248         }
249                                                   249 
250         /* zeroes */                              250         /* zeroes */
251         if (IS_ZERO(dest)) {                      251         if (IS_ZERO(dest)) {
252                 /* zero / zero = NaN */           252                 /* zero / zero = NaN */
253                 if (IS_ZERO(src))                 253                 if (IS_ZERO(src))
254                         fp_set_nan(dest);         254                         fp_set_nan(dest);
255                 /* zero / anything else = zero    255                 /* zero / anything else = zero */
256                 return dest;                      256                 return dest;
257         }                                         257         }
258         if (IS_ZERO(src)) {                       258         if (IS_ZERO(src)) {
259                 /* anything / zero = infinity     259                 /* anything / zero = infinity (with appropriate sign) */
260                 fp_set_sr(FPSR_EXC_DZ);           260                 fp_set_sr(FPSR_EXC_DZ);
261                 dest->exp = 0x7fff;               261                 dest->exp = 0x7fff;
262                 dest->mant.m64 = 0;               262                 dest->mant.m64 = 0;
263                                                   263 
264                 return dest;                      264                 return dest;
265         }                                         265         }
266                                                   266 
267         exp = dest->exp - src->exp + 0x3fff;      267         exp = dest->exp - src->exp + 0x3fff;
268                                                   268 
269         /* shift up the mantissa for denormali    269         /* shift up the mantissa for denormalized numbers,
270            so that the highest bit is set, thi    270            so that the highest bit is set, this makes lots
271            of things below easier */              271            of things below easier */
272         if ((long)dest->mant.m32[0] >= 0)         272         if ((long)dest->mant.m32[0] >= 0)
273                 exp -= fp_overnormalize(dest);    273                 exp -= fp_overnormalize(dest);
274         if ((long)src->mant.m32[0] >= 0)          274         if ((long)src->mant.m32[0] >= 0)
275                 exp -= fp_overnormalize(src);     275                 exp -= fp_overnormalize(src);
276                                                   276 
277         /* now, do the 64-bit divide */           277         /* now, do the 64-bit divide */
278         fp_dividemant(&temp, dest, src);          278         fp_dividemant(&temp, dest, src);
279                                                   279 
280         /* normalize it back to 64 bits and st    280         /* normalize it back to 64 bits and stuff it back into the
281            destination struct */                  281            destination struct */
282         if (!temp.m32[0]) {                       282         if (!temp.m32[0]) {
283                 exp--;                            283                 exp--;
284                 fp_putmant128(dest, &temp, 32)    284                 fp_putmant128(dest, &temp, 32);
285         } else                                    285         } else
286                 fp_putmant128(dest, &temp, 31)    286                 fp_putmant128(dest, &temp, 31);
287                                                   287 
288         if (exp >= 0x7fff) {                      288         if (exp >= 0x7fff) {
289                 fp_set_ovrflw(dest);              289                 fp_set_ovrflw(dest);
290                 return dest;                      290                 return dest;
291         }                                         291         }
292         dest->exp = exp;                          292         dest->exp = exp;
293         if (exp < 0) {                            293         if (exp < 0) {
294                 fp_set_sr(FPSR_EXC_UNFL);         294                 fp_set_sr(FPSR_EXC_UNFL);
295                 fp_denormalize(dest, -exp);       295                 fp_denormalize(dest, -exp);
296         }                                         296         }
297                                                   297 
298         return dest;                              298         return dest;
299 }                                                 299 }
300                                                   300 
301 struct fp_ext *fp_fsglmul(struct fp_ext *dest,    301 struct fp_ext *fp_fsglmul(struct fp_ext *dest, struct fp_ext *src)
302 {                                                 302 {
303         int exp;                                  303         int exp;
304                                                   304 
305         dprint(PINSTR, "fsglmul\n");              305         dprint(PINSTR, "fsglmul\n");
306                                                   306 
307         fp_dyadic_check(dest, src);               307         fp_dyadic_check(dest, src);
308                                                   308 
309         /* calculate the correct sign now, as     309         /* calculate the correct sign now, as it's necessary for infinities */
310         dest->sign = src->sign ^ dest->sign;      310         dest->sign = src->sign ^ dest->sign;
311                                                   311 
312         /* Handle infinities */                   312         /* Handle infinities */
313         if (IS_INF(dest)) {                       313         if (IS_INF(dest)) {
314                 if (IS_ZERO(src))                 314                 if (IS_ZERO(src))
315                         fp_set_nan(dest);         315                         fp_set_nan(dest);
316                 return dest;                      316                 return dest;
317         }                                         317         }
318         if (IS_INF(src)) {                        318         if (IS_INF(src)) {
319                 if (IS_ZERO(dest))                319                 if (IS_ZERO(dest))
320                         fp_set_nan(dest);         320                         fp_set_nan(dest);
321                 else                              321                 else
322                         fp_copy_ext(dest, src)    322                         fp_copy_ext(dest, src);
323                 return dest;                      323                 return dest;
324         }                                         324         }
325                                                   325 
326         /* Of course, as we all know, zero * a    326         /* Of course, as we all know, zero * anything = zero.  You may
327            not have known that it might be a p    327            not have known that it might be a positive or negative
328            zero... */                             328            zero... */
329         if (IS_ZERO(dest) || IS_ZERO(src)) {      329         if (IS_ZERO(dest) || IS_ZERO(src)) {
330                 dest->exp = 0;                    330                 dest->exp = 0;
331                 dest->mant.m64 = 0;               331                 dest->mant.m64 = 0;
332                 dest->lowmant = 0;                332                 dest->lowmant = 0;
333                                                   333 
334                 return dest;                      334                 return dest;
335         }                                         335         }
336                                                   336 
337         exp = dest->exp + src->exp - 0x3ffe;      337         exp = dest->exp + src->exp - 0x3ffe;
338                                                   338 
339         /* do a 32-bit multiply */                339         /* do a 32-bit multiply */
340         fp_mul64(dest->mant.m32[0], dest->mant    340         fp_mul64(dest->mant.m32[0], dest->mant.m32[1],
341                  dest->mant.m32[0] & 0xffffff0    341                  dest->mant.m32[0] & 0xffffff00,
342                  src->mant.m32[0] & 0xffffff00    342                  src->mant.m32[0] & 0xffffff00);
343                                                   343 
344         if (exp >= 0x7fff) {                      344         if (exp >= 0x7fff) {
345                 fp_set_ovrflw(dest);              345                 fp_set_ovrflw(dest);
346                 return dest;                      346                 return dest;
347         }                                         347         }
348         dest->exp = exp;                          348         dest->exp = exp;
349         if (exp < 0) {                            349         if (exp < 0) {
350                 fp_set_sr(FPSR_EXC_UNFL);         350                 fp_set_sr(FPSR_EXC_UNFL);
351                 fp_denormalize(dest, -exp);       351                 fp_denormalize(dest, -exp);
352         }                                         352         }
353                                                   353 
354         return dest;                              354         return dest;
355 }                                                 355 }
356                                                   356 
357 struct fp_ext *fp_fsgldiv(struct fp_ext *dest,    357 struct fp_ext *fp_fsgldiv(struct fp_ext *dest, struct fp_ext *src)
358 {                                                 358 {
359         int exp;                                  359         int exp;
360         unsigned long quot, rem;                  360         unsigned long quot, rem;
361                                                   361 
362         dprint(PINSTR, "fsgldiv\n");              362         dprint(PINSTR, "fsgldiv\n");
363                                                   363 
364         fp_dyadic_check(dest, src);               364         fp_dyadic_check(dest, src);
365                                                   365 
366         /* calculate the correct sign now, as     366         /* calculate the correct sign now, as it's necessary for infinities */
367         dest->sign = src->sign ^ dest->sign;      367         dest->sign = src->sign ^ dest->sign;
368                                                   368 
369         /* Handle infinities */                   369         /* Handle infinities */
370         if (IS_INF(dest)) {                       370         if (IS_INF(dest)) {
371                 /* infinity / infinity = NaN (    371                 /* infinity / infinity = NaN (quiet, as always) */
372                 if (IS_INF(src))                  372                 if (IS_INF(src))
373                         fp_set_nan(dest);         373                         fp_set_nan(dest);
374                 /* infinity / anything else =     374                 /* infinity / anything else = infinity (with approprate sign) */
375                 return dest;                      375                 return dest;
376         }                                         376         }
377         if (IS_INF(src)) {                        377         if (IS_INF(src)) {
378                 /* anything / infinity = zero     378                 /* anything / infinity = zero (with appropriate sign) */
379                 dest->exp = 0;                    379                 dest->exp = 0;
380                 dest->mant.m64 = 0;               380                 dest->mant.m64 = 0;
381                 dest->lowmant = 0;                381                 dest->lowmant = 0;
382                                                   382 
383                 return dest;                      383                 return dest;
384         }                                         384         }
385                                                   385 
386         /* zeroes */                              386         /* zeroes */
387         if (IS_ZERO(dest)) {                      387         if (IS_ZERO(dest)) {
388                 /* zero / zero = NaN */           388                 /* zero / zero = NaN */
389                 if (IS_ZERO(src))                 389                 if (IS_ZERO(src))
390                         fp_set_nan(dest);         390                         fp_set_nan(dest);
391                 /* zero / anything else = zero    391                 /* zero / anything else = zero */
392                 return dest;                      392                 return dest;
393         }                                         393         }
394         if (IS_ZERO(src)) {                       394         if (IS_ZERO(src)) {
395                 /* anything / zero = infinity     395                 /* anything / zero = infinity (with appropriate sign) */
396                 fp_set_sr(FPSR_EXC_DZ);           396                 fp_set_sr(FPSR_EXC_DZ);
397                 dest->exp = 0x7fff;               397                 dest->exp = 0x7fff;
398                 dest->mant.m64 = 0;               398                 dest->mant.m64 = 0;
399                                                   399 
400                 return dest;                      400                 return dest;
401         }                                         401         }
402                                                   402 
403         exp = dest->exp - src->exp + 0x3fff;      403         exp = dest->exp - src->exp + 0x3fff;
404                                                   404 
405         dest->mant.m32[0] &= 0xffffff00;          405         dest->mant.m32[0] &= 0xffffff00;
406         src->mant.m32[0] &= 0xffffff00;           406         src->mant.m32[0] &= 0xffffff00;
407                                                   407 
408         /* do the 32-bit divide */                408         /* do the 32-bit divide */
409         if (dest->mant.m32[0] >= src->mant.m32    409         if (dest->mant.m32[0] >= src->mant.m32[0]) {
410                 fp_sub64(dest->mant, src->mant    410                 fp_sub64(dest->mant, src->mant);
411                 fp_div64(quot, rem, dest->mant    411                 fp_div64(quot, rem, dest->mant.m32[0], 0, src->mant.m32[0]);
412                 dest->mant.m32[0] = 0x80000000    412                 dest->mant.m32[0] = 0x80000000 | (quot >> 1);
413                 dest->mant.m32[1] = (quot & 1)    413                 dest->mant.m32[1] = (quot & 1) | rem;   /* only for rounding */
414         } else {                                  414         } else {
415                 fp_div64(quot, rem, dest->mant    415                 fp_div64(quot, rem, dest->mant.m32[0], 0, src->mant.m32[0]);
416                 dest->mant.m32[0] = quot;         416                 dest->mant.m32[0] = quot;
417                 dest->mant.m32[1] = rem;          417                 dest->mant.m32[1] = rem;                /* only for rounding */
418                 exp--;                            418                 exp--;
419         }                                         419         }
420                                                   420 
421         if (exp >= 0x7fff) {                      421         if (exp >= 0x7fff) {
422                 fp_set_ovrflw(dest);              422                 fp_set_ovrflw(dest);
423                 return dest;                      423                 return dest;
424         }                                         424         }
425         dest->exp = exp;                          425         dest->exp = exp;
426         if (exp < 0) {                            426         if (exp < 0) {
427                 fp_set_sr(FPSR_EXC_UNFL);         427                 fp_set_sr(FPSR_EXC_UNFL);
428                 fp_denormalize(dest, -exp);       428                 fp_denormalize(dest, -exp);
429         }                                         429         }
430                                                   430 
431         return dest;                              431         return dest;
432 }                                                 432 }
433                                                   433 
434 /* fp_roundint: Internal rounding function for    434 /* fp_roundint: Internal rounding function for use by several of these
435    emulated instructions.                         435    emulated instructions.
436                                                   436 
437    This one rounds off the fractional part usi    437    This one rounds off the fractional part using the rounding mode
438    specified. */                                  438    specified. */
439                                                   439 
440 static void fp_roundint(struct fp_ext *dest, i    440 static void fp_roundint(struct fp_ext *dest, int mode)
441 {                                                 441 {
442         union fp_mant64 oldmant;                  442         union fp_mant64 oldmant;
443         unsigned long mask;                       443         unsigned long mask;
444                                                   444 
445         if (!fp_normalize_ext(dest))              445         if (!fp_normalize_ext(dest))
446                 return;                           446                 return;
447                                                   447 
448         /* infinities and zeroes */               448         /* infinities and zeroes */
449         if (IS_INF(dest) || IS_ZERO(dest))        449         if (IS_INF(dest) || IS_ZERO(dest))
450                 return;                           450                 return;
451                                                   451 
452         /* first truncate the lower bits */       452         /* first truncate the lower bits */
453         oldmant = dest->mant;                     453         oldmant = dest->mant;
454         switch (dest->exp) {                      454         switch (dest->exp) {
455         case 0 ... 0x3ffe:                        455         case 0 ... 0x3ffe:
456                 dest->mant.m64 = 0;               456                 dest->mant.m64 = 0;
457                 break;                            457                 break;
458         case 0x3fff ... 0x401e:                   458         case 0x3fff ... 0x401e:
459                 dest->mant.m32[0] &= 0xfffffff    459                 dest->mant.m32[0] &= 0xffffffffU << (0x401e - dest->exp);
460                 dest->mant.m32[1] = 0;            460                 dest->mant.m32[1] = 0;
461                 if (oldmant.m64 == dest->mant.    461                 if (oldmant.m64 == dest->mant.m64)
462                         return;                   462                         return;
463                 break;                            463                 break;
464         case 0x401f ... 0x403e:                   464         case 0x401f ... 0x403e:
465                 dest->mant.m32[1] &= 0xfffffff    465                 dest->mant.m32[1] &= 0xffffffffU << (0x403e - dest->exp);
466                 if (oldmant.m32[1] == dest->ma    466                 if (oldmant.m32[1] == dest->mant.m32[1])
467                         return;                   467                         return;
468                 break;                            468                 break;
469         default:                                  469         default:
470                 return;                           470                 return;
471         }                                         471         }
472         fp_set_sr(FPSR_EXC_INEX2);                472         fp_set_sr(FPSR_EXC_INEX2);
473                                                   473 
474         /* We might want to normalize upwards     474         /* We might want to normalize upwards here... however, since
475            we know that this is only called on    475            we know that this is only called on the output of fp_fdiv,
476            or with the input to fp_fint or fp_    476            or with the input to fp_fint or fp_fintrz, and the inputs
477            to all these functions are either n    477            to all these functions are either normal or denormalized
478            (no subnormals allowed!), there's r    478            (no subnormals allowed!), there's really no need.
479                                                   479 
480            In the case of fp_fdiv, observe tha    480            In the case of fp_fdiv, observe that 0x80000000 / 0xffff =
481            0xffff8000, and the same holds for     481            0xffff8000, and the same holds for 128-bit / 64-bit. (i.e. the
482            smallest possible normal dividend a    482            smallest possible normal dividend and the largest possible normal
483            divisor will still produce a normal    483            divisor will still produce a normal quotient, therefore, (normal
484            << 64) / normal is normal in all ca    484            << 64) / normal is normal in all cases) */
485                                                   485 
486         switch (mode) {                           486         switch (mode) {
487         case FPCR_ROUND_RN:                       487         case FPCR_ROUND_RN:
488                 switch (dest->exp) {              488                 switch (dest->exp) {
489                 case 0 ... 0x3ffd:                489                 case 0 ... 0x3ffd:
490                         return;                   490                         return;
491                 case 0x3ffe:                      491                 case 0x3ffe:
492                         /* As noted above, the    492                         /* As noted above, the input is always normal, so the
493                            guard bit (bit 63)     493                            guard bit (bit 63) is always set.  therefore, the
494                            only case in which     494                            only case in which we will NOT round to 1.0 is when
495                            the input is exactl    495                            the input is exactly 0.5. */
496                         if (oldmant.m64 == (1U    496                         if (oldmant.m64 == (1ULL << 63))
497                                 return;           497                                 return;
498                         break;                    498                         break;
499                 case 0x3fff ... 0x401d:           499                 case 0x3fff ... 0x401d:
500                         mask = 1 << (0x401d -     500                         mask = 1 << (0x401d - dest->exp);
501                         if (!(oldmant.m32[0] &    501                         if (!(oldmant.m32[0] & mask))
502                                 return;           502                                 return;
503                         if (oldmant.m32[0] & (    503                         if (oldmant.m32[0] & (mask << 1))
504                                 break;            504                                 break;
505                         if (!(oldmant.m32[0] <    505                         if (!(oldmant.m32[0] << (dest->exp - 0x3ffd)) &&
506                                         !oldma    506                                         !oldmant.m32[1])
507                                 return;           507                                 return;
508                         break;                    508                         break;
509                 case 0x401e:                      509                 case 0x401e:
510                         if (oldmant.m32[1] & 0    510                         if (oldmant.m32[1] & 0x80000000)
511                                 return;           511                                 return;
512                         if (oldmant.m32[0] & 1    512                         if (oldmant.m32[0] & 1)
513                                 break;            513                                 break;
514                         if (!(oldmant.m32[1] <    514                         if (!(oldmant.m32[1] << 1))
515                                 return;           515                                 return;
516                         break;                    516                         break;
517                 case 0x401f ... 0x403d:           517                 case 0x401f ... 0x403d:
518                         mask = 1 << (0x403d -     518                         mask = 1 << (0x403d - dest->exp);
519                         if (!(oldmant.m32[1] &    519                         if (!(oldmant.m32[1] & mask))
520                                 return;           520                                 return;
521                         if (oldmant.m32[1] & (    521                         if (oldmant.m32[1] & (mask << 1))
522                                 break;            522                                 break;
523                         if (!(oldmant.m32[1] <    523                         if (!(oldmant.m32[1] << (dest->exp - 0x401d)))
524                                 return;           524                                 return;
525                         break;                    525                         break;
526                 default:                          526                 default:
527                         return;                   527                         return;
528                 }                                 528                 }
529                 break;                            529                 break;
530         case FPCR_ROUND_RZ:                       530         case FPCR_ROUND_RZ:
531                 return;                           531                 return;
532         default:                                  532         default:
533                 if (dest->sign ^ (mode - FPCR_    533                 if (dest->sign ^ (mode - FPCR_ROUND_RM))
534                         break;                    534                         break;
535                 return;                           535                 return;
536         }                                         536         }
537                                                   537 
538         switch (dest->exp) {                      538         switch (dest->exp) {
539         case 0 ... 0x3ffe:                        539         case 0 ... 0x3ffe:
540                 dest->exp = 0x3fff;               540                 dest->exp = 0x3fff;
541                 dest->mant.m64 = 1ULL << 63;      541                 dest->mant.m64 = 1ULL << 63;
542                 break;                            542                 break;
543         case 0x3fff ... 0x401e:                   543         case 0x3fff ... 0x401e:
544                 mask = 1 << (0x401e - dest->ex    544                 mask = 1 << (0x401e - dest->exp);
545                 if (dest->mant.m32[0] += mask)    545                 if (dest->mant.m32[0] += mask)
546                         break;                    546                         break;
547                 dest->mant.m32[0] = 0x80000000    547                 dest->mant.m32[0] = 0x80000000;
548                 dest->exp++;                      548                 dest->exp++;
549                 break;                            549                 break;
550         case 0x401f ... 0x403e:                   550         case 0x401f ... 0x403e:
551                 mask = 1 << (0x403e - dest->ex    551                 mask = 1 << (0x403e - dest->exp);
552                 if (dest->mant.m32[1] += mask)    552                 if (dest->mant.m32[1] += mask)
553                         break;                    553                         break;
554                 if (dest->mant.m32[0] += 1)       554                 if (dest->mant.m32[0] += 1)
555                         break;                    555                         break;
556                 dest->mant.m32[0] = 0x80000000    556                 dest->mant.m32[0] = 0x80000000;
557                 dest->exp++;                      557                 dest->exp++;
558                 break;                            558                 break;
559         }                                         559         }
560 }                                                 560 }
561                                                   561 
562 /* modrem_kernel: Implementation of the FREM a    562 /* modrem_kernel: Implementation of the FREM and FMOD instructions
563    (which are exactly the same, except for the    563    (which are exactly the same, except for the rounding used on the
564    intermediate value) */                         564    intermediate value) */
565                                                   565 
566 static struct fp_ext *modrem_kernel(struct fp_    566 static struct fp_ext *modrem_kernel(struct fp_ext *dest, struct fp_ext *src,
567                                     int mode)     567                                     int mode)
568 {                                                 568 {
569         struct fp_ext tmp;                        569         struct fp_ext tmp;
570                                                   570 
571         fp_dyadic_check(dest, src);               571         fp_dyadic_check(dest, src);
572                                                   572 
573         /* Infinities and zeros */                573         /* Infinities and zeros */
574         if (IS_INF(dest) || IS_ZERO(src)) {       574         if (IS_INF(dest) || IS_ZERO(src)) {
575                 fp_set_nan(dest);                 575                 fp_set_nan(dest);
576                 return dest;                      576                 return dest;
577         }                                         577         }
578         if (IS_ZERO(dest) || IS_INF(src))         578         if (IS_ZERO(dest) || IS_INF(src))
579                 return dest;                      579                 return dest;
580                                                   580 
581         /* FIXME: there is almost certainly a     581         /* FIXME: there is almost certainly a smarter way to do this */
582         fp_copy_ext(&tmp, dest);                  582         fp_copy_ext(&tmp, dest);
583         fp_fdiv(&tmp, src);             /* NOT    583         fp_fdiv(&tmp, src);             /* NOTE: src might be modified */
584         fp_roundint(&tmp, mode);                  584         fp_roundint(&tmp, mode);
585         fp_fmul(&tmp, src);                       585         fp_fmul(&tmp, src);
586         fp_fsub(dest, &tmp);                      586         fp_fsub(dest, &tmp);
587                                                   587 
588         /* set the quotient byte */               588         /* set the quotient byte */
589         fp_set_quotient((dest->mant.m64 & 0x7f    589         fp_set_quotient((dest->mant.m64 & 0x7f) | (dest->sign << 7));
590         return dest;                              590         return dest;
591 }                                                 591 }
592                                                   592 
593 /* fp_fmod: Implements the kernel of the FMOD     593 /* fp_fmod: Implements the kernel of the FMOD instruction.
594                                                   594 
595    Again, the argument order is backwards.  Th    595    Again, the argument order is backwards.  The result, as defined in
596    the Motorola manuals, is:                      596    the Motorola manuals, is:
597                                                   597 
598    fmod(src,dest) = (dest - (src * floor(dest     598    fmod(src,dest) = (dest - (src * floor(dest / src))) */
599                                                   599 
600 struct fp_ext *fp_fmod(struct fp_ext *dest, st    600 struct fp_ext *fp_fmod(struct fp_ext *dest, struct fp_ext *src)
601 {                                                 601 {
602         dprint(PINSTR, "fmod\n");                 602         dprint(PINSTR, "fmod\n");
603         return modrem_kernel(dest, src, FPCR_R    603         return modrem_kernel(dest, src, FPCR_ROUND_RZ);
604 }                                                 604 }
605                                                   605 
606 /* fp_frem: Implements the kernel of the FREM     606 /* fp_frem: Implements the kernel of the FREM instruction.
607                                                   607 
608    frem(src,dest) = (dest - (src * round(dest     608    frem(src,dest) = (dest - (src * round(dest / src)))
609  */                                               609  */
610                                                   610 
611 struct fp_ext *fp_frem(struct fp_ext *dest, st    611 struct fp_ext *fp_frem(struct fp_ext *dest, struct fp_ext *src)
612 {                                                 612 {
613         dprint(PINSTR, "frem\n");                 613         dprint(PINSTR, "frem\n");
614         return modrem_kernel(dest, src, FPCR_R    614         return modrem_kernel(dest, src, FPCR_ROUND_RN);
615 }                                                 615 }
616                                                   616 
617 struct fp_ext *fp_fint(struct fp_ext *dest, st    617 struct fp_ext *fp_fint(struct fp_ext *dest, struct fp_ext *src)
618 {                                                 618 {
619         dprint(PINSTR, "fint\n");                 619         dprint(PINSTR, "fint\n");
620                                                   620 
621         fp_copy_ext(dest, src);                   621         fp_copy_ext(dest, src);
622                                                   622 
623         fp_roundint(dest, FPDATA->rnd);           623         fp_roundint(dest, FPDATA->rnd);
624                                                   624 
625         return dest;                              625         return dest;
626 }                                                 626 }
627                                                   627 
628 struct fp_ext *fp_fintrz(struct fp_ext *dest,     628 struct fp_ext *fp_fintrz(struct fp_ext *dest, struct fp_ext *src)
629 {                                                 629 {
630         dprint(PINSTR, "fintrz\n");               630         dprint(PINSTR, "fintrz\n");
631                                                   631 
632         fp_copy_ext(dest, src);                   632         fp_copy_ext(dest, src);
633                                                   633 
634         fp_roundint(dest, FPCR_ROUND_RZ);         634         fp_roundint(dest, FPCR_ROUND_RZ);
635                                                   635 
636         return dest;                              636         return dest;
637 }                                                 637 }
638                                                   638 
639 struct fp_ext *fp_fscale(struct fp_ext *dest,     639 struct fp_ext *fp_fscale(struct fp_ext *dest, struct fp_ext *src)
640 {                                                 640 {
641         int scale, oldround;                      641         int scale, oldround;
642                                                   642 
643         dprint(PINSTR, "fscale\n");               643         dprint(PINSTR, "fscale\n");
644                                                   644 
645         fp_dyadic_check(dest, src);               645         fp_dyadic_check(dest, src);
646                                                   646 
647         /* Infinities */                          647         /* Infinities */
648         if (IS_INF(src)) {                        648         if (IS_INF(src)) {
649                 fp_set_nan(dest);                 649                 fp_set_nan(dest);
650                 return dest;                      650                 return dest;
651         }                                         651         }
652         if (IS_INF(dest))                         652         if (IS_INF(dest))
653                 return dest;                      653                 return dest;
654                                                   654 
655         /* zeroes */                              655         /* zeroes */
656         if (IS_ZERO(src) || IS_ZERO(dest))        656         if (IS_ZERO(src) || IS_ZERO(dest))
657                 return dest;                      657                 return dest;
658                                                   658 
659         /* Source exponent out of range */        659         /* Source exponent out of range */
660         if (src->exp >= 0x400c) {                 660         if (src->exp >= 0x400c) {
661                 fp_set_ovrflw(dest);              661                 fp_set_ovrflw(dest);
662                 return dest;                      662                 return dest;
663         }                                         663         }
664                                                   664 
665         /* src must be rounded with round to z    665         /* src must be rounded with round to zero. */
666         oldround = FPDATA->rnd;                   666         oldround = FPDATA->rnd;
667         FPDATA->rnd = FPCR_ROUND_RZ;              667         FPDATA->rnd = FPCR_ROUND_RZ;
668         scale = fp_conv_ext2long(src);            668         scale = fp_conv_ext2long(src);
669         FPDATA->rnd = oldround;                   669         FPDATA->rnd = oldround;
670                                                   670 
671         /* new exponent */                        671         /* new exponent */
672         scale += dest->exp;                       672         scale += dest->exp;
673                                                   673 
674         if (scale >= 0x7fff) {                    674         if (scale >= 0x7fff) {
675                 fp_set_ovrflw(dest);              675                 fp_set_ovrflw(dest);
676         } else if (scale <= 0) {                  676         } else if (scale <= 0) {
677                 fp_set_sr(FPSR_EXC_UNFL);         677                 fp_set_sr(FPSR_EXC_UNFL);
678                 fp_denormalize(dest, -scale);     678                 fp_denormalize(dest, -scale);
679         } else                                    679         } else
680                 dest->exp = scale;                680                 dest->exp = scale;
681                                                   681 
682         return dest;                              682         return dest;
683 }                                                 683 }
684                                                   684 
685                                                   685 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php