1*3ebdd119Saurel32 /* 2*3ebdd119Saurel32 NetWinder Floating Point Emulator 3*3ebdd119Saurel32 (c) Rebel.COM, 1998,1999 4*3ebdd119Saurel32 5*3ebdd119Saurel32 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> 6*3ebdd119Saurel32 7*3ebdd119Saurel32 This program is free software; you can redistribute it and/or modify 8*3ebdd119Saurel32 it under the terms of the GNU General Public License as published by 9*3ebdd119Saurel32 the Free Software Foundation; either version 2 of the License, or 10*3ebdd119Saurel32 (at your option) any later version. 11*3ebdd119Saurel32 12*3ebdd119Saurel32 This program is distributed in the hope that it will be useful, 13*3ebdd119Saurel32 but WITHOUT ANY WARRANTY; without even the implied warranty of 14*3ebdd119Saurel32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*3ebdd119Saurel32 GNU General Public License for more details. 16*3ebdd119Saurel32 17*3ebdd119Saurel32 You should have received a copy of the GNU General Public License 18*3ebdd119Saurel32 along with this program; if not, write to the Free Software 19*3ebdd119Saurel32 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20*3ebdd119Saurel32 */ 21*3ebdd119Saurel32 22*3ebdd119Saurel32 #include "fpa11.h" 23*3ebdd119Saurel32 #include "fpopcode.h" 24*3ebdd119Saurel32 25*3ebdd119Saurel32 unsigned int SingleCPDO(const unsigned int opcode); 26*3ebdd119Saurel32 unsigned int DoubleCPDO(const unsigned int opcode); 27*3ebdd119Saurel32 unsigned int ExtendedCPDO(const unsigned int opcode); 28*3ebdd119Saurel32 29*3ebdd119Saurel32 unsigned int EmulateCPDO(const unsigned int opcode) 30*3ebdd119Saurel32 { 31*3ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11(); 32*3ebdd119Saurel32 unsigned int Fd, nType, nDest, nRc = 1; 33*3ebdd119Saurel32 34*3ebdd119Saurel32 //printk("EmulateCPDO(0x%08x)\n",opcode); 35*3ebdd119Saurel32 36*3ebdd119Saurel32 /* Get the destination size. If not valid let Linux perform 37*3ebdd119Saurel32 an invalid instruction trap. */ 38*3ebdd119Saurel32 nDest = getDestinationSize(opcode); 39*3ebdd119Saurel32 if (typeNone == nDest) return 0; 40*3ebdd119Saurel32 41*3ebdd119Saurel32 SetRoundingMode(opcode); 42*3ebdd119Saurel32 43*3ebdd119Saurel32 /* Compare the size of the operands in Fn and Fm. 44*3ebdd119Saurel32 Choose the largest size and perform operations in that size, 45*3ebdd119Saurel32 in order to make use of all the precision of the operands. 46*3ebdd119Saurel32 If Fm is a constant, we just grab a constant of a size 47*3ebdd119Saurel32 matching the size of the operand in Fn. */ 48*3ebdd119Saurel32 if (MONADIC_INSTRUCTION(opcode)) 49*3ebdd119Saurel32 nType = nDest; 50*3ebdd119Saurel32 else 51*3ebdd119Saurel32 nType = fpa11->fType[getFn(opcode)]; 52*3ebdd119Saurel32 53*3ebdd119Saurel32 if (!CONSTANT_FM(opcode)) 54*3ebdd119Saurel32 { 55*3ebdd119Saurel32 register unsigned int Fm = getFm(opcode); 56*3ebdd119Saurel32 if (nType < fpa11->fType[Fm]) 57*3ebdd119Saurel32 { 58*3ebdd119Saurel32 nType = fpa11->fType[Fm]; 59*3ebdd119Saurel32 } 60*3ebdd119Saurel32 } 61*3ebdd119Saurel32 62*3ebdd119Saurel32 switch (nType) 63*3ebdd119Saurel32 { 64*3ebdd119Saurel32 case typeSingle : nRc = SingleCPDO(opcode); break; 65*3ebdd119Saurel32 case typeDouble : nRc = DoubleCPDO(opcode); break; 66*3ebdd119Saurel32 case typeExtended : nRc = ExtendedCPDO(opcode); break; 67*3ebdd119Saurel32 default : nRc = 0; 68*3ebdd119Saurel32 } 69*3ebdd119Saurel32 70*3ebdd119Saurel32 /* If the operation succeeded, check to see if the result in the 71*3ebdd119Saurel32 destination register is the correct size. If not force it 72*3ebdd119Saurel32 to be. */ 73*3ebdd119Saurel32 Fd = getFd(opcode); 74*3ebdd119Saurel32 nType = fpa11->fType[Fd]; 75*3ebdd119Saurel32 if ((0 != nRc) && (nDest != nType)) 76*3ebdd119Saurel32 { 77*3ebdd119Saurel32 switch (nDest) 78*3ebdd119Saurel32 { 79*3ebdd119Saurel32 case typeSingle: 80*3ebdd119Saurel32 { 81*3ebdd119Saurel32 if (typeDouble == nType) 82*3ebdd119Saurel32 fpa11->fpreg[Fd].fSingle = 83*3ebdd119Saurel32 float64_to_float32(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status); 84*3ebdd119Saurel32 else 85*3ebdd119Saurel32 fpa11->fpreg[Fd].fSingle = 86*3ebdd119Saurel32 floatx80_to_float32(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); 87*3ebdd119Saurel32 } 88*3ebdd119Saurel32 break; 89*3ebdd119Saurel32 90*3ebdd119Saurel32 case typeDouble: 91*3ebdd119Saurel32 { 92*3ebdd119Saurel32 if (typeSingle == nType) 93*3ebdd119Saurel32 fpa11->fpreg[Fd].fDouble = 94*3ebdd119Saurel32 float32_to_float64(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status); 95*3ebdd119Saurel32 else 96*3ebdd119Saurel32 fpa11->fpreg[Fd].fDouble = 97*3ebdd119Saurel32 floatx80_to_float64(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status); 98*3ebdd119Saurel32 } 99*3ebdd119Saurel32 break; 100*3ebdd119Saurel32 101*3ebdd119Saurel32 case typeExtended: 102*3ebdd119Saurel32 { 103*3ebdd119Saurel32 if (typeSingle == nType) 104*3ebdd119Saurel32 fpa11->fpreg[Fd].fExtended = 105*3ebdd119Saurel32 float32_to_floatx80(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status); 106*3ebdd119Saurel32 else 107*3ebdd119Saurel32 fpa11->fpreg[Fd].fExtended = 108*3ebdd119Saurel32 float64_to_floatx80(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status); 109*3ebdd119Saurel32 } 110*3ebdd119Saurel32 break; 111*3ebdd119Saurel32 } 112*3ebdd119Saurel32 113*3ebdd119Saurel32 fpa11->fType[Fd] = nDest; 114*3ebdd119Saurel32 } 115*3ebdd119Saurel32 116*3ebdd119Saurel32 return nRc; 117*3ebdd119Saurel32 } 118