162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci NetWinder Floating Point Emulator 462306a36Sopenharmony_ci (c) Rebel.COM, 1998,1999 562306a36Sopenharmony_ci (c) Philip Blundell, 2001 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci Direct questions, comments to Scott Bambrough <scottb@netwinder.org> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci*/ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "fpa11.h" 1262306a36Sopenharmony_ci#include "fpopcode.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ciunsigned int SingleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd); 1562306a36Sopenharmony_ciunsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd); 1662306a36Sopenharmony_ciunsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd); 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciunsigned int EmulateCPDO(const unsigned int opcode) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci FPA11 *fpa11 = GET_FPA11(); 2162306a36Sopenharmony_ci FPREG *rFd; 2262306a36Sopenharmony_ci unsigned int nType, nDest, nRc; 2362306a36Sopenharmony_ci struct roundingData roundData; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci /* Get the destination size. If not valid let Linux perform 2662306a36Sopenharmony_ci an invalid instruction trap. */ 2762306a36Sopenharmony_ci nDest = getDestinationSize(opcode); 2862306a36Sopenharmony_ci if (typeNone == nDest) 2962306a36Sopenharmony_ci return 0; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci roundData.mode = SetRoundingMode(opcode); 3262306a36Sopenharmony_ci roundData.precision = SetRoundingPrecision(opcode); 3362306a36Sopenharmony_ci roundData.exception = 0; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* Compare the size of the operands in Fn and Fm. 3662306a36Sopenharmony_ci Choose the largest size and perform operations in that size, 3762306a36Sopenharmony_ci in order to make use of all the precision of the operands. 3862306a36Sopenharmony_ci If Fm is a constant, we just grab a constant of a size 3962306a36Sopenharmony_ci matching the size of the operand in Fn. */ 4062306a36Sopenharmony_ci if (MONADIC_INSTRUCTION(opcode)) 4162306a36Sopenharmony_ci nType = nDest; 4262306a36Sopenharmony_ci else 4362306a36Sopenharmony_ci nType = fpa11->fType[getFn(opcode)]; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (!CONSTANT_FM(opcode)) { 4662306a36Sopenharmony_ci register unsigned int Fm = getFm(opcode); 4762306a36Sopenharmony_ci if (nType < fpa11->fType[Fm]) { 4862306a36Sopenharmony_ci nType = fpa11->fType[Fm]; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci rFd = &fpa11->fpreg[getFd(opcode)]; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci switch (nType) { 5562306a36Sopenharmony_ci case typeSingle: 5662306a36Sopenharmony_ci nRc = SingleCPDO(&roundData, opcode, rFd); 5762306a36Sopenharmony_ci break; 5862306a36Sopenharmony_ci case typeDouble: 5962306a36Sopenharmony_ci nRc = DoubleCPDO(&roundData, opcode, rFd); 6062306a36Sopenharmony_ci break; 6162306a36Sopenharmony_ci#ifdef CONFIG_FPE_NWFPE_XP 6262306a36Sopenharmony_ci case typeExtended: 6362306a36Sopenharmony_ci nRc = ExtendedCPDO(&roundData, opcode, rFd); 6462306a36Sopenharmony_ci break; 6562306a36Sopenharmony_ci#endif 6662306a36Sopenharmony_ci default: 6762306a36Sopenharmony_ci nRc = 0; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* The CPDO functions used to always set the destination type 7162306a36Sopenharmony_ci to be the same as their working size. */ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (nRc != 0) { 7462306a36Sopenharmony_ci /* If the operation succeeded, check to see if the result in the 7562306a36Sopenharmony_ci destination register is the correct size. If not force it 7662306a36Sopenharmony_ci to be. */ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci fpa11->fType[getFd(opcode)] = nDest; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#ifdef CONFIG_FPE_NWFPE_XP 8162306a36Sopenharmony_ci if (nDest != nType) { 8262306a36Sopenharmony_ci switch (nDest) { 8362306a36Sopenharmony_ci case typeSingle: 8462306a36Sopenharmony_ci { 8562306a36Sopenharmony_ci if (typeDouble == nType) 8662306a36Sopenharmony_ci rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble); 8762306a36Sopenharmony_ci else 8862306a36Sopenharmony_ci rFd->fSingle = floatx80_to_float32(&roundData, rFd->fExtended); 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci break; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci case typeDouble: 9362306a36Sopenharmony_ci { 9462306a36Sopenharmony_ci if (typeSingle == nType) 9562306a36Sopenharmony_ci rFd->fDouble = float32_to_float64(rFd->fSingle); 9662306a36Sopenharmony_ci else 9762306a36Sopenharmony_ci rFd->fDouble = floatx80_to_float64(&roundData, rFd->fExtended); 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci case typeExtended: 10262306a36Sopenharmony_ci { 10362306a36Sopenharmony_ci if (typeSingle == nType) 10462306a36Sopenharmony_ci rFd->fExtended = float32_to_floatx80(rFd->fSingle); 10562306a36Sopenharmony_ci else 10662306a36Sopenharmony_ci rFd->fExtended = float64_to_floatx80(rFd->fDouble); 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci break; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci#else 11262306a36Sopenharmony_ci if (nDest != nType) { 11362306a36Sopenharmony_ci if (nDest == typeSingle) 11462306a36Sopenharmony_ci rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble); 11562306a36Sopenharmony_ci else 11662306a36Sopenharmony_ci rFd->fDouble = float32_to_float64(rFd->fSingle); 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci#endif 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (roundData.exception) 12262306a36Sopenharmony_ci float_raise(roundData.exception); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return nRc; 12562306a36Sopenharmony_ci} 126