Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     NetWinder Floating Point Emulator
0004     (c) Rebel.COM, 1998,1999
0005     (c) Philip Blundell, 2001
0006 
0007     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
0008 
0009 */
0010 
0011 #include "fpa11.h"
0012 #include "fpopcode.h"
0013 
0014 unsigned int SingleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
0015 unsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
0016 unsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
0017 
0018 unsigned int EmulateCPDO(const unsigned int opcode)
0019 {
0020     FPA11 *fpa11 = GET_FPA11();
0021     FPREG *rFd;
0022     unsigned int nType, nDest, nRc;
0023     struct roundingData roundData;
0024 
0025     /* Get the destination size.  If not valid let Linux perform
0026        an invalid instruction trap. */
0027     nDest = getDestinationSize(opcode);
0028     if (typeNone == nDest)
0029         return 0;
0030 
0031     roundData.mode = SetRoundingMode(opcode);
0032     roundData.precision = SetRoundingPrecision(opcode);
0033     roundData.exception = 0;
0034 
0035     /* Compare the size of the operands in Fn and Fm.
0036        Choose the largest size and perform operations in that size,
0037        in order to make use of all the precision of the operands.
0038        If Fm is a constant, we just grab a constant of a size
0039        matching the size of the operand in Fn. */
0040     if (MONADIC_INSTRUCTION(opcode))
0041         nType = nDest;
0042     else
0043         nType = fpa11->fType[getFn(opcode)];
0044 
0045     if (!CONSTANT_FM(opcode)) {
0046         register unsigned int Fm = getFm(opcode);
0047         if (nType < fpa11->fType[Fm]) {
0048             nType = fpa11->fType[Fm];
0049         }
0050     }
0051 
0052     rFd = &fpa11->fpreg[getFd(opcode)];
0053 
0054     switch (nType) {
0055     case typeSingle:
0056         nRc = SingleCPDO(&roundData, opcode, rFd);
0057         break;
0058     case typeDouble:
0059         nRc = DoubleCPDO(&roundData, opcode, rFd);
0060         break;
0061 #ifdef CONFIG_FPE_NWFPE_XP
0062     case typeExtended:
0063         nRc = ExtendedCPDO(&roundData, opcode, rFd);
0064         break;
0065 #endif
0066     default:
0067         nRc = 0;
0068     }
0069 
0070     /* The CPDO functions used to always set the destination type
0071        to be the same as their working size. */
0072 
0073     if (nRc != 0) {
0074         /* If the operation succeeded, check to see if the result in the
0075            destination register is the correct size.  If not force it
0076            to be. */
0077 
0078         fpa11->fType[getFd(opcode)] = nDest;
0079 
0080 #ifdef CONFIG_FPE_NWFPE_XP
0081         if (nDest != nType) {
0082             switch (nDest) {
0083             case typeSingle:
0084                 {
0085                     if (typeDouble == nType)
0086                         rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
0087                     else
0088                         rFd->fSingle = floatx80_to_float32(&roundData, rFd->fExtended);
0089                 }
0090                 break;
0091 
0092             case typeDouble:
0093                 {
0094                     if (typeSingle == nType)
0095                         rFd->fDouble = float32_to_float64(rFd->fSingle);
0096                     else
0097                         rFd->fDouble = floatx80_to_float64(&roundData, rFd->fExtended);
0098                 }
0099                 break;
0100 
0101             case typeExtended:
0102                 {
0103                     if (typeSingle == nType)
0104                         rFd->fExtended = float32_to_floatx80(rFd->fSingle);
0105                     else
0106                         rFd->fExtended = float64_to_floatx80(rFd->fDouble);
0107                 }
0108                 break;
0109             }
0110         }
0111 #else
0112         if (nDest != nType) {
0113             if (nDest == typeSingle)
0114                 rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
0115             else
0116                 rFd->fDouble = float32_to_float64(rFd->fSingle);
0117         }
0118 #endif
0119     }
0120 
0121     if (roundData.exception)
0122         float_raise(roundData.exception);
0123 
0124     return nRc;
0125 }