13ebdd119Saurel32 /* 23ebdd119Saurel32 NetWinder Floating Point Emulator 33ebdd119Saurel32 (c) Rebel.COM, 1998,1999 43ebdd119Saurel32 53ebdd119Saurel32 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> 63ebdd119Saurel32 73ebdd119Saurel32 This program is free software; you can redistribute it and/or modify 83ebdd119Saurel32 it under the terms of the GNU General Public License as published by 93ebdd119Saurel32 the Free Software Foundation; either version 2 of the License, or 103ebdd119Saurel32 (at your option) any later version. 113ebdd119Saurel32 123ebdd119Saurel32 This program is distributed in the hope that it will be useful, 133ebdd119Saurel32 but WITHOUT ANY WARRANTY; without even the implied warranty of 143ebdd119Saurel32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 153ebdd119Saurel32 GNU General Public License for more details. 163ebdd119Saurel32 173ebdd119Saurel32 You should have received a copy of the GNU General Public License 18*70539e18SBlue Swirl along with this program; if not, see <http://www.gnu.org/licenses/>. 193ebdd119Saurel32 */ 203ebdd119Saurel32 213ebdd119Saurel32 #include "fpa11.h" 223ebdd119Saurel32 #include "fpopcode.h" 233ebdd119Saurel32 243ebdd119Saurel32 unsigned int EmulateCPDO(const unsigned int opcode) 253ebdd119Saurel32 { 263ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11(); 273ebdd119Saurel32 unsigned int Fd, nType, nDest, nRc = 1; 283ebdd119Saurel32 293ebdd119Saurel32 //printk("EmulateCPDO(0x%08x)\n",opcode); 303ebdd119Saurel32 313ebdd119Saurel32 /* Get the destination size. If not valid let Linux perform 323ebdd119Saurel32 an invalid instruction trap. */ 333ebdd119Saurel32 nDest = getDestinationSize(opcode); 343ebdd119Saurel32 if (typeNone == nDest) return 0; 353ebdd119Saurel32 363ebdd119Saurel32 SetRoundingMode(opcode); 373ebdd119Saurel32 383ebdd119Saurel32 /* Compare the size of the operands in Fn and Fm. 393ebdd119Saurel32 Choose the largest size and perform operations in that size, 403ebdd119Saurel32 in order to make use of all the precision of the operands. 413ebdd119Saurel32 If Fm is a constant, we just grab a constant of a size 423ebdd119Saurel32 matching the size of the operand in Fn. */ 433ebdd119Saurel32 if (MONADIC_INSTRUCTION(opcode)) 443ebdd119Saurel32 nType = nDest; 453ebdd119Saurel32 else 463ebdd119Saurel32 nType = fpa11->fType[getFn(opcode)]; 473ebdd119Saurel32 483ebdd119Saurel32 if (!CONSTANT_FM(opcode)) 493ebdd119Saurel32 { 503ebdd119Saurel32 register unsigned int Fm = getFm(opcode); 513ebdd119Saurel32 if (nType < fpa11->fType[Fm]) 523ebdd119Saurel32 { 533ebdd119Saurel32 nType = fpa11->fType[Fm]; 543ebdd119Saurel32 } 553ebdd119Saurel32 } 563ebdd119Saurel32 573ebdd119Saurel32 switch (nType) 583ebdd119Saurel32 { 593ebdd119Saurel32 case typeSingle : nRc = SingleCPDO(opcode); break; 603ebdd119Saurel32 case typeDouble : nRc = DoubleCPDO(opcode); break; 613ebdd119Saurel32 case typeExtended : nRc = ExtendedCPDO(opcode); break; 623ebdd119Saurel32 default : nRc = 0; 633ebdd119Saurel32 } 643ebdd119Saurel32 653ebdd119Saurel32 /* If the operation succeeded, check to see if the result in the 663ebdd119Saurel32 destination register is the correct size. If not force it 673ebdd119Saurel32 to be. */ 683ebdd119Saurel32 Fd = getFd(opcode); 693ebdd119Saurel32 nType = fpa11->fType[Fd]; 703ebdd119Saurel32 if ((0 != nRc) && (nDest != nType)) 713ebdd119Saurel32 { 723ebdd119Saurel32 switch (nDest) 733ebdd119Saurel32 { 743ebdd119Saurel32 case typeSingle: 753ebdd119Saurel32 { 763ebdd119Saurel32 if (typeDouble == nType) 773ebdd119Saurel32 fpa11->fpreg[Fd].fSingle = 783ebdd119Saurel32 float64_to_float32(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status); 793ebdd119Saurel32 else 803ebdd119Saurel32 fpa11->fpreg[Fd].fSingle = 813ebdd119Saurel32 floatx80_to_float32(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); 823ebdd119Saurel32 } 833ebdd119Saurel32 break; 843ebdd119Saurel32 853ebdd119Saurel32 case typeDouble: 863ebdd119Saurel32 { 873ebdd119Saurel32 if (typeSingle == nType) 883ebdd119Saurel32 fpa11->fpreg[Fd].fDouble = 893ebdd119Saurel32 float32_to_float64(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status); 903ebdd119Saurel32 else 913ebdd119Saurel32 fpa11->fpreg[Fd].fDouble = 923ebdd119Saurel32 floatx80_to_float64(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); 933ebdd119Saurel32 } 943ebdd119Saurel32 break; 953ebdd119Saurel32 963ebdd119Saurel32 case typeExtended: 973ebdd119Saurel32 { 983ebdd119Saurel32 if (typeSingle == nType) 993ebdd119Saurel32 fpa11->fpreg[Fd].fExtended = 1003ebdd119Saurel32 float32_to_floatx80(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status); 1013ebdd119Saurel32 else 1023ebdd119Saurel32 fpa11->fpreg[Fd].fExtended = 1033ebdd119Saurel32 float64_to_floatx80(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status); 1043ebdd119Saurel32 } 1053ebdd119Saurel32 break; 1063ebdd119Saurel32 } 1073ebdd119Saurel32 1083ebdd119Saurel32 fpa11->fType[Fd] = nDest; 1093ebdd119Saurel32 } 1103ebdd119Saurel32 1113ebdd119Saurel32 return nRc; 1123ebdd119Saurel32 } 113