1*74ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds NetWinder Floating Point Emulator
41da177e4SLinus Torvalds (c) Rebel.COM, 1998,1999
51da177e4SLinus Torvalds (c) Philip Blundell, 2001
61da177e4SLinus Torvalds
71da177e4SLinus Torvalds Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
81da177e4SLinus Torvalds
91da177e4SLinus Torvalds */
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds #include "fpa11.h"
121da177e4SLinus Torvalds #include "fpopcode.h"
131da177e4SLinus Torvalds
14f148af25SRichard Purdie unsigned int SingleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
15f148af25SRichard Purdie unsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
16f148af25SRichard Purdie unsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);
171da177e4SLinus Torvalds
EmulateCPDO(const unsigned int opcode)181da177e4SLinus Torvalds unsigned int EmulateCPDO(const unsigned int opcode)
191da177e4SLinus Torvalds {
201da177e4SLinus Torvalds FPA11 *fpa11 = GET_FPA11();
211da177e4SLinus Torvalds FPREG *rFd;
221da177e4SLinus Torvalds unsigned int nType, nDest, nRc;
23f148af25SRichard Purdie struct roundingData roundData;
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds /* Get the destination size. If not valid let Linux perform
261da177e4SLinus Torvalds an invalid instruction trap. */
271da177e4SLinus Torvalds nDest = getDestinationSize(opcode);
281da177e4SLinus Torvalds if (typeNone == nDest)
291da177e4SLinus Torvalds return 0;
301da177e4SLinus Torvalds
31f148af25SRichard Purdie roundData.mode = SetRoundingMode(opcode);
32f148af25SRichard Purdie roundData.precision = SetRoundingPrecision(opcode);
33f148af25SRichard Purdie roundData.exception = 0;
341da177e4SLinus Torvalds
351da177e4SLinus Torvalds /* Compare the size of the operands in Fn and Fm.
361da177e4SLinus Torvalds Choose the largest size and perform operations in that size,
371da177e4SLinus Torvalds in order to make use of all the precision of the operands.
381da177e4SLinus Torvalds If Fm is a constant, we just grab a constant of a size
391da177e4SLinus Torvalds matching the size of the operand in Fn. */
401da177e4SLinus Torvalds if (MONADIC_INSTRUCTION(opcode))
411da177e4SLinus Torvalds nType = nDest;
421da177e4SLinus Torvalds else
431da177e4SLinus Torvalds nType = fpa11->fType[getFn(opcode)];
441da177e4SLinus Torvalds
451da177e4SLinus Torvalds if (!CONSTANT_FM(opcode)) {
461da177e4SLinus Torvalds register unsigned int Fm = getFm(opcode);
471da177e4SLinus Torvalds if (nType < fpa11->fType[Fm]) {
481da177e4SLinus Torvalds nType = fpa11->fType[Fm];
491da177e4SLinus Torvalds }
501da177e4SLinus Torvalds }
511da177e4SLinus Torvalds
521da177e4SLinus Torvalds rFd = &fpa11->fpreg[getFd(opcode)];
531da177e4SLinus Torvalds
541da177e4SLinus Torvalds switch (nType) {
551da177e4SLinus Torvalds case typeSingle:
56f148af25SRichard Purdie nRc = SingleCPDO(&roundData, opcode, rFd);
571da177e4SLinus Torvalds break;
581da177e4SLinus Torvalds case typeDouble:
59f148af25SRichard Purdie nRc = DoubleCPDO(&roundData, opcode, rFd);
601da177e4SLinus Torvalds break;
611da177e4SLinus Torvalds #ifdef CONFIG_FPE_NWFPE_XP
621da177e4SLinus Torvalds case typeExtended:
63f148af25SRichard Purdie nRc = ExtendedCPDO(&roundData, opcode, rFd);
641da177e4SLinus Torvalds break;
651da177e4SLinus Torvalds #endif
661da177e4SLinus Torvalds default:
671da177e4SLinus Torvalds nRc = 0;
681da177e4SLinus Torvalds }
691da177e4SLinus Torvalds
701da177e4SLinus Torvalds /* The CPDO functions used to always set the destination type
711da177e4SLinus Torvalds to be the same as their working size. */
721da177e4SLinus Torvalds
731da177e4SLinus Torvalds if (nRc != 0) {
741da177e4SLinus Torvalds /* If the operation succeeded, check to see if the result in the
751da177e4SLinus Torvalds destination register is the correct size. If not force it
761da177e4SLinus Torvalds to be. */
771da177e4SLinus Torvalds
781da177e4SLinus Torvalds fpa11->fType[getFd(opcode)] = nDest;
791da177e4SLinus Torvalds
801da177e4SLinus Torvalds #ifdef CONFIG_FPE_NWFPE_XP
811da177e4SLinus Torvalds if (nDest != nType) {
821da177e4SLinus Torvalds switch (nDest) {
831da177e4SLinus Torvalds case typeSingle:
841da177e4SLinus Torvalds {
851da177e4SLinus Torvalds if (typeDouble == nType)
86f148af25SRichard Purdie rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
871da177e4SLinus Torvalds else
88f148af25SRichard Purdie rFd->fSingle = floatx80_to_float32(&roundData, rFd->fExtended);
891da177e4SLinus Torvalds }
901da177e4SLinus Torvalds break;
911da177e4SLinus Torvalds
921da177e4SLinus Torvalds case typeDouble:
931da177e4SLinus Torvalds {
941da177e4SLinus Torvalds if (typeSingle == nType)
951da177e4SLinus Torvalds rFd->fDouble = float32_to_float64(rFd->fSingle);
961da177e4SLinus Torvalds else
97f148af25SRichard Purdie rFd->fDouble = floatx80_to_float64(&roundData, rFd->fExtended);
981da177e4SLinus Torvalds }
991da177e4SLinus Torvalds break;
1001da177e4SLinus Torvalds
1011da177e4SLinus Torvalds case typeExtended:
1021da177e4SLinus Torvalds {
1031da177e4SLinus Torvalds if (typeSingle == nType)
1041da177e4SLinus Torvalds rFd->fExtended = float32_to_floatx80(rFd->fSingle);
1051da177e4SLinus Torvalds else
1061da177e4SLinus Torvalds rFd->fExtended = float64_to_floatx80(rFd->fDouble);
1071da177e4SLinus Torvalds }
1081da177e4SLinus Torvalds break;
1091da177e4SLinus Torvalds }
1101da177e4SLinus Torvalds }
1111da177e4SLinus Torvalds #else
1121da177e4SLinus Torvalds if (nDest != nType) {
1131da177e4SLinus Torvalds if (nDest == typeSingle)
114f148af25SRichard Purdie rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);
1151da177e4SLinus Torvalds else
1161da177e4SLinus Torvalds rFd->fDouble = float32_to_float64(rFd->fSingle);
1171da177e4SLinus Torvalds }
1181da177e4SLinus Torvalds #endif
1191da177e4SLinus Torvalds }
1201da177e4SLinus Torvalds
121f148af25SRichard Purdie if (roundData.exception)
122f148af25SRichard Purdie float_raise(roundData.exception);
123f148af25SRichard Purdie
1241da177e4SLinus Torvalds return nRc;
1251da177e4SLinus Torvalds }
126