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/sfdiv.c $Revision: 1.1 $ 26 * 27 * Purpose: 28 * Single Precision Floating-point Divide 29 * 30 * External Interfaces: 31 * sgl_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 "sgl_float.h" 44 45 /* 46 * Single Precision Floating-point Divide 47 */ 48 49 int 50 sgl_fdiv (sgl_floating_point * srcptr1, sgl_floating_point * srcptr2, 51 sgl_floating_point * dstptr, unsigned int *status) 52 { 53 register unsigned int opnd1, opnd2, opnd3, result; 54 register int dest_exponent, count; 55 register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE; 56 boolean is_tiny; 57 58 opnd1 = *srcptr1; 59 opnd2 = *srcptr2; 60 /* 61 * set sign bit of result 62 */ 63 if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result); 64 else Sgl_setzero(result); 65 /* 66 * check first operand for NaN's or infinity 67 */ 68 if (Sgl_isinfinity_exponent(opnd1)) { 69 if (Sgl_iszero_mantissa(opnd1)) { 70 if (Sgl_isnotnan(opnd2)) { 71 if (Sgl_isinfinity(opnd2)) { 72 /* 73 * invalid since both operands 74 * are infinity 75 */ 76 if (Is_invalidtrap_enabled()) 77 return(INVALIDEXCEPTION); 78 Set_invalidflag(); 79 Sgl_makequietnan(result); 80 *dstptr = result; 81 return(NOEXCEPTION); 82 } 83 /* 84 * return infinity 85 */ 86 Sgl_setinfinity_exponentmantissa(result); 87 *dstptr = result; 88 return(NOEXCEPTION); 89 } 90 } 91 else { 92 /* 93 * is NaN; signaling or quiet? 94 */ 95 if (Sgl_isone_signaling(opnd1)) { 96 /* trap if INVALIDTRAP enabled */ 97 if (Is_invalidtrap_enabled()) 98 return(INVALIDEXCEPTION); 99 /* make NaN quiet */ 100 Set_invalidflag(); 101 Sgl_set_quiet(opnd1); 102 } 103 /* 104 * is second operand a signaling NaN? 105 */ 106 else if (Sgl_is_signalingnan(opnd2)) { 107 /* trap if INVALIDTRAP enabled */ 108 if (Is_invalidtrap_enabled()) 109 return(INVALIDEXCEPTION); 110 /* make NaN quiet */ 111 Set_invalidflag(); 112 Sgl_set_quiet(opnd2); 113 *dstptr = opnd2; 114 return(NOEXCEPTION); 115 } 116 /* 117 * return quiet NaN 118 */ 119 *dstptr = opnd1; 120 return(NOEXCEPTION); 121 } 122 } 123 /* 124 * check second operand for NaN's or infinity 125 */ 126 if (Sgl_isinfinity_exponent(opnd2)) { 127 if (Sgl_iszero_mantissa(opnd2)) { 128 /* 129 * return zero 130 */ 131 Sgl_setzero_exponentmantissa(result); 132 *dstptr = result; 133 return(NOEXCEPTION); 134 } 135 /* 136 * is NaN; signaling or quiet? 137 */ 138 if (Sgl_isone_signaling(opnd2)) { 139 /* trap if INVALIDTRAP enabled */ 140 if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 141 /* make NaN quiet */ 142 Set_invalidflag(); 143 Sgl_set_quiet(opnd2); 144 } 145 /* 146 * return quiet NaN 147 */ 148 *dstptr = opnd2; 149 return(NOEXCEPTION); 150 } 151 /* 152 * check for division by zero 153 */ 154 if (Sgl_iszero_exponentmantissa(opnd2)) { 155 if (Sgl_iszero_exponentmantissa(opnd1)) { 156 /* invalid since both operands are zero */ 157 if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION); 158 Set_invalidflag(); 159 Sgl_makequietnan(result); 160 *dstptr = result; 161 return(NOEXCEPTION); 162 } 163 if (Is_divisionbyzerotrap_enabled()) 164 return(DIVISIONBYZEROEXCEPTION); 165 Set_divisionbyzeroflag(); 166 Sgl_setinfinity_exponentmantissa(result); 167 *dstptr = result; 168 return(NOEXCEPTION); 169 } 170 /* 171 * Generate exponent 172 */ 173 dest_exponent = Sgl_exponent(opnd1) - Sgl_exponent(opnd2) + SGL_BIAS; 174 175 /* 176 * Generate mantissa 177 */ 178 if (Sgl_isnotzero_exponent(opnd1)) { 179 /* set hidden bit */ 180 Sgl_clear_signexponent_set_hidden(opnd1); 181 } 182 else { 183 /* check for zero */ 184 if (Sgl_iszero_mantissa(opnd1)) { 185 Sgl_setzero_exponentmantissa(result); 186 *dstptr = result; 187 return(NOEXCEPTION); 188 } 189 /* is denormalized; want to normalize */ 190 Sgl_clear_signexponent(opnd1); 191 Sgl_leftshiftby1(opnd1); 192 Sgl_normalize(opnd1,dest_exponent); 193 } 194 /* opnd2 needs to have hidden bit set with msb in hidden bit */ 195 if (Sgl_isnotzero_exponent(opnd2)) { 196 Sgl_clear_signexponent_set_hidden(opnd2); 197 } 198 else { 199 /* is denormalized; want to normalize */ 200 Sgl_clear_signexponent(opnd2); 201 Sgl_leftshiftby1(opnd2); 202 while(Sgl_iszero_hiddenhigh7mantissa(opnd2)) { 203 Sgl_leftshiftby8(opnd2); 204 dest_exponent += 8; 205 } 206 if(Sgl_iszero_hiddenhigh3mantissa(opnd2)) { 207 Sgl_leftshiftby4(opnd2); 208 dest_exponent += 4; 209 } 210 while(Sgl_iszero_hidden(opnd2)) { 211 Sgl_leftshiftby1(opnd2); 212 dest_exponent += 1; 213 } 214 } 215 216 /* Divide the source mantissas */ 217 218 /* 219 * A non_restoring divide algorithm is used. 220 */ 221 Sgl_subtract(opnd1,opnd2,opnd1); 222 Sgl_setzero(opnd3); 223 for (count=1;count<=SGL_P && Sgl_all(opnd1);count++) { 224 Sgl_leftshiftby1(opnd1); 225 Sgl_leftshiftby1(opnd3); 226 if (Sgl_iszero_sign(opnd1)) { 227 Sgl_setone_lowmantissa(opnd3); 228 Sgl_subtract(opnd1,opnd2,opnd1); 229 } 230 else Sgl_addition(opnd1,opnd2,opnd1); 231 } 232 if (count <= SGL_P) { 233 Sgl_leftshiftby1(opnd3); 234 Sgl_setone_lowmantissa(opnd3); 235 Sgl_leftshift(opnd3,SGL_P-count); 236 if (Sgl_iszero_hidden(opnd3)) { 237 Sgl_leftshiftby1(opnd3); 238 dest_exponent--; 239 } 240 } 241 else { 242 if (Sgl_iszero_hidden(opnd3)) { 243 /* need to get one more bit of result */ 244 Sgl_leftshiftby1(opnd1); 245 Sgl_leftshiftby1(opnd3); 246 if (Sgl_iszero_sign(opnd1)) { 247 Sgl_setone_lowmantissa(opnd3); 248 Sgl_subtract(opnd1,opnd2,opnd1); 249 } 250 else Sgl_addition(opnd1,opnd2,opnd1); 251 dest_exponent--; 252 } 253 if (Sgl_iszero_sign(opnd1)) guardbit = TRUE; 254 stickybit = Sgl_all(opnd1); 255 } 256 inexact = guardbit | stickybit; 257 258 /* 259 * round result 260 */ 261 if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) { 262 Sgl_clear_signexponent(opnd3); 263 switch (Rounding_mode()) { 264 case ROUNDPLUS: 265 if (Sgl_iszero_sign(result)) 266 Sgl_increment_mantissa(opnd3); 267 break; 268 case ROUNDMINUS: 269 if (Sgl_isone_sign(result)) 270 Sgl_increment_mantissa(opnd3); 271 break; 272 case ROUNDNEAREST: 273 if (guardbit) { 274 if (stickybit || Sgl_isone_lowmantissa(opnd3)) 275 Sgl_increment_mantissa(opnd3); 276 } 277 } 278 if (Sgl_isone_hidden(opnd3)) dest_exponent++; 279 } 280 Sgl_set_mantissa(result,opnd3); 281 282 /* 283 * Test for overflow 284 */ 285 if (dest_exponent >= SGL_INFINITY_EXPONENT) { 286 /* trap if OVERFLOWTRAP enabled */ 287 if (Is_overflowtrap_enabled()) { 288 /* 289 * Adjust bias of result 290 */ 291 Sgl_setwrapped_exponent(result,dest_exponent,ovfl); 292 *dstptr = result; 293 if (inexact) 294 if (Is_inexacttrap_enabled()) 295 return(OVERFLOWEXCEPTION | INEXACTEXCEPTION); 296 else Set_inexactflag(); 297 return(OVERFLOWEXCEPTION); 298 } 299 Set_overflowflag(); 300 /* set result to infinity or largest number */ 301 Sgl_setoverflow(result); 302 inexact = TRUE; 303 } 304 /* 305 * Test for underflow 306 */ 307 else if (dest_exponent <= 0) { 308 /* trap if UNDERFLOWTRAP enabled */ 309 if (Is_underflowtrap_enabled()) { 310 /* 311 * Adjust bias of result 312 */ 313 Sgl_setwrapped_exponent(result,dest_exponent,unfl); 314 *dstptr = result; 315 if (inexact) 316 if (Is_inexacttrap_enabled()) 317 return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION); 318 else Set_inexactflag(); 319 return(UNDERFLOWEXCEPTION); 320 } 321 322 /* Determine if should set underflow flag */ 323 is_tiny = TRUE; 324 if (dest_exponent == 0 && inexact) { 325 switch (Rounding_mode()) { 326 case ROUNDPLUS: 327 if (Sgl_iszero_sign(result)) { 328 Sgl_increment(opnd3); 329 if (Sgl_isone_hiddenoverflow(opnd3)) 330 is_tiny = FALSE; 331 Sgl_decrement(opnd3); 332 } 333 break; 334 case ROUNDMINUS: 335 if (Sgl_isone_sign(result)) { 336 Sgl_increment(opnd3); 337 if (Sgl_isone_hiddenoverflow(opnd3)) 338 is_tiny = FALSE; 339 Sgl_decrement(opnd3); 340 } 341 break; 342 case ROUNDNEAREST: 343 if (guardbit && (stickybit || 344 Sgl_isone_lowmantissa(opnd3))) { 345 Sgl_increment(opnd3); 346 if (Sgl_isone_hiddenoverflow(opnd3)) 347 is_tiny = FALSE; 348 Sgl_decrement(opnd3); 349 } 350 break; 351 } 352 } 353 354 /* 355 * denormalize result or set to signed zero 356 */ 357 stickybit = inexact; 358 Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact); 359 360 /* return rounded number */ 361 if (inexact) { 362 switch (Rounding_mode()) { 363 case ROUNDPLUS: 364 if (Sgl_iszero_sign(result)) { 365 Sgl_increment(opnd3); 366 } 367 break; 368 case ROUNDMINUS: 369 if (Sgl_isone_sign(result)) { 370 Sgl_increment(opnd3); 371 } 372 break; 373 case ROUNDNEAREST: 374 if (guardbit && (stickybit || 375 Sgl_isone_lowmantissa(opnd3))) { 376 Sgl_increment(opnd3); 377 } 378 break; 379 } 380 if (is_tiny) Set_underflowflag(); 381 } 382 Sgl_set_exponentmantissa(result,opnd3); 383 } 384 else Sgl_set_exponent(result,dest_exponent); 385 *dstptr = result; 386 /* check for inexact */ 387 if (inexact) { 388 if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION); 389 else Set_inexactflag(); 390 } 391 return(NOEXCEPTION); 392 } 393