1/* 2 * Linux/PA-RISC Project (http://www.parisc-linux.org/) 3 * 4 * Floating-point emulation code 5 * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21/* 22 * BEGIN_DESC 23 * 24 * File: 25 * @(#) pa/spmath/dfdiv.c $Revision: 1.1 $ 26 * 27 * Purpose: 28 * Double Precision Floating-point Divide 29 * 30 * External Interfaces: 31 * dbl_fdiv(srcptr1,srcptr2,dstptr,status) 32 * 33 * Internal Interfaces: 34 * 35 * Theory: 36 * <<please update with a overview of the operation of this file>> 37 * 38 * END_DESC 39*/ 40 41 42#include "float.h" 43#include "dbl_float.h" 44 45/* 46 * Double Precision Floating-point Divide 47 */ 48 49int 50dbl_fdiv (dbl_floating_point * srcptr1, dbl_floating_point * srcptr2, 51 dbl_floating_point * dstptr, unsigned int *status) 52{ 53 register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2; 54 register unsigned int opnd3p1, opnd3p2, resultp1, resultp2; 55 register int dest_exponent, count; 56 register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE; 57 boolean is_tiny; 58 59 Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2); 60 Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2); 61 /* 62 * set sign bit of result 63 */ 64 if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1)) 65 Dbl_setnegativezerop1(resultp1); 66 else Dbl_setzerop1(resultp1); 67 /* 68 * check first operand for NaN's or infinity 69 */ 70 if (Dbl_isinfinity_exponent(opnd1p1)) { 71 if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) { 72 if (Dbl_isnotnan(opnd2p1,opnd2p2)) { 73 if (Dbl_isinfinity(opnd2p1,opnd2p2)) { 74 /* 75 * invalid since both operands 76 * are infinity 77 */ 78 if (Is_invalidtrap_enabled()) 79 return(INVALIDEXCEPTION); 80 Set_invalidflag(); 81 Dbl_makequietnan(resultp1,resultp2); 82 Dbl_copytoptr(resultp1,resultp2,dstptr); 83 return(NOEXCEPTION); 84 } 85 /* 86 * return infinity 87 */ 88 Dbl_setinfinity_exponentmantissa(resultp1,resultp2); 89 Dbl_copytoptr(resultp1,resultp2,dstptr); 90 return(NOEXCEPTION); 91 } 92 } 93 else { 94 /* 95 * is NaN; signaling or quiet? 96 */ 97 if (Dbl_isone_signaling(opnd1p1)) { 98 /* trap if INVALIDTRAP enabled */ 99 if (Is_invalidtrap_enabled()) 100 return(INVALIDEXCEPTION); 101 /* make NaN quiet */ 102 Set_invalidflag(); 103 Dbl_set_quiet(opnd1p1); 104 } 105 /* 106 * is second operand a signaling NaN? 107 */ 108 else if (Dbl_is_signalingnan(opnd2p1)) { 109 /* trap if INVALIDTRAP enabled */ 110 if (Is_invalidtrap_enabled()) 111 return(INVALIDEXCEPTION); 112 /* make NaN quiet */ 113 Set_invalidflag(); 114 Dbl_set_quiet(opnd2p1); 115 Dbl_copytoptr(opnd2p1,opnd2p2,dstptr); 116 return(NOEXCEPTION); 117 } 118 /* 119 * return quiet NaN 120 */ 121 Dbl_copytoptr(opnd1p1,opnd1p2,dstptr); 122 return(NOEXCEPTION); 123 } 124 } 125 /* 126 * check second operand for NaN's or infinity 127 */ 128 if (Dbl_isinfinity_exponent(opnd2p1)) { 129 if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) { 130 /* 131 * return zero 132 */ 133 Dbl_setzero_exponentmantissa(resultp1,resultp2); 134 Dbl_copytoptr(resultp1,resultp2,dstptr); 135 return(NOEXCEPTION); 136 } 137 /* 138 * is NaN; signaling or quiet? 139 */ 140 if (Dbl_isone_signaling(opnd2p1)) { 141 /* trap if INVALIDTRAP enabled */ 142 if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 143 /* make NaN quiet */ 144 Set_invalidflag(); 145 Dbl_set_quiet(opnd2p1); 146 } 147 /* 148 * return quiet NaN 149 */ 150 Dbl_copytoptr(opnd2p1,opnd2p2,dstptr); 151 return(NOEXCEPTION); 152 } 153 /* 154 * check for division by zero 155 */ 156 if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) { 157 if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) { 158 /* invalid since both operands are zero */ 159 if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 160 Set_invalidflag(); 161 Dbl_makequietnan(resultp1,resultp2); 162 Dbl_copytoptr(resultp1,resultp2,dstptr); 163 return(NOEXCEPTION); 164 } 165 if (Is_divisionbyzerotrap_enabled()) 166 return(DIVISIONBYZEROEXCEPTION); 167 Set_divisionbyzeroflag(); 168 Dbl_setinfinity_exponentmantissa(resultp1,resultp2); 169 Dbl_copytoptr(resultp1,resultp2,dstptr); 170 return(NOEXCEPTION); 171 } 172 /* 173 * Generate exponent 174 */ 175 dest_exponent = Dbl_exponent(opnd1p1) - Dbl_exponent(opnd2p1) + DBL_BIAS; 176 177 /* 178 * Generate mantissa 179 */ 180 if (Dbl_isnotzero_exponent(opnd1p1)) { 181 /* set hidden bit */ 182 Dbl_clear_signexponent_set_hidden(opnd1p1); 183 } 184 else { 185 /* check for zero */ 186 if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) { 187 Dbl_setzero_exponentmantissa(resultp1,resultp2); 188 Dbl_copytoptr(resultp1,resultp2,dstptr); 189 return(NOEXCEPTION); 190 } 191 /* is denormalized, want to normalize */ 192 Dbl_clear_signexponent(opnd1p1); 193 Dbl_leftshiftby1(opnd1p1,opnd1p2); 194 Dbl_normalize(opnd1p1,opnd1p2,dest_exponent); 195 } 196 /* opnd2 needs to have hidden bit set with msb in hidden bit */ 197 if (Dbl_isnotzero_exponent(opnd2p1)) { 198 Dbl_clear_signexponent_set_hidden(opnd2p1); 199 } 200 else { 201 /* is denormalized; want to normalize */ 202 Dbl_clear_signexponent(opnd2p1); 203 Dbl_leftshiftby1(opnd2p1,opnd2p2); 204 while (Dbl_iszero_hiddenhigh7mantissa(opnd2p1)) { 205 dest_exponent+=8; 206 Dbl_leftshiftby8(opnd2p1,opnd2p2); 207 } 208 if (Dbl_iszero_hiddenhigh3mantissa(opnd2p1)) { 209 dest_exponent+=4; 210 Dbl_leftshiftby4(opnd2p1,opnd2p2); 211 } 212 while (Dbl_iszero_hidden(opnd2p1)) { 213 dest_exponent++; 214 Dbl_leftshiftby1(opnd2p1,opnd2p2); 215 } 216 } 217 218 /* Divide the source mantissas */ 219 220 /* 221 * A non-restoring divide algorithm is used. 222 */ 223 Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2); 224 Dbl_setzero(opnd3p1,opnd3p2); 225 for (count=1; count <= DBL_P && (opnd1p1 || opnd1p2); count++) { 226 Dbl_leftshiftby1(opnd1p1,opnd1p2); 227 Dbl_leftshiftby1(opnd3p1,opnd3p2); 228 if (Dbl_iszero_sign(opnd1p1)) { 229 Dbl_setone_lowmantissap2(opnd3p2); 230 Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2); 231 } 232 else { 233 Twoword_add(opnd1p1, opnd1p2, opnd2p1, opnd2p2); 234 } 235 } 236 if (count <= DBL_P) { 237 Dbl_leftshiftby1(opnd3p1,opnd3p2); 238 Dbl_setone_lowmantissap2(opnd3p2); 239 Dbl_leftshift(opnd3p1,opnd3p2,(DBL_P-count)); 240 if (Dbl_iszero_hidden(opnd3p1)) { 241 Dbl_leftshiftby1(opnd3p1,opnd3p2); 242 dest_exponent--; 243 } 244 } 245 else { 246 if (Dbl_iszero_hidden(opnd3p1)) { 247 /* need to get one more bit of result */ 248 Dbl_leftshiftby1(opnd1p1,opnd1p2); 249 Dbl_leftshiftby1(opnd3p1,opnd3p2); 250 if (Dbl_iszero_sign(opnd1p1)) { 251 Dbl_setone_lowmantissap2(opnd3p2); 252 Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2); 253 } 254 else { 255 Twoword_add(opnd1p1,opnd1p2,opnd2p1,opnd2p2); 256 } 257 dest_exponent--; 258 } 259 if (Dbl_iszero_sign(opnd1p1)) guardbit = TRUE; 260 stickybit = Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2); 261 } 262 inexact = guardbit | stickybit; 263 264 /* 265 * round result 266 */ 267 if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) { 268 Dbl_clear_signexponent(opnd3p1); 269 switch (Rounding_mode()) { 270 case ROUNDPLUS: 271 if (Dbl_iszero_sign(resultp1)) 272 Dbl_increment(opnd3p1,opnd3p2); 273 break; 274 case ROUNDMINUS: 275 if (Dbl_isone_sign(resultp1)) 276 Dbl_increment(opnd3p1,opnd3p2); 277 break; 278 case ROUNDNEAREST: 279 if (guardbit && (stickybit || 280 Dbl_isone_lowmantissap2(opnd3p2))) { 281 Dbl_increment(opnd3p1,opnd3p2); 282 } 283 } 284 if (Dbl_isone_hidden(opnd3p1)) dest_exponent++; 285 } 286 Dbl_set_mantissa(resultp1,resultp2,opnd3p1,opnd3p2); 287 288 /* 289 * Test for overflow 290 */ 291 if (dest_exponent >= DBL_INFINITY_EXPONENT) { 292 /* trap if OVERFLOWTRAP enabled */ 293 if (Is_overflowtrap_enabled()) { 294 /* 295 * Adjust bias of result 296 */ 297 Dbl_setwrapped_exponent(resultp1,dest_exponent,ovfl); 298 Dbl_copytoptr(resultp1,resultp2,dstptr); 299 if (inexact) 300 if (Is_inexacttrap_enabled()) 301 return(OVERFLOWEXCEPTION | INEXACTEXCEPTION); 302 else Set_inexactflag(); 303 return(OVERFLOWEXCEPTION); 304 } 305 Set_overflowflag(); 306 /* set result to infinity or largest number */ 307 Dbl_setoverflow(resultp1,resultp2); 308 inexact = TRUE; 309 } 310 /* 311 * Test for underflow 312 */ 313 else if (dest_exponent <= 0) { 314 /* trap if UNDERFLOWTRAP enabled */ 315 if (Is_underflowtrap_enabled()) { 316 /* 317 * Adjust bias of result 318 */ 319 Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl); 320 Dbl_copytoptr(resultp1,resultp2,dstptr); 321 if (inexact) 322 if (Is_inexacttrap_enabled()) 323 return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION); 324 else Set_inexactflag(); 325 return(UNDERFLOWEXCEPTION); 326 } 327 328 /* Determine if should set underflow flag */ 329 is_tiny = TRUE; 330 if (dest_exponent == 0 && inexact) { 331 switch (Rounding_mode()) { 332 case ROUNDPLUS: 333 if (Dbl_iszero_sign(resultp1)) { 334 Dbl_increment(opnd3p1,opnd3p2); 335 if (Dbl_isone_hiddenoverflow(opnd3p1)) 336 is_tiny = FALSE; 337 Dbl_decrement(opnd3p1,opnd3p2); 338 } 339 break; 340 case ROUNDMINUS: 341 if (Dbl_isone_sign(resultp1)) { 342 Dbl_increment(opnd3p1,opnd3p2); 343 if (Dbl_isone_hiddenoverflow(opnd3p1)) 344 is_tiny = FALSE; 345 Dbl_decrement(opnd3p1,opnd3p2); 346 } 347 break; 348 case ROUNDNEAREST: 349 if (guardbit && (stickybit || 350 Dbl_isone_lowmantissap2(opnd3p2))) { 351 Dbl_increment(opnd3p1,opnd3p2); 352 if (Dbl_isone_hiddenoverflow(opnd3p1)) 353 is_tiny = FALSE; 354 Dbl_decrement(opnd3p1,opnd3p2); 355 } 356 break; 357 } 358 } 359 360 /* 361 * denormalize result or set to signed zero 362 */ 363 stickybit = inexact; 364 Dbl_denormalize(opnd3p1,opnd3p2,dest_exponent,guardbit, 365 stickybit,inexact); 366 367 /* return rounded number */ 368 if (inexact) { 369 switch (Rounding_mode()) { 370 case ROUNDPLUS: 371 if (Dbl_iszero_sign(resultp1)) { 372 Dbl_increment(opnd3p1,opnd3p2); 373 } 374 break; 375 case ROUNDMINUS: 376 if (Dbl_isone_sign(resultp1)) { 377 Dbl_increment(opnd3p1,opnd3p2); 378 } 379 break; 380 case ROUNDNEAREST: 381 if (guardbit && (stickybit || 382 Dbl_isone_lowmantissap2(opnd3p2))) { 383 Dbl_increment(opnd3p1,opnd3p2); 384 } 385 break; 386 } 387 if (is_tiny) Set_underflowflag(); 388 } 389 Dbl_set_exponentmantissa(resultp1,resultp2,opnd3p1,opnd3p2); 390 } 391 else Dbl_set_exponent(resultp1,dest_exponent); 392 Dbl_copytoptr(resultp1,resultp2,dstptr); 393 394 /* check for inexact */ 395 if (inexact) { 396 if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION); 397 else Set_inexactflag(); 398 } 399 return(NOEXCEPTION); 400} 401