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
1870539e18SBlue Swirl along with this program; if not, see <http://www.gnu.org/licenses/>.
193ebdd119Saurel32 */
203ebdd119Saurel32
21*d39594e9SPeter Maydell #include "qemu/osdep.h"
223ebdd119Saurel32 #include "fpa11.h"
233ebdd119Saurel32 #include "fpopcode.h"
243ebdd119Saurel32
EmulateCPDO(const unsigned int opcode)253ebdd119Saurel32 unsigned int EmulateCPDO(const unsigned int opcode)
263ebdd119Saurel32 {
273ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11();
283ebdd119Saurel32 unsigned int Fd, nType, nDest, nRc = 1;
293ebdd119Saurel32
303ebdd119Saurel32 //printk("EmulateCPDO(0x%08x)\n",opcode);
313ebdd119Saurel32
323ebdd119Saurel32 /* Get the destination size. If not valid let Linux perform
333ebdd119Saurel32 an invalid instruction trap. */
343ebdd119Saurel32 nDest = getDestinationSize(opcode);
353ebdd119Saurel32 if (typeNone == nDest) return 0;
363ebdd119Saurel32
373ebdd119Saurel32 SetRoundingMode(opcode);
383ebdd119Saurel32
393ebdd119Saurel32 /* Compare the size of the operands in Fn and Fm.
403ebdd119Saurel32 Choose the largest size and perform operations in that size,
413ebdd119Saurel32 in order to make use of all the precision of the operands.
423ebdd119Saurel32 If Fm is a constant, we just grab a constant of a size
433ebdd119Saurel32 matching the size of the operand in Fn. */
443ebdd119Saurel32 if (MONADIC_INSTRUCTION(opcode))
453ebdd119Saurel32 nType = nDest;
463ebdd119Saurel32 else
473ebdd119Saurel32 nType = fpa11->fType[getFn(opcode)];
483ebdd119Saurel32
493ebdd119Saurel32 if (!CONSTANT_FM(opcode))
503ebdd119Saurel32 {
513ebdd119Saurel32 register unsigned int Fm = getFm(opcode);
523ebdd119Saurel32 if (nType < fpa11->fType[Fm])
533ebdd119Saurel32 {
543ebdd119Saurel32 nType = fpa11->fType[Fm];
553ebdd119Saurel32 }
563ebdd119Saurel32 }
573ebdd119Saurel32
583ebdd119Saurel32 switch (nType)
593ebdd119Saurel32 {
603ebdd119Saurel32 case typeSingle : nRc = SingleCPDO(opcode); break;
613ebdd119Saurel32 case typeDouble : nRc = DoubleCPDO(opcode); break;
623ebdd119Saurel32 case typeExtended : nRc = ExtendedCPDO(opcode); break;
633ebdd119Saurel32 default : nRc = 0;
643ebdd119Saurel32 }
653ebdd119Saurel32
663ebdd119Saurel32 /* If the operation succeeded, check to see if the result in the
673ebdd119Saurel32 destination register is the correct size. If not force it
683ebdd119Saurel32 to be. */
693ebdd119Saurel32 Fd = getFd(opcode);
703ebdd119Saurel32 nType = fpa11->fType[Fd];
713ebdd119Saurel32 if ((0 != nRc) && (nDest != nType))
723ebdd119Saurel32 {
733ebdd119Saurel32 switch (nDest)
743ebdd119Saurel32 {
753ebdd119Saurel32 case typeSingle:
763ebdd119Saurel32 {
773ebdd119Saurel32 if (typeDouble == nType)
783ebdd119Saurel32 fpa11->fpreg[Fd].fSingle =
793ebdd119Saurel32 float64_to_float32(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status);
803ebdd119Saurel32 else
813ebdd119Saurel32 fpa11->fpreg[Fd].fSingle =
823ebdd119Saurel32 floatx80_to_float32(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status);
833ebdd119Saurel32 }
843ebdd119Saurel32 break;
853ebdd119Saurel32
863ebdd119Saurel32 case typeDouble:
873ebdd119Saurel32 {
883ebdd119Saurel32 if (typeSingle == nType)
893ebdd119Saurel32 fpa11->fpreg[Fd].fDouble =
903ebdd119Saurel32 float32_to_float64(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status);
913ebdd119Saurel32 else
923ebdd119Saurel32 fpa11->fpreg[Fd].fDouble =
933ebdd119Saurel32 floatx80_to_float64(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status);
943ebdd119Saurel32 }
953ebdd119Saurel32 break;
963ebdd119Saurel32
973ebdd119Saurel32 case typeExtended:
983ebdd119Saurel32 {
993ebdd119Saurel32 if (typeSingle == nType)
1003ebdd119Saurel32 fpa11->fpreg[Fd].fExtended =
1013ebdd119Saurel32 float32_to_floatx80(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status);
1023ebdd119Saurel32 else
1033ebdd119Saurel32 fpa11->fpreg[Fd].fExtended =
1043ebdd119Saurel32 float64_to_floatx80(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status);
1053ebdd119Saurel32 }
1063ebdd119Saurel32 break;
1073ebdd119Saurel32 }
1083ebdd119Saurel32
1093ebdd119Saurel32 fpa11->fType[Fd] = nDest;
1103ebdd119Saurel32 }
1113ebdd119Saurel32
1123ebdd119Saurel32 return nRc;
1133ebdd119Saurel32 }
114