linux/arch/parisc/math-emu/sfdiv.c
<<
>>
Prefs
   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
  49int
  50sgl_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