linux/arch/arm/nwfpe/fpa11_cpdo.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3    NetWinder Floating Point Emulator
   4    (c) Rebel.COM, 1998,1999
   5    (c) Philip Blundell, 2001
   6
   7    Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
   8
   9*/
  10
  11#include "fpa11.h"
  12#include "fpopcode.h"
  13
  14unsigned int SingleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
  15unsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
  16unsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
  17
  18unsigned int EmulateCPDO(const unsigned int opcode)
  19{
  20        FPA11 *fpa11 = GET_FPA11();
  21        FPREG *rFd;
  22        unsigned int nType, nDest, nRc;
  23        struct roundingData roundData;
  24
  25        /* Get the destination size.  If not valid let Linux perform
  26           an invalid instruction trap. */
  27        nDest = getDestinationSize(opcode);
  28        if (typeNone == nDest)
  29                return 0;
  30
  31        roundData.mode = SetRoundingMode(opcode);
  32        roundData.precision = SetRoundingPrecision(opcode);
  33        roundData.exception = 0;
  34
  35        /* Compare the size of the operands in Fn and Fm.
  36           Choose the largest size and perform operations in that size,
  37           in order to make use of all the precision of the operands.
  38           If Fm is a constant, we just grab a constant of a size
  39           matching the size of the operand in Fn. */
  40        if (MONADIC_INSTRUCTION(opcode))
  41                nType = nDest;
  42        else
  43                nType = fpa11->fType[getFn(opcode)];
  44
  45        if (!CONSTANT_FM(opcode)) {
  46                register unsigned int Fm = getFm(opcode);
  47                if (nType < fpa11->fType[Fm]) {
  48                        nType = fpa11->fType[Fm];
  49                }
  50        }
  51
  52        rFd = &fpa11->fpreg[getFd(opcode)];
  53
  54        switch (nType) {
  55        case typeSingle:
  56                nRc = SingleCPDO(&roundData, opcode, rFd);
  57                break;
  58        case typeDouble:
  59                nRc = DoubleCPDO(&roundData, opcode, rFd);
  60                break;
  61#ifdef CONFIG_FPE_NWFPE_XP
  62        case typeExtended:
  63                nRc = ExtendedCPDO(&roundData, opcode, rFd);
  64                break;
  65#endif
  66        default:
  67                nRc = 0;
  68        }
  69
  70        /* The CPDO functions used to always set the destination type
  71           to be the same as their working size. */
  72
  73        if (nRc != 0) {
  74                /* If the operation succeeded, check to see if the result in the
  75                   destination register is the correct size.  If not force it
  76                   to be. */
  77
  78                fpa11->fType[getFd(opcode)] = nDest;
  79
  80#ifdef CONFIG_FPE_NWFPE_XP
  81                if (nDest != nType) {
  82                        switch (nDest) {
  83                        case typeSingle:
  84                                {
  85                                        if (typeDouble == nType)
  86                                                rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
  87                                        else
  88                                                rFd->fSingle = floatx80_to_float32(&roundData, rFd->fExtended);
  89                                }
  90                                break;
  91
  92                        case typeDouble:
  93                                {
  94                                        if (typeSingle == nType)
  95                                                rFd->fDouble = float32_to_float64(rFd->fSingle);
  96                                        else
  97                                                rFd->fDouble = floatx80_to_float64(&roundData, rFd->fExtended);
  98                                }
  99                                break;
 100
 101                        case typeExtended:
 102                                {
 103                                        if (typeSingle == nType)
 104                                                rFd->fExtended = float32_to_floatx80(rFd->fSingle);
 105                                        else
 106                                                rFd->fExtended = float64_to_floatx80(rFd->fDouble);
 107                                }
 108                                break;
 109                        }
 110                }
 111#else
 112                if (nDest != nType) {
 113                        if (nDest == typeSingle)
 114                                rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
 115                        else
 116                                rFd->fDouble = float32_to_float64(rFd->fSingle);
 117                }
 118#endif
 119        }
 120
 121        if (roundData.exception)
 122                float_raise(roundData.exception);
 123
 124        return nRc;
 125}
 126