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