linux/arch/arm/nwfpe/fpa11_cpdo.c
<<
>>
Prefs
   1/*
   2    NetWinder Floating Point Emulator
   3    (c) Rebel.COM, 1998,1999
   4    (c) Philip Blundell, 2001
   5
   6    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
   7
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 2 of the License, or
  11    (at your option) any later version.
  12
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17
  18    You should have received a copy of the GNU General Public License
  19    along with this program; if not, write to the Free Software
  20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21*/
  22
  23#include "fpa11.h"
  24#include "fpopcode.h"
  25
  26unsigned int SingleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
  27unsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
  28unsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
  29
  30unsigned int EmulateCPDO(const unsigned int opcode)
  31{
  32        FPA11 *fpa11 = GET_FPA11();
  33        FPREG *rFd;
  34        unsigned int nType, nDest, nRc;
  35        struct roundingData roundData;
  36
  37        /* Get the destination size.  If not valid let Linux perform
  38           an invalid instruction trap. */
  39        nDest = getDestinationSize(opcode);
  40        if (typeNone == nDest)
  41                return 0;
  42
  43        roundData.mode = SetRoundingMode(opcode);
  44        roundData.precision = SetRoundingPrecision(opcode);
  45        roundData.exception = 0;
  46
  47        /* Compare the size of the operands in Fn and Fm.
  48           Choose the largest size and perform operations in that size,
  49           in order to make use of all the precision of the operands.
  50           If Fm is a constant, we just grab a constant of a size
  51           matching the size of the operand in Fn. */
  52        if (MONADIC_INSTRUCTION(opcode))
  53                nType = nDest;
  54        else
  55                nType = fpa11->fType[getFn(opcode)];
  56
  57        if (!CONSTANT_FM(opcode)) {
  58                register unsigned int Fm = getFm(opcode);
  59                if (nType < fpa11->fType[Fm]) {
  60                        nType = fpa11->fType[Fm];
  61                }
  62        }
  63
  64        rFd = &fpa11->fpreg[getFd(opcode)];
  65
  66        switch (nType) {
  67        case typeSingle:
  68                nRc = SingleCPDO(&roundData, opcode, rFd);
  69                break;
  70        case typeDouble:
  71                nRc = DoubleCPDO(&roundData, opcode, rFd);
  72                break;
  73#ifdef CONFIG_FPE_NWFPE_XP
  74        case typeExtended:
  75                nRc = ExtendedCPDO(&roundData, opcode, rFd);
  76                break;
  77#endif
  78        default:
  79                nRc = 0;
  80        }
  81
  82        /* The CPDO functions used to always set the destination type
  83           to be the same as their working size. */
  84
  85        if (nRc != 0) {
  86                /* If the operation succeeded, check to see if the result in the
  87                   destination register is the correct size.  If not force it
  88                   to be. */
  89
  90                fpa11->fType[getFd(opcode)] = nDest;
  91
  92#ifdef CONFIG_FPE_NWFPE_XP
  93                if (nDest != nType) {
  94                        switch (nDest) {
  95                        case typeSingle:
  96                                {
  97                                        if (typeDouble == nType)
  98                                                rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
  99                                        else
 100                                                rFd->fSingle = floatx80_to_float32(&roundData, rFd->fExtended);
 101                                }
 102                                break;
 103
 104                        case typeDouble:
 105                                {
 106                                        if (typeSingle == nType)
 107                                                rFd->fDouble = float32_to_float64(rFd->fSingle);
 108                                        else
 109                                                rFd->fDouble = floatx80_to_float64(&roundData, rFd->fExtended);
 110                                }
 111                                break;
 112
 113                        case typeExtended:
 114                                {
 115                                        if (typeSingle == nType)
 116                                                rFd->fExtended = float32_to_floatx80(rFd->fSingle);
 117                                        else
 118                                                rFd->fExtended = float64_to_floatx80(rFd->fDouble);
 119                                }
 120                                break;
 121                        }
 122                }
 123#else
 124                if (nDest != nType) {
 125                        if (nDest == typeSingle)
 126                                rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
 127                        else
 128                                rFd->fDouble = float32_to_float64(rFd->fSingle);
 129                }
 130#endif
 131        }
 132
 133        if (roundData.exception)
 134                float_raise(roundData.exception);
 135
 136        return nRc;
 137}
 138