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