linux/arch/parisc/math-emu/fcnvfu.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/fcnvfu.c              $Revision: 1.1 $
  26 *
  27 *  Purpose:
  28 *      Floating-point to Unsigned Fixed-point Converts
  29 *
  30 *  External Interfaces:
  31 *      dbl_to_dbl_fcnvfu(srcptr,nullptr,dstptr,status)
  32 *      dbl_to_sgl_fcnvfu(srcptr,nullptr,dstptr,status)
  33 *      sgl_to_dbl_fcnvfu(srcptr,nullptr,dstptr,status)
  34 *      sgl_to_sgl_fcnvfu(srcptr,nullptr,dstptr,status)
  35 *
  36 *  Internal Interfaces:
  37 *
  38 *  Theory:
  39 *      <<please update with a overview of the operation of this file>>
  40 *
  41 * END_DESC
  42*/
  43
  44
  45#include "float.h"
  46#include "sgl_float.h"
  47#include "dbl_float.h"
  48#include "cnv_float.h"
  49
  50/************************************************************************
  51 *  Floating-point to Unsigned Fixed-point Converts                     *
  52 ************************************************************************/
  53
  54/*
  55 *  Single Floating-point to Single Unsigned Fixed 
  56 */
  57/*ARGSUSED*/
  58int
  59sgl_to_sgl_fcnvfu(
  60                        sgl_floating_point *srcptr,
  61                        unsigned int *nullptr,
  62                        unsigned int *dstptr,
  63                        unsigned int *status)
  64{
  65        register unsigned int src, result;
  66        register int src_exponent;
  67        register boolean inexact = FALSE;
  68
  69        src = *srcptr;
  70        src_exponent = Sgl_exponent(src) - SGL_BIAS;
  71
  72        /* 
  73         * Test for overflow
  74         */
  75        if (src_exponent > SGL_FX_MAX_EXP + 1) {
  76                if (Sgl_isone_sign(src)) {
  77                        result = 0;
  78                } else {
  79                        result = 0xffffffff;
  80                }
  81                if (Is_invalidtrap_enabled()) {
  82                        return(INVALIDEXCEPTION);
  83                }
  84                Set_invalidflag();
  85                *dstptr = result;
  86                return(NOEXCEPTION);
  87        }
  88        /*
  89         * Generate result
  90         */
  91        if (src_exponent >= 0) {
  92                /* 
  93                 * Check sign.
  94                 * If negative, trap unimplemented.
  95                 */
  96                if (Sgl_isone_sign(src)) {
  97                        result = 0;
  98                        if (Is_invalidtrap_enabled()) {
  99                                return(INVALIDEXCEPTION);
 100                        }
 101                        Set_invalidflag();
 102                        *dstptr = result;
 103                        return(NOEXCEPTION);
 104                }
 105                Sgl_clear_signexponent_set_hidden(src);
 106                Suint_from_sgl_mantissa(src,src_exponent,result);
 107
 108                /* check for inexact */
 109                if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
 110                        inexact = TRUE;
 111                        /*  round result  */
 112                        switch (Rounding_mode()) {
 113                        case ROUNDPLUS:
 114                                result++;
 115                                break;
 116                        case ROUNDMINUS: /* never negative */
 117                                break;
 118                        case ROUNDNEAREST:
 119                                if (Sgl_isone_roundbit(src,src_exponent) &&
 120                                    (Sgl_isone_stickybit(src,src_exponent) ||
 121                                     (result & 1))) {
 122                                        result++;
 123                                }
 124                                break;
 125                        }
 126                }
 127        } else {
 128                result = 0;
 129
 130                /* check for inexact */
 131                if (Sgl_isnotzero_exponentmantissa(src)) {
 132                        inexact = TRUE;
 133                        /*  round result  */
 134                        switch (Rounding_mode()) {
 135                        case ROUNDPLUS:
 136                                if (Sgl_iszero_sign(src)) {
 137                                        result++;
 138                                }
 139                                break;
 140                        case ROUNDMINUS:
 141                                if (Sgl_isone_sign(src)) {
 142                                        result = 0;
 143                                        if (Is_invalidtrap_enabled()) {
 144                                                return(INVALIDEXCEPTION);
 145                                        }
 146                                        Set_invalidflag();
 147                                        inexact = FALSE;
 148                                }
 149                                break;
 150                        case ROUNDNEAREST:
 151                                if (src_exponent == -1 &&
 152                                    Sgl_isnotzero_mantissa(src)) {
 153                                        if (Sgl_isone_sign(src)) {
 154                                                result = 0;
 155                                                if (Is_invalidtrap_enabled()) {
 156                                                        return(INVALIDEXCEPTION);
 157                                                }
 158                                                Set_invalidflag();
 159                                                inexact = FALSE;
 160                                        }
 161                                        else result++;
 162                                }
 163                                break;
 164                        }
 165                }
 166        }
 167        *dstptr = result;
 168        if (inexact) {
 169                if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
 170                else Set_inexactflag();
 171        }
 172        return(NOEXCEPTION);
 173}
 174
 175/*
 176 *  Single Floating-point to Double Unsigned Fixed 
 177 */
 178/*ARGSUSED*/
 179int
 180sgl_to_dbl_fcnvfu(
 181                    sgl_floating_point *srcptr,
 182                    unsigned int *nullptr,
 183                    dbl_unsigned *dstptr,
 184                    unsigned int *status)
 185{
 186        register int src_exponent;
 187        register unsigned int src, resultp1, resultp2;
 188        register boolean inexact = FALSE;
 189
 190        src = *srcptr;
 191        src_exponent = Sgl_exponent(src) - SGL_BIAS;
 192
 193        /* 
 194         * Test for overflow
 195         */
 196        if (src_exponent > DBL_FX_MAX_EXP + 1) {
 197                if (Sgl_isone_sign(src)) {
 198                        resultp1 = resultp2 = 0;
 199                } else {
 200                        resultp1 = resultp2 = 0xffffffff;
 201                }
 202                if (Is_invalidtrap_enabled()) {
 203                        return(INVALIDEXCEPTION);
 204                }
 205                Set_invalidflag();
 206                Duint_copytoptr(resultp1,resultp2,dstptr);
 207                return(NOEXCEPTION);
 208        }
 209        /*
 210         * Generate result
 211         */
 212        if (src_exponent >= 0) {
 213                /* 
 214                 * Check sign.
 215                 * If negative, trap unimplemented.
 216                 */
 217                if (Sgl_isone_sign(src)) {
 218                        resultp1 = resultp2 = 0;
 219                        if (Is_invalidtrap_enabled()) {
 220                                return(INVALIDEXCEPTION);
 221                        }
 222                        Set_invalidflag();
 223                        Duint_copytoptr(resultp1,resultp2,dstptr);
 224                        return(NOEXCEPTION);
 225                }
 226                Sgl_clear_signexponent_set_hidden(src);
 227                Duint_from_sgl_mantissa(src,src_exponent,resultp1,resultp2);
 228
 229                /* check for inexact */
 230                if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
 231                        inexact = TRUE;
 232                        /*  round result  */
 233                        switch (Rounding_mode()) {
 234                        case ROUNDPLUS:
 235                                Duint_increment(resultp1,resultp2);
 236                                break;
 237                        case ROUNDMINUS: /* never negative */
 238                                break;
 239                        case ROUNDNEAREST:
 240                                if (Sgl_isone_roundbit(src,src_exponent) &&
 241                                    (Sgl_isone_stickybit(src,src_exponent) || 
 242                                     Duint_isone_lowp2(resultp2))) {
 243                                        Duint_increment(resultp1,resultp2);
 244                                }
 245                                break;
 246                        }
 247                }
 248        } else {
 249                Duint_setzero(resultp1,resultp2);
 250
 251                /* check for inexact */
 252                if (Sgl_isnotzero_exponentmantissa(src)) {
 253                        inexact = TRUE;
 254                        /*  round result  */
 255                        switch (Rounding_mode()) {
 256                        case ROUNDPLUS:
 257                                if (Sgl_iszero_sign(src)) {
 258                                        Duint_increment(resultp1,resultp2);
 259                                }
 260                                break;
 261                        case ROUNDMINUS:
 262                                if (Sgl_isone_sign(src)) {
 263                                        resultp1 = resultp2 = 0;
 264                                        if (Is_invalidtrap_enabled()) {
 265                                                return(INVALIDEXCEPTION);
 266                                        }
 267                                        Set_invalidflag();
 268                                        inexact = FALSE;
 269                                }
 270                                break;
 271                        case ROUNDNEAREST:
 272                                if (src_exponent == -1 &&
 273                                    Sgl_isnotzero_mantissa(src)) {
 274                                        if (Sgl_isone_sign(src)) {
 275                                                resultp1 = 0;
 276                                                resultp2 = 0;
 277                                                if (Is_invalidtrap_enabled()) {
 278                                                        return(INVALIDEXCEPTION);
 279                                                }
 280                                                Set_invalidflag();
 281                                                inexact = FALSE;
 282                                        }
 283                                        else Duint_increment(resultp1,resultp2);
 284                                }
 285                        }
 286                }
 287        }
 288        Duint_copytoptr(resultp1,resultp2,dstptr);
 289        if (inexact) {
 290                if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
 291                else Set_inexactflag();
 292        }
 293        return(NOEXCEPTION);
 294}
 295
 296/*
 297 *  Double Floating-point to Single Unsigned Fixed 
 298 */
 299/*ARGSUSED*/
 300int
 301dbl_to_sgl_fcnvfu (dbl_floating_point * srcptr, unsigned int *nullptr,
 302                   unsigned int *dstptr, unsigned int *status)
 303{
 304        register unsigned int srcp1, srcp2, result;
 305        register int src_exponent;
 306        register boolean inexact = FALSE;
 307
 308        Dbl_copyfromptr(srcptr,srcp1,srcp2);
 309        src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
 310
 311        /* 
 312         * Test for overflow
 313         */
 314        if (src_exponent > SGL_FX_MAX_EXP + 1) {
 315                if (Dbl_isone_sign(srcp1)) {
 316                        result = 0;
 317                } else {
 318                        result = 0xffffffff;
 319                }
 320                if (Is_invalidtrap_enabled()) {
 321                        return(INVALIDEXCEPTION);
 322                }
 323                Set_invalidflag();
 324                *dstptr = result;
 325                return(NOEXCEPTION);
 326        }
 327        /*
 328         * Generate result
 329         */
 330        if (src_exponent >= 0) {
 331                /* 
 332                 * Check sign.
 333                 * If negative, trap unimplemented.
 334                 */
 335                if (Dbl_isone_sign(srcp1)) {
 336                        result = 0;
 337                        if (Is_invalidtrap_enabled()) {
 338                                return(INVALIDEXCEPTION);
 339                        }
 340                        Set_invalidflag();
 341                        *dstptr = result;
 342                        return(NOEXCEPTION);
 343                }
 344                Dbl_clear_signexponent_set_hidden(srcp1);
 345                Suint_from_dbl_mantissa(srcp1,srcp2,src_exponent,result);
 346
 347                /* check for inexact */
 348                if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
 349                        inexact = TRUE;
 350                        /*  round result  */
 351                        switch (Rounding_mode()) {
 352                        case ROUNDPLUS:
 353                             result++;
 354                             break;
 355                        case ROUNDMINUS: /* never negative */
 356                             break;
 357                        case ROUNDNEAREST:
 358                             if(Dbl_isone_roundbit(srcp1,srcp2,src_exponent) &&
 359                                (Dbl_isone_stickybit(srcp1,srcp2,src_exponent)||
 360                                 result&1))
 361                                   result++;
 362                             break;
 363                        }
 364                        /* check for overflow */
 365                        if (result == 0) {
 366                                result = 0xffffffff;
 367                                if (Is_invalidtrap_enabled()) {
 368                                        return(INVALIDEXCEPTION);
 369                                }
 370                                Set_invalidflag();
 371                                *dstptr = result;
 372                                return(NOEXCEPTION);
 373                        }
 374                }
 375        } else {
 376                result = 0;
 377
 378                /* check for inexact */
 379                if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
 380                        inexact = TRUE;
 381                        /*  round result  */
 382                        switch (Rounding_mode()) {
 383                        case ROUNDPLUS:
 384                                if (Dbl_iszero_sign(srcp1)) result++;
 385                                break;
 386                        case ROUNDMINUS:
 387                                if (Dbl_isone_sign(srcp1)) {
 388                                        result = 0;
 389                                        if (Is_invalidtrap_enabled()) {
 390                                                return(INVALIDEXCEPTION);
 391                                        }
 392                                        Set_invalidflag();
 393                                        inexact = FALSE;
 394                                }
 395                                break;
 396                        case ROUNDNEAREST:
 397                                if (src_exponent == -1 &&
 398                                    Dbl_isnotzero_mantissa(srcp1,srcp2))
 399                                        if (Dbl_isone_sign(srcp1)) {
 400                                                result = 0;
 401                                                if (Is_invalidtrap_enabled()) {
 402                                                        return(INVALIDEXCEPTION);
 403                                                }
 404                                                Set_invalidflag();
 405                                                inexact = FALSE;
 406                                        }
 407                                        else result++;
 408                        }
 409                }
 410        }
 411        *dstptr = result;
 412        if (inexact) {
 413                if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
 414                else Set_inexactflag();
 415        }
 416        return(NOEXCEPTION);
 417}
 418
 419/*
 420 *  Double Floating-point to Double Unsigned Fixed 
 421 */
 422/*ARGSUSED*/
 423int
 424dbl_to_dbl_fcnvfu (dbl_floating_point * srcptr, unsigned int *nullptr,
 425                   dbl_unsigned * dstptr, unsigned int *status)
 426{
 427        register int src_exponent;
 428        register unsigned int srcp1, srcp2, resultp1, resultp2;
 429        register boolean inexact = FALSE;
 430
 431        Dbl_copyfromptr(srcptr,srcp1,srcp2);
 432        src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
 433
 434        /* 
 435         * Test for overflow
 436         */
 437        if (src_exponent > DBL_FX_MAX_EXP + 1) {
 438                if (Dbl_isone_sign(srcp1)) {
 439                        resultp1 = resultp2 = 0;
 440                } else {
 441                        resultp1 = resultp2 = 0xffffffff;
 442                }
 443                if (Is_invalidtrap_enabled()) {
 444                        return(INVALIDEXCEPTION);
 445                }
 446                Set_invalidflag();
 447                Duint_copytoptr(resultp1,resultp2,dstptr);
 448                return(NOEXCEPTION);
 449        }
 450 
 451        /*
 452         * Generate result
 453         */
 454        if (src_exponent >= 0) {
 455                /* 
 456                 * Check sign.
 457                 * If negative, trap unimplemented.
 458                 */
 459                if (Dbl_isone_sign(srcp1)) {
 460                        resultp1 = resultp2 = 0;
 461                        if (Is_invalidtrap_enabled()) {
 462                                return(INVALIDEXCEPTION);
 463                        }
 464                        Set_invalidflag();
 465                        Duint_copytoptr(resultp1,resultp2,dstptr);
 466                        return(NOEXCEPTION);
 467                }
 468                Dbl_clear_signexponent_set_hidden(srcp1);
 469                Duint_from_dbl_mantissa(srcp1,srcp2,src_exponent,resultp1,
 470                  resultp2);
 471
 472                /* check for inexact */
 473                if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
 474                        inexact = TRUE;
 475                        /*  round result  */
 476                        switch (Rounding_mode()) {
 477                        case ROUNDPLUS:
 478                                Duint_increment(resultp1,resultp2);
 479                                break;
 480                        case ROUNDMINUS: /* never negative */
 481                                break;
 482                        case ROUNDNEAREST:
 483                                if(Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
 484                                  if(Dbl_isone_stickybit(srcp1,srcp2,src_exponent) || 
 485                                     Duint_isone_lowp2(resultp2))
 486                                        Duint_increment(resultp1,resultp2);
 487                        } 
 488                }
 489        } else {
 490                Duint_setzero(resultp1,resultp2);
 491
 492                /* check for inexact */
 493                if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
 494                        inexact = TRUE;
 495                        /*  round result  */
 496                        switch (Rounding_mode()) {
 497                        case ROUNDPLUS:
 498                                if (Dbl_iszero_sign(srcp1)) {
 499                                        Duint_increment(resultp1,resultp2);
 500                                }
 501                                break;
 502                        case ROUNDMINUS:
 503                                if (Dbl_isone_sign(srcp1)) {
 504                                        resultp1 = resultp2 = 0;
 505                                        if (Is_invalidtrap_enabled()) {
 506                                                return(INVALIDEXCEPTION);
 507                                        }
 508                                        Set_invalidflag();
 509                                        inexact = FALSE;
 510                                }
 511                                break;
 512                        case ROUNDNEAREST:
 513                                if (src_exponent == -1 &&
 514                                    Dbl_isnotzero_mantissa(srcp1,srcp2))
 515                                        if (Dbl_iszero_sign(srcp1)) {
 516                                                Duint_increment(resultp1,resultp2);
 517                                        } else {
 518                                                resultp1 = 0;
 519                                                resultp2 = 0;
 520                                                if (Is_invalidtrap_enabled()) {
 521                                                        return(INVALIDEXCEPTION);
 522                                                }
 523                                                Set_invalidflag();
 524                                                inexact = FALSE;
 525                                        }
 526                        }
 527                }
 528        }
 529        Duint_copytoptr(resultp1,resultp2,dstptr);
 530        if (inexact) {
 531                if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
 532                else Set_inexactflag();
 533        }
 534        return(NOEXCEPTION);
 535}
 536
 537