fpu_implode.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. /* $NetBSD: fpu_implode.c,v 1.6 2005/12/11 12:18:42 christos Exp $ */
  2. /*-
  3. * SPDX-License-Identifier: BSD-3-Clause
  4. *
  5. * Copyright (c) 1992, 1993
  6. * The Regents of the University of California. All rights reserved.
  7. *
  8. * This software was developed by the Computer Systems Engineering group
  9. * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
  10. * contributed to Berkeley.
  11. *
  12. * All advertising materials mentioning features or use of this software
  13. * must display the following acknowledgement:
  14. * This product includes software developed by the University of
  15. * California, Lawrence Berkeley Laboratory.
  16. *
  17. * Redistribution and use in source and binary forms, with or without
  18. * modification, are permitted provided that the following conditions
  19. * are met:
  20. * 1. Redistributions of source code must retain the above copyright
  21. * notice, this list of conditions and the following disclaimer.
  22. * 2. Redistributions in binary form must reproduce the above copyright
  23. * notice, this list of conditions and the following disclaimer in the
  24. * documentation and/or other materials provided with the distribution.
  25. * 3. Neither the name of the University nor the names of its contributors
  26. * may be used to endorse or promote products derived from this software
  27. * without specific prior written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  30. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  31. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  32. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  33. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  34. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  35. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  36. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  37. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  38. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  39. * SUCH DAMAGE.
  40. *
  41. * @(#)fpu_implode.c 8.1 (Berkeley) 6/11/93
  42. */
  43. /*
  44. * FPU subroutines: `implode' internal format numbers into the machine's
  45. * `packed binary' format.
  46. */
  47. #include <sys/cdefs.h>
  48. __FBSDID("$FreeBSD$");
  49. #include <sys/types.h>
  50. #include <sys/systm.h>
  51. #include <machine/fpu.h>
  52. #include <machine/ieee.h>
  53. #include <machine/ieeefp.h>
  54. #include <machine/reg.h>
  55. #include <powerpc/fpu/fpu_arith.h>
  56. #include <powerpc/fpu/fpu_emu.h>
  57. #include <powerpc/fpu/fpu_extern.h>
  58. #include <powerpc/fpu/fpu_instr.h>
  59. static int round(struct fpemu *, struct fpn *);
  60. static int toinf(struct fpemu *, int);
  61. /*
  62. * Round a number (algorithm from Motorola MC68882 manual, modified for
  63. * our internal format). Set inexact exception if rounding is required.
  64. * Return true iff we rounded up.
  65. *
  66. * After rounding, we discard the guard and round bits by shifting right
  67. * 2 bits (a la fpu_shr(), but we do not bother with fp->fp_sticky).
  68. * This saves effort later.
  69. *
  70. * Note that we may leave the value 2.0 in fp->fp_mant; it is the caller's
  71. * responsibility to fix this if necessary.
  72. */
  73. static int
  74. round(struct fpemu *fe, struct fpn *fp)
  75. {
  76. u_int m0, m1, m2, m3;
  77. int gr, s;
  78. FPU_DECL_CARRY;
  79. m0 = fp->fp_mant[0];
  80. m1 = fp->fp_mant[1];
  81. m2 = fp->fp_mant[2];
  82. m3 = fp->fp_mant[3];
  83. gr = m3 & 3;
  84. s = fp->fp_sticky;
  85. /* mant >>= FP_NG */
  86. m3 = (m3 >> FP_NG) | (m2 << (32 - FP_NG));
  87. m2 = (m2 >> FP_NG) | (m1 << (32 - FP_NG));
  88. m1 = (m1 >> FP_NG) | (m0 << (32 - FP_NG));
  89. m0 >>= FP_NG;
  90. if ((gr | s) == 0) /* result is exact: no rounding needed */
  91. goto rounddown;
  92. fe->fe_cx |= FPSCR_XX|FPSCR_FI; /* inexact */
  93. /* Go to rounddown to round down; break to round up. */
  94. switch ((fe->fe_fpscr) & FPSCR_RN) {
  95. case FP_RN:
  96. default:
  97. /*
  98. * Round only if guard is set (gr & 2). If guard is set,
  99. * but round & sticky both clear, then we want to round
  100. * but have a tie, so round to even, i.e., add 1 iff odd.
  101. */
  102. if ((gr & 2) == 0)
  103. goto rounddown;
  104. if ((gr & 1) || fp->fp_sticky || (m3 & 1))
  105. break;
  106. goto rounddown;
  107. case FP_RZ:
  108. /* Round towards zero, i.e., down. */
  109. goto rounddown;
  110. case FP_RM:
  111. /* Round towards -Inf: up if negative, down if positive. */
  112. if (fp->fp_sign)
  113. break;
  114. goto rounddown;
  115. case FP_RP:
  116. /* Round towards +Inf: up if positive, down otherwise. */
  117. if (!fp->fp_sign)
  118. break;
  119. goto rounddown;
  120. }
  121. /* Bump low bit of mantissa, with carry. */
  122. fe->fe_cx |= FPSCR_FR;
  123. FPU_ADDS(m3, m3, 1);
  124. FPU_ADDCS(m2, m2, 0);
  125. FPU_ADDCS(m1, m1, 0);
  126. FPU_ADDC(m0, m0, 0);
  127. fp->fp_mant[0] = m0;
  128. fp->fp_mant[1] = m1;
  129. fp->fp_mant[2] = m2;
  130. fp->fp_mant[3] = m3;
  131. return (1);
  132. rounddown:
  133. fp->fp_mant[0] = m0;
  134. fp->fp_mant[1] = m1;
  135. fp->fp_mant[2] = m2;
  136. fp->fp_mant[3] = m3;
  137. return (0);
  138. }
  139. /*
  140. * For overflow: return true if overflow is to go to +/-Inf, according
  141. * to the sign of the overflowing result. If false, overflow is to go
  142. * to the largest magnitude value instead.
  143. */
  144. static int
  145. toinf(struct fpemu *fe, int sign)
  146. {
  147. int inf;
  148. /* look at rounding direction */
  149. switch ((fe->fe_fpscr) & FPSCR_RN) {
  150. default:
  151. case FP_RN: /* the nearest value is always Inf */
  152. inf = 1;
  153. break;
  154. case FP_RZ: /* toward 0 => never towards Inf */
  155. inf = 0;
  156. break;
  157. case FP_RP: /* toward +Inf iff positive */
  158. inf = sign == 0;
  159. break;
  160. case FP_RM: /* toward -Inf iff negative */
  161. inf = sign;
  162. break;
  163. }
  164. if (inf)
  165. fe->fe_cx |= FPSCR_OX;
  166. return (inf);
  167. }
  168. /*
  169. * fpn -> int (int value returned as return value).
  170. *
  171. * N.B.: this conversion always rounds towards zero (this is a peculiarity
  172. * of the SPARC instruction set).
  173. */
  174. u_int
  175. fpu_ftoi(struct fpemu *fe, struct fpn *fp)
  176. {
  177. u_int i;
  178. int sign, exp;
  179. sign = fp->fp_sign;
  180. switch (fp->fp_class) {
  181. case FPC_ZERO:
  182. return (0);
  183. case FPC_NUM:
  184. /*
  185. * If exp >= 2^32, overflow. Otherwise shift value right
  186. * into last mantissa word (this will not exceed 0xffffffff),
  187. * shifting any guard and round bits out into the sticky
  188. * bit. Then ``round'' towards zero, i.e., just set an
  189. * inexact exception if sticky is set (see round()).
  190. * If the result is > 0x80000000, or is positive and equals
  191. * 0x80000000, overflow; otherwise the last fraction word
  192. * is the result.
  193. */
  194. if ((exp = fp->fp_exp) >= 32)
  195. break;
  196. /* NB: the following includes exp < 0 cases */
  197. if (fpu_shr(fp, FP_NMANT - 1 - exp) != 0)
  198. fe->fe_cx |= FPSCR_UX;
  199. i = fp->fp_mant[3];
  200. if (i >= ((u_int)0x80000000 + sign))
  201. break;
  202. return (sign ? -i : i);
  203. default: /* Inf, qNaN, sNaN */
  204. break;
  205. }
  206. /* overflow: replace any inexact exception with invalid */
  207. fe->fe_cx |= FPSCR_VXCVI;
  208. return (0x7fffffff + sign);
  209. }
  210. /*
  211. * fpn -> extended int (high bits of int value returned as return value).
  212. *
  213. * N.B.: this conversion always rounds towards zero (this is a peculiarity
  214. * of the SPARC instruction set).
  215. */
  216. u_int
  217. fpu_ftox(struct fpemu *fe, struct fpn *fp, u_int *res)
  218. {
  219. u_int64_t i;
  220. int sign, exp;
  221. sign = fp->fp_sign;
  222. switch (fp->fp_class) {
  223. case FPC_ZERO:
  224. res[1] = 0;
  225. return (0);
  226. case FPC_NUM:
  227. /*
  228. * If exp >= 2^64, overflow. Otherwise shift value right
  229. * into last mantissa word (this will not exceed 0xffffffffffffffff),
  230. * shifting any guard and round bits out into the sticky
  231. * bit. Then ``round'' towards zero, i.e., just set an
  232. * inexact exception if sticky is set (see round()).
  233. * If the result is > 0x8000000000000000, or is positive and equals
  234. * 0x8000000000000000, overflow; otherwise the last fraction word
  235. * is the result.
  236. */
  237. if ((exp = fp->fp_exp) >= 64)
  238. break;
  239. /* NB: the following includes exp < 0 cases */
  240. if (fpu_shr(fp, FP_NMANT - 1 - exp) != 0)
  241. fe->fe_cx |= FPSCR_UX;
  242. i = ((u_int64_t)fp->fp_mant[2]<<32)|fp->fp_mant[3];
  243. if (i >= ((u_int64_t)0x8000000000000000LL + sign))
  244. break;
  245. return (sign ? -i : i);
  246. default: /* Inf, qNaN, sNaN */
  247. break;
  248. }
  249. /* overflow: replace any inexact exception with invalid */
  250. fe->fe_cx |= FPSCR_VXCVI;
  251. return (0x7fffffffffffffffLL + sign);
  252. }
  253. /*
  254. * fpn -> single (32 bit single returned as return value).
  255. * We assume <= 29 bits in a single-precision fraction (1.f part).
  256. */
  257. u_int
  258. fpu_ftos(struct fpemu *fe, struct fpn *fp)
  259. {
  260. u_int sign = fp->fp_sign << 31;
  261. int exp;
  262. #define SNG_EXP(e) ((e) << SNG_FRACBITS) /* makes e an exponent */
  263. #define SNG_MASK (SNG_EXP(1) - 1) /* mask for fraction */
  264. /* Take care of non-numbers first. */
  265. if (ISNAN(fp)) {
  266. /*
  267. * Preserve upper bits of NaN, per SPARC V8 appendix N.
  268. * Note that fp->fp_mant[0] has the quiet bit set,
  269. * even if it is classified as a signalling NaN.
  270. */
  271. (void) fpu_shr(fp, FP_NMANT - 1 - SNG_FRACBITS);
  272. exp = SNG_EXP_INFNAN;
  273. goto done;
  274. }
  275. if (ISINF(fp))
  276. return (sign | SNG_EXP(SNG_EXP_INFNAN));
  277. if (ISZERO(fp))
  278. return (sign);
  279. /*
  280. * Normals (including subnormals). Drop all the fraction bits
  281. * (including the explicit ``implied'' 1 bit) down into the
  282. * single-precision range. If the number is subnormal, move
  283. * the ``implied'' 1 into the explicit range as well, and shift
  284. * right to introduce leading zeroes. Rounding then acts
  285. * differently for normals and subnormals: the largest subnormal
  286. * may round to the smallest normal (1.0 x 2^minexp), or may
  287. * remain subnormal. In the latter case, signal an underflow
  288. * if the result was inexact or if underflow traps are enabled.
  289. *
  290. * Rounding a normal, on the other hand, always produces another
  291. * normal (although either way the result might be too big for
  292. * single precision, and cause an overflow). If rounding a
  293. * normal produces 2.0 in the fraction, we need not adjust that
  294. * fraction at all, since both 1.0 and 2.0 are zero under the
  295. * fraction mask.
  296. *
  297. * Note that the guard and round bits vanish from the number after
  298. * rounding.
  299. */
  300. if ((exp = fp->fp_exp + SNG_EXP_BIAS) <= 0) { /* subnormal */
  301. /* -NG for g,r; -SNG_FRACBITS-exp for fraction */
  302. (void) fpu_shr(fp, FP_NMANT - FP_NG - SNG_FRACBITS - exp);
  303. if (round(fe, fp) && fp->fp_mant[3] == SNG_EXP(1))
  304. return (sign | SNG_EXP(1) | 0);
  305. if ((fe->fe_cx & FPSCR_FI) ||
  306. (fe->fe_fpscr & FPSCR_UX))
  307. fe->fe_cx |= FPSCR_UX;
  308. return (sign | SNG_EXP(0) | fp->fp_mant[3]);
  309. }
  310. /* -FP_NG for g,r; -1 for implied 1; -SNG_FRACBITS for fraction */
  311. (void) fpu_shr(fp, FP_NMANT - FP_NG - 1 - SNG_FRACBITS);
  312. #ifdef DIAGNOSTIC
  313. if ((fp->fp_mant[3] & SNG_EXP(1 << FP_NG)) == 0)
  314. panic("fpu_ftos");
  315. #endif
  316. if (round(fe, fp) && fp->fp_mant[3] == SNG_EXP(2))
  317. exp++;
  318. if (exp >= SNG_EXP_INFNAN) {
  319. /* overflow to inf or to max single */
  320. if (toinf(fe, sign))
  321. return (sign | SNG_EXP(SNG_EXP_INFNAN));
  322. return (sign | SNG_EXP(SNG_EXP_INFNAN - 1) | SNG_MASK);
  323. }
  324. done:
  325. /* phew, made it */
  326. return (sign | SNG_EXP(exp) | (fp->fp_mant[3] & SNG_MASK));
  327. }
  328. /*
  329. * fpn -> double (32 bit high-order result returned; 32-bit low order result
  330. * left in res[1]). Assumes <= 61 bits in double precision fraction.
  331. *
  332. * This code mimics fpu_ftos; see it for comments.
  333. */
  334. u_int
  335. fpu_ftod(struct fpemu *fe, struct fpn *fp, u_int *res)
  336. {
  337. u_int sign = fp->fp_sign << 31;
  338. int exp;
  339. #define DBL_EXP(e) ((e) << (DBL_FRACBITS & 31))
  340. #define DBL_MASK (DBL_EXP(1) - 1)
  341. if (ISNAN(fp)) {
  342. (void) fpu_shr(fp, FP_NMANT - 1 - DBL_FRACBITS);
  343. exp = DBL_EXP_INFNAN;
  344. goto done;
  345. }
  346. if (ISINF(fp)) {
  347. sign |= DBL_EXP(DBL_EXP_INFNAN);
  348. goto zero;
  349. }
  350. if (ISZERO(fp)) {
  351. zero: res[1] = 0;
  352. return (sign);
  353. }
  354. if ((exp = fp->fp_exp + DBL_EXP_BIAS) <= 0) {
  355. (void) fpu_shr(fp, FP_NMANT - FP_NG - DBL_FRACBITS - exp);
  356. if (round(fe, fp) && fp->fp_mant[2] == DBL_EXP(1)) {
  357. res[1] = 0;
  358. return (sign | DBL_EXP(1) | 0);
  359. }
  360. if ((fe->fe_cx & FPSCR_FI) ||
  361. (fe->fe_fpscr & FPSCR_UX))
  362. fe->fe_cx |= FPSCR_UX;
  363. exp = 0;
  364. goto done;
  365. }
  366. (void) fpu_shr(fp, FP_NMANT - FP_NG - 1 - DBL_FRACBITS);
  367. if (round(fe, fp) && fp->fp_mant[2] == DBL_EXP(2))
  368. exp++;
  369. if (exp >= DBL_EXP_INFNAN) {
  370. fe->fe_cx |= FPSCR_OX | FPSCR_UX;
  371. if (toinf(fe, sign)) {
  372. res[1] = 0;
  373. return (sign | DBL_EXP(DBL_EXP_INFNAN) | 0);
  374. }
  375. res[1] = ~0;
  376. return (sign | DBL_EXP(DBL_EXP_INFNAN) | DBL_MASK);
  377. }
  378. done:
  379. res[1] = fp->fp_mant[3];
  380. return (sign | DBL_EXP(exp) | (fp->fp_mant[2] & DBL_MASK));
  381. }
  382. /*
  383. * Implode an fpn, writing the result into the given space.
  384. */
  385. void
  386. fpu_implode(struct fpemu *fe, struct fpn *fp, int type, u_int *space)
  387. {
  388. switch (type) {
  389. case FTYPE_LNG:
  390. space[0] = fpu_ftox(fe, fp, space);
  391. DPRINTF(FPE_REG, ("fpu_implode: long %x %x\n",
  392. space[0], space[1]));
  393. break;
  394. case FTYPE_INT:
  395. space[0] = 0;
  396. space[1] = fpu_ftoi(fe, fp);
  397. DPRINTF(FPE_REG, ("fpu_implode: int %x\n",
  398. space[1]));
  399. break;
  400. case FTYPE_SNG:
  401. space[0] = fpu_ftos(fe, fp);
  402. DPRINTF(FPE_REG, ("fpu_implode: single %x\n",
  403. space[0]));
  404. break;
  405. case FTYPE_DBL:
  406. space[0] = fpu_ftod(fe, fp, space);
  407. DPRINTF(FPE_REG, ("fpu_implode: double %x %x\n",
  408. space[0], space[1]));
  409. break; break;
  410. default:
  411. panic("fpu_implode: invalid type %d", type);
  412. }
  413. }