18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci NetWinder Floating Point Emulator 48c2ecf20Sopenharmony_ci (c) Rebel.COM, 1998,1999 58c2ecf20Sopenharmony_ci (c) Philip Blundell, 2001 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci Direct questions, comments to Scott Bambrough <scottb@netwinder.org> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci*/ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "fpa11.h" 128c2ecf20Sopenharmony_ci#include "fpopcode.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ciunsigned int SingleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd); 158c2ecf20Sopenharmony_ciunsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd); 168c2ecf20Sopenharmony_ciunsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd); 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ciunsigned int EmulateCPDO(const unsigned int opcode) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci FPA11 *fpa11 = GET_FPA11(); 218c2ecf20Sopenharmony_ci FPREG *rFd; 228c2ecf20Sopenharmony_ci unsigned int nType, nDest, nRc; 238c2ecf20Sopenharmony_ci struct roundingData roundData; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci /* Get the destination size. If not valid let Linux perform 268c2ecf20Sopenharmony_ci an invalid instruction trap. */ 278c2ecf20Sopenharmony_ci nDest = getDestinationSize(opcode); 288c2ecf20Sopenharmony_ci if (typeNone == nDest) 298c2ecf20Sopenharmony_ci return 0; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci roundData.mode = SetRoundingMode(opcode); 328c2ecf20Sopenharmony_ci roundData.precision = SetRoundingPrecision(opcode); 338c2ecf20Sopenharmony_ci roundData.exception = 0; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci /* Compare the size of the operands in Fn and Fm. 368c2ecf20Sopenharmony_ci Choose the largest size and perform operations in that size, 378c2ecf20Sopenharmony_ci in order to make use of all the precision of the operands. 388c2ecf20Sopenharmony_ci If Fm is a constant, we just grab a constant of a size 398c2ecf20Sopenharmony_ci matching the size of the operand in Fn. */ 408c2ecf20Sopenharmony_ci if (MONADIC_INSTRUCTION(opcode)) 418c2ecf20Sopenharmony_ci nType = nDest; 428c2ecf20Sopenharmony_ci else 438c2ecf20Sopenharmony_ci nType = fpa11->fType[getFn(opcode)]; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (!CONSTANT_FM(opcode)) { 468c2ecf20Sopenharmony_ci register unsigned int Fm = getFm(opcode); 478c2ecf20Sopenharmony_ci if (nType < fpa11->fType[Fm]) { 488c2ecf20Sopenharmony_ci nType = fpa11->fType[Fm]; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci rFd = &fpa11->fpreg[getFd(opcode)]; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci switch (nType) { 558c2ecf20Sopenharmony_ci case typeSingle: 568c2ecf20Sopenharmony_ci nRc = SingleCPDO(&roundData, opcode, rFd); 578c2ecf20Sopenharmony_ci break; 588c2ecf20Sopenharmony_ci case typeDouble: 598c2ecf20Sopenharmony_ci nRc = DoubleCPDO(&roundData, opcode, rFd); 608c2ecf20Sopenharmony_ci break; 618c2ecf20Sopenharmony_ci#ifdef CONFIG_FPE_NWFPE_XP 628c2ecf20Sopenharmony_ci case typeExtended: 638c2ecf20Sopenharmony_ci nRc = ExtendedCPDO(&roundData, opcode, rFd); 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci#endif 668c2ecf20Sopenharmony_ci default: 678c2ecf20Sopenharmony_ci nRc = 0; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* The CPDO functions used to always set the destination type 718c2ecf20Sopenharmony_ci to be the same as their working size. */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (nRc != 0) { 748c2ecf20Sopenharmony_ci /* If the operation succeeded, check to see if the result in the 758c2ecf20Sopenharmony_ci destination register is the correct size. If not force it 768c2ecf20Sopenharmony_ci to be. */ 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci fpa11->fType[getFd(opcode)] = nDest; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#ifdef CONFIG_FPE_NWFPE_XP 818c2ecf20Sopenharmony_ci if (nDest != nType) { 828c2ecf20Sopenharmony_ci switch (nDest) { 838c2ecf20Sopenharmony_ci case typeSingle: 848c2ecf20Sopenharmony_ci { 858c2ecf20Sopenharmony_ci if (typeDouble == nType) 868c2ecf20Sopenharmony_ci rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble); 878c2ecf20Sopenharmony_ci else 888c2ecf20Sopenharmony_ci rFd->fSingle = floatx80_to_float32(&roundData, rFd->fExtended); 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci case typeDouble: 938c2ecf20Sopenharmony_ci { 948c2ecf20Sopenharmony_ci if (typeSingle == nType) 958c2ecf20Sopenharmony_ci rFd->fDouble = float32_to_float64(rFd->fSingle); 968c2ecf20Sopenharmony_ci else 978c2ecf20Sopenharmony_ci rFd->fDouble = floatx80_to_float64(&roundData, rFd->fExtended); 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci case typeExtended: 1028c2ecf20Sopenharmony_ci { 1038c2ecf20Sopenharmony_ci if (typeSingle == nType) 1048c2ecf20Sopenharmony_ci rFd->fExtended = float32_to_floatx80(rFd->fSingle); 1058c2ecf20Sopenharmony_ci else 1068c2ecf20Sopenharmony_ci rFd->fExtended = float64_to_floatx80(rFd->fDouble); 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci break; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci#else 1128c2ecf20Sopenharmony_ci if (nDest != nType) { 1138c2ecf20Sopenharmony_ci if (nDest == typeSingle) 1148c2ecf20Sopenharmony_ci rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble); 1158c2ecf20Sopenharmony_ci else 1168c2ecf20Sopenharmony_ci rFd->fDouble = float32_to_float64(rFd->fSingle); 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci#endif 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (roundData.exception) 1228c2ecf20Sopenharmony_ci float_raise(roundData.exception); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return nRc; 1258c2ecf20Sopenharmony_ci} 126