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