1 /* single and double precision fp ops 2 * missing extended precision. 3 */ 4 /* 5 * MIPS floating point support 6 * Copyright (C) 1994-2000 Algorithmics Ltd. 7 * http://www.algor.co.uk 8 * 9 * ######################################################################## 10 * 11 * This program is free software; you can distribute it and/or modify it 12 * under the terms of the GNU General Public License (Version 2) as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope it will be useful, but WITHOUT 16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18 * for more details. 19 * 20 * You should have received a copy of the GNU General Public License along 21 * with this program; if not, write to the Free Software Foundation, Inc., 22 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 23 * 24 * ######################################################################## 25 */ 26 27 /************************************************************************** 28 * Nov 7, 2000 29 * Modification to allow integration with Linux kernel 30 * 31 * Kevin D. Kissell, kevink@mips.com and Carsten Langgard, carstenl@mips.com 32 * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. 33 *************************************************************************/ 34 35 #ifdef __KERNEL__ 36 /* Going from Algorithmics to Linux native environment, add this */ 37 #include <linux/types.h> 38 39 /* 40 * Not very pretty, but the Linux kernel's normal va_list definition 41 * does not allow it to be used as a structure element, as it is here. 42 */ 43 #ifndef _STDARG_H 44 #include <stdarg.h> 45 #endif 46 47 #else 48 49 /* Note that __KERNEL__ is taken to mean Linux kernel */ 50 51 #if #system(OpenBSD) 52 #include <machine/types.h> 53 #endif 54 #include <machine/endian.h> 55 56 #endif /* __KERNEL__ */ 57 58 #if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) 59 struct ieee754dp_konst { 60 unsigned mantlo:32; 61 unsigned manthi:20; 62 unsigned bexp:11; 63 unsigned sign:1; 64 }; 65 struct ieee754sp_konst { 66 unsigned mant:23; 67 unsigned bexp:8; 68 unsigned sign:1; 69 }; 70 71 typedef union _ieee754dp { 72 struct ieee754dp_konst oparts; 73 struct { 74 u64 mant:52; 75 unsigned int bexp:11; 76 unsigned int sign:1; 77 } parts; 78 u64 bits; 79 double d; 80 } ieee754dp; 81 82 typedef union _ieee754sp { 83 struct ieee754sp_konst parts; 84 float f; 85 u32 bits; 86 } ieee754sp; 87 #endif 88 89 #if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) 90 struct ieee754dp_konst { 91 unsigned sign:1; 92 unsigned bexp:11; 93 unsigned manthi:20; 94 unsigned mantlo:32; 95 }; 96 typedef union _ieee754dp { 97 struct ieee754dp_konst oparts; 98 struct { 99 unsigned int sign:1; 100 unsigned int bexp:11; 101 u64 mant:52; 102 } parts; 103 double d; 104 u64 bits; 105 } ieee754dp; 106 107 struct ieee754sp_konst { 108 unsigned sign:1; 109 unsigned bexp:8; 110 unsigned mant:23; 111 }; 112 113 typedef union _ieee754sp { 114 struct ieee754sp_konst parts; 115 float f; 116 u32 bits; 117 } ieee754sp; 118 #endif 119 120 /* 121 * single precision (often aka float) 122 */ 123 int ieee754sp_finite(ieee754sp x); 124 int ieee754sp_class(ieee754sp x); 125 126 ieee754sp ieee754sp_abs(ieee754sp x); 127 ieee754sp ieee754sp_neg(ieee754sp x); 128 ieee754sp ieee754sp_scalb(ieee754sp x, int); 129 ieee754sp ieee754sp_logb(ieee754sp x); 130 131 /* x with sign of y */ 132 ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y); 133 134 ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y); 135 ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y); 136 ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y); 137 ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y); 138 139 ieee754sp ieee754sp_fint(int x); 140 ieee754sp ieee754sp_funs(unsigned x); 141 ieee754sp ieee754sp_flong(s64 x); 142 ieee754sp ieee754sp_fulong(u64 x); 143 ieee754sp ieee754sp_fdp(ieee754dp x); 144 145 int ieee754sp_tint(ieee754sp x); 146 unsigned int ieee754sp_tuns(ieee754sp x); 147 s64 ieee754sp_tlong(ieee754sp x); 148 u64 ieee754sp_tulong(ieee754sp x); 149 150 int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cop, int sig); 151 /* 152 * basic sp math 153 */ 154 ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip); 155 ieee754sp ieee754sp_frexp(ieee754sp x, int *exp); 156 ieee754sp ieee754sp_ldexp(ieee754sp x, int exp); 157 158 ieee754sp ieee754sp_ceil(ieee754sp x); 159 ieee754sp ieee754sp_floor(ieee754sp x); 160 ieee754sp ieee754sp_trunc(ieee754sp x); 161 162 ieee754sp ieee754sp_sqrt(ieee754sp x); 163 164 /* 165 * double precision (often aka double) 166 */ 167 int ieee754dp_finite(ieee754dp x); 168 int ieee754dp_class(ieee754dp x); 169 170 /* x with sign of y */ 171 ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y); 172 173 ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y); 174 ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y); 175 ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y); 176 ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y); 177 178 ieee754dp ieee754dp_abs(ieee754dp x); 179 ieee754dp ieee754dp_neg(ieee754dp x); 180 ieee754dp ieee754dp_scalb(ieee754dp x, int); 181 182 /* return exponent as integer in floating point format 183 */ 184 ieee754dp ieee754dp_logb(ieee754dp x); 185 186 ieee754dp ieee754dp_fint(int x); 187 ieee754dp ieee754dp_funs(unsigned x); 188 ieee754dp ieee754dp_flong(s64 x); 189 ieee754dp ieee754dp_fulong(u64 x); 190 ieee754dp ieee754dp_fsp(ieee754sp x); 191 192 ieee754dp ieee754dp_ceil(ieee754dp x); 193 ieee754dp ieee754dp_floor(ieee754dp x); 194 ieee754dp ieee754dp_trunc(ieee754dp x); 195 196 int ieee754dp_tint(ieee754dp x); 197 unsigned int ieee754dp_tuns(ieee754dp x); 198 s64 ieee754dp_tlong(ieee754dp x); 199 u64 ieee754dp_tulong(ieee754dp x); 200 201 int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop, int sig); 202 /* 203 * basic sp math 204 */ 205 ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip); 206 ieee754dp ieee754dp_frexp(ieee754dp x, int *exp); 207 ieee754dp ieee754dp_ldexp(ieee754dp x, int exp); 208 209 ieee754dp ieee754dp_ceil(ieee754dp x); 210 ieee754dp ieee754dp_floor(ieee754dp x); 211 ieee754dp ieee754dp_trunc(ieee754dp x); 212 213 ieee754dp ieee754dp_sqrt(ieee754dp x); 214 215 216 217 /* 5 types of floating point number 218 */ 219 #define IEEE754_CLASS_NORM 0x00 220 #define IEEE754_CLASS_ZERO 0x01 221 #define IEEE754_CLASS_DNORM 0x02 222 #define IEEE754_CLASS_INF 0x03 223 #define IEEE754_CLASS_SNAN 0x04 224 #define IEEE754_CLASS_QNAN 0x05 225 extern const char *const ieee754_cname[]; 226 227 /* exception numbers */ 228 #define IEEE754_INEXACT 0x01 229 #define IEEE754_UNDERFLOW 0x02 230 #define IEEE754_OVERFLOW 0x04 231 #define IEEE754_ZERO_DIVIDE 0x08 232 #define IEEE754_INVALID_OPERATION 0x10 233 234 /* cmp operators 235 */ 236 #define IEEE754_CLT 0x01 237 #define IEEE754_CEQ 0x02 238 #define IEEE754_CGT 0x04 239 #define IEEE754_CUN 0x08 240 241 /* rounding mode 242 */ 243 #define IEEE754_RN 0 /* round to nearest */ 244 #define IEEE754_RZ 1 /* round toward zero */ 245 #define IEEE754_RD 2 /* round toward -Infinity */ 246 #define IEEE754_RU 3 /* round toward +Infinity */ 247 248 /* other naming */ 249 #define IEEE754_RM IEEE754_RD 250 #define IEEE754_RP IEEE754_RU 251 252 /* "normal" comparisons 253 */ 254 static __inline int ieee754sp_eq(ieee754sp x, ieee754sp y) 255 { 256 return ieee754sp_cmp(x, y, IEEE754_CEQ, 0); 257 } 258 259 static __inline int ieee754sp_ne(ieee754sp x, ieee754sp y) 260 { 261 return ieee754sp_cmp(x, y, 262 IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0); 263 } 264 265 static __inline int ieee754sp_lt(ieee754sp x, ieee754sp y) 266 { 267 return ieee754sp_cmp(x, y, IEEE754_CLT, 0); 268 } 269 270 static __inline int ieee754sp_le(ieee754sp x, ieee754sp y) 271 { 272 return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0); 273 } 274 275 static __inline int ieee754sp_gt(ieee754sp x, ieee754sp y) 276 { 277 return ieee754sp_cmp(x, y, IEEE754_CGT, 0); 278 } 279 280 281 static __inline int ieee754sp_ge(ieee754sp x, ieee754sp y) 282 { 283 return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0); 284 } 285 286 static __inline int ieee754dp_eq(ieee754dp x, ieee754dp y) 287 { 288 return ieee754dp_cmp(x, y, IEEE754_CEQ, 0); 289 } 290 291 static __inline int ieee754dp_ne(ieee754dp x, ieee754dp y) 292 { 293 return ieee754dp_cmp(x, y, 294 IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0); 295 } 296 297 static __inline int ieee754dp_lt(ieee754dp x, ieee754dp y) 298 { 299 return ieee754dp_cmp(x, y, IEEE754_CLT, 0); 300 } 301 302 static __inline int ieee754dp_le(ieee754dp x, ieee754dp y) 303 { 304 return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0); 305 } 306 307 static __inline int ieee754dp_gt(ieee754dp x, ieee754dp y) 308 { 309 return ieee754dp_cmp(x, y, IEEE754_CGT, 0); 310 } 311 312 static __inline int ieee754dp_ge(ieee754dp x, ieee754dp y) 313 { 314 return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0); 315 } 316 317 318 /* like strtod 319 */ 320 ieee754dp ieee754dp_fstr(const char *s, char **endp); 321 char *ieee754dp_tstr(ieee754dp x, int prec, int fmt, int af); 322 323 324 /* the control status register 325 */ 326 struct ieee754_csr { 327 unsigned pad:13; 328 unsigned nod:1; /* set 1 for no denormalised numbers */ 329 unsigned cx:5; /* exceptions this operation */ 330 unsigned mx:5; /* exception enable mask */ 331 unsigned sx:5; /* exceptions total */ 332 unsigned rm:2; /* current rounding mode */ 333 }; 334 extern struct ieee754_csr ieee754_csr; 335 336 static __inline unsigned ieee754_getrm(void) 337 { 338 return (ieee754_csr.rm); 339 } 340 static __inline unsigned ieee754_setrm(unsigned rm) 341 { 342 return (ieee754_csr.rm = rm); 343 } 344 345 /* 346 * get current exceptions 347 */ 348 static __inline unsigned ieee754_getcx(void) 349 { 350 return (ieee754_csr.cx); 351 } 352 353 /* test for current exception condition 354 */ 355 static __inline int ieee754_cxtest(unsigned n) 356 { 357 return (ieee754_csr.cx & n); 358 } 359 360 /* 361 * get sticky exceptions 362 */ 363 static __inline unsigned ieee754_getsx(void) 364 { 365 return (ieee754_csr.sx); 366 } 367 368 /* clear sticky conditions 369 */ 370 static __inline unsigned ieee754_clrsx(void) 371 { 372 return (ieee754_csr.sx = 0); 373 } 374 375 /* test for sticky exception condition 376 */ 377 static __inline int ieee754_sxtest(unsigned n) 378 { 379 return (ieee754_csr.sx & n); 380 } 381 382 /* debugging */ 383 ieee754sp ieee754sp_dump(char *s, ieee754sp x); 384 ieee754dp ieee754dp_dump(char *s, ieee754dp x); 385 386 #define IEEE754_SPCVAL_PZERO 0 387 #define IEEE754_SPCVAL_NZERO 1 388 #define IEEE754_SPCVAL_PONE 2 389 #define IEEE754_SPCVAL_NONE 3 390 #define IEEE754_SPCVAL_PTEN 4 391 #define IEEE754_SPCVAL_NTEN 5 392 #define IEEE754_SPCVAL_PINFINITY 6 393 #define IEEE754_SPCVAL_NINFINITY 7 394 #define IEEE754_SPCVAL_INDEF 8 395 #define IEEE754_SPCVAL_PMAX 9 /* +max norm */ 396 #define IEEE754_SPCVAL_NMAX 10 /* -max norm */ 397 #define IEEE754_SPCVAL_PMIN 11 /* +min norm */ 398 #define IEEE754_SPCVAL_NMIN 12 /* +min norm */ 399 #define IEEE754_SPCVAL_PMIND 13 /* +min denorm */ 400 #define IEEE754_SPCVAL_NMIND 14 /* +min denorm */ 401 #define IEEE754_SPCVAL_P1E31 15 /* + 1.0e31 */ 402 #define IEEE754_SPCVAL_P1E63 16 /* + 1.0e63 */ 403 404 extern const struct ieee754dp_konst __ieee754dp_spcvals[]; 405 extern const struct ieee754sp_konst __ieee754sp_spcvals[]; 406 #define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals) 407 #define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals) 408 409 /* return infinity with given sign 410 */ 411 #define ieee754dp_inf(sn) \ 412 (ieee754dp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) 413 #define ieee754dp_zero(sn) \ 414 (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) 415 #define ieee754dp_one(sn) \ 416 (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) 417 #define ieee754dp_ten(sn) \ 418 (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) 419 #define ieee754dp_indef() \ 420 (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF]) 421 #define ieee754dp_max(sn) \ 422 (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) 423 #define ieee754dp_min(sn) \ 424 (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) 425 #define ieee754dp_mind(sn) \ 426 (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) 427 #define ieee754dp_1e31() \ 428 (ieee754dp_spcvals[IEEE754_SPCVAL_P1E31]) 429 #define ieee754dp_1e63() \ 430 (ieee754dp_spcvals[IEEE754_SPCVAL_P1E63]) 431 432 #define ieee754sp_inf(sn) \ 433 (ieee754sp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) 434 #define ieee754sp_zero(sn) \ 435 (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) 436 #define ieee754sp_one(sn) \ 437 (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) 438 #define ieee754sp_ten(sn) \ 439 (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) 440 #define ieee754sp_indef() \ 441 (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF]) 442 #define ieee754sp_max(sn) \ 443 (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) 444 #define ieee754sp_min(sn) \ 445 (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) 446 #define ieee754sp_mind(sn) \ 447 (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) 448 #define ieee754sp_1e31() \ 449 (ieee754sp_spcvals[IEEE754_SPCVAL_P1E31]) 450 #define ieee754sp_1e63() \ 451 (ieee754sp_spcvals[IEEE754_SPCVAL_P1E63]) 452 453 /* indefinite integer value 454 */ 455 #define ieee754si_indef() INT_MAX 456 #ifdef LONG_LONG_MAX 457 #define ieee754di_indef() LONG_LONG_MAX 458 #else 459 #define ieee754di_indef() ((s64)(~0ULL>>1)) 460 #endif 461 462 /* IEEE exception context, passed to handler */ 463 struct ieee754xctx { 464 const char *op; /* operation name */ 465 int rt; /* result type */ 466 union { 467 ieee754sp sp; /* single precision */ 468 ieee754dp dp; /* double precision */ 469 #ifdef IEEE854_XP 470 ieee754xp xp; /* extended precision */ 471 #endif 472 int si; /* standard signed integer (32bits) */ 473 s64 di; /* extended signed integer (64bits) */ 474 } rv; /* default result format implied by op */ 475 va_list ap; 476 }; 477 478 /* result types for xctx.rt */ 479 #define IEEE754_RT_SP 0 480 #define IEEE754_RT_DP 1 481 #define IEEE754_RT_XP 2 482 #define IEEE754_RT_SI 3 483 #define IEEE754_RT_DI 4 484 485 extern void ieee754_xcpt(struct ieee754xctx *xcp); 486 487 /* compat */ 488 #define ieee754dp_fix(x) ieee754dp_tint(x) 489 #define ieee754sp_fix(x) ieee754sp_tint(x) 490