xref: /qemu/linux-user/arm/nwfpe/fpa11_cpdo.c (revision d39594e9)
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