Add qemu 2.4.0
[kvmfornfv.git] / qemu / linux-user / arm / nwfpe / fpa11_cprt.c
1 /*
2     NetWinder Floating Point Emulator
3     (c) Rebel.COM, 1998,1999
4     (c) Philip Blundell, 1999
5
6     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "fpa11.h"
23 #include "fpu/softfloat.h"
24 #include "fpopcode.h"
25 #include "fpa11.inl"
26 //#include "fpmodule.h"
27 //#include "fpmodule.inl"
28
29 unsigned int PerformFLT(const unsigned int opcode);
30 unsigned int PerformFIX(const unsigned int opcode);
31
32 static unsigned int
33 PerformComparison(const unsigned int opcode);
34
35 unsigned int EmulateCPRT(const unsigned int opcode)
36 {
37   unsigned int nRc = 1;
38
39   //printk("EmulateCPRT(0x%08x)\n",opcode);
40
41   if (opcode & 0x800000)
42   {
43      /* This is some variant of a comparison (PerformComparison will
44         sort out which one).  Since most of the other CPRT
45         instructions are oddball cases of some sort or other it makes
46         sense to pull this out into a fast path.  */
47      return PerformComparison(opcode);
48   }
49
50   /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
51   switch ((opcode & 0x700000) >> 20)
52   {
53     case  FLT_CODE >> 20: nRc = PerformFLT(opcode); break;
54     case  FIX_CODE >> 20: nRc = PerformFIX(opcode); break;
55
56     case  WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break;
57     case  RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break;
58
59 #if 0    /* We currently have no use for the FPCR, so there's no point
60             in emulating it. */
61     case  WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode)));
62     case  RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break;
63 #endif
64
65     default: nRc = 0;
66   }
67
68   return nRc;
69 }
70
71 unsigned int PerformFLT(const unsigned int opcode)
72 {
73    FPA11 *fpa11 = GET_FPA11();
74
75    unsigned int nRc = 1;
76    SetRoundingMode(opcode);
77
78    switch (opcode & MASK_ROUNDING_PRECISION)
79    {
80       case ROUND_SINGLE:
81       {
82         fpa11->fType[getFn(opcode)] = typeSingle;
83         fpa11->fpreg[getFn(opcode)].fSingle =
84            int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status);
85       }
86       break;
87
88       case ROUND_DOUBLE:
89       {
90         fpa11->fType[getFn(opcode)] = typeDouble;
91         fpa11->fpreg[getFn(opcode)].fDouble =
92             int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status);
93       }
94       break;
95
96       case ROUND_EXTENDED:
97       {
98         fpa11->fType[getFn(opcode)] = typeExtended;
99         fpa11->fpreg[getFn(opcode)].fExtended =
100            int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status);
101       }
102       break;
103
104       default: nRc = 0;
105   }
106
107   return nRc;
108 }
109
110 unsigned int PerformFIX(const unsigned int opcode)
111 {
112    FPA11 *fpa11 = GET_FPA11();
113    unsigned int nRc = 1;
114    unsigned int Fn = getFm(opcode);
115
116    SetRoundingMode(opcode);
117
118    switch (fpa11->fType[Fn])
119    {
120       case typeSingle:
121       {
122          writeRegister(getRd(opcode),
123                        float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status));
124       }
125       break;
126
127       case typeDouble:
128       {
129          //printf("F%d is 0x%" PRIx64 "\n",Fn,fpa11->fpreg[Fn].fDouble);
130          writeRegister(getRd(opcode),
131                        float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status));
132       }
133       break;
134
135       case typeExtended:
136       {
137          writeRegister(getRd(opcode),
138                        floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status));
139       }
140       break;
141
142       default: nRc = 0;
143   }
144
145   return nRc;
146 }
147
148
149 static __inline unsigned int
150 PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
151 {
152    FPA11 *fpa11 = GET_FPA11();
153    unsigned int flags = 0;
154
155    /* test for less than condition */
156    if (floatx80_lt(Fn,Fm, &fpa11->fp_status))
157    {
158       flags |= CC_NEGATIVE;
159    }
160
161    /* test for equal condition */
162    if (floatx80_eq_quiet(Fn,Fm, &fpa11->fp_status))
163    {
164       flags |= CC_ZERO;
165    }
166
167    /* test for greater than or equal condition */
168    if (floatx80_lt(Fm,Fn, &fpa11->fp_status))
169    {
170       flags |= CC_CARRY;
171    }
172
173    writeConditionCodes(flags);
174    return 1;
175 }
176
177 /* This instruction sets the flags N, Z, C, V in the FPSR. */
178
179 static unsigned int PerformComparison(const unsigned int opcode)
180 {
181    FPA11 *fpa11 = GET_FPA11();
182    unsigned int Fn, Fm;
183    floatx80 rFn, rFm;
184    int e_flag = opcode & 0x400000;      /* 1 if CxFE */
185    int n_flag = opcode & 0x200000;      /* 1 if CNxx */
186    unsigned int flags = 0;
187
188    //printk("PerformComparison(0x%08x)\n",opcode);
189
190    Fn = getFn(opcode);
191    Fm = getFm(opcode);
192
193    /* Check for unordered condition and convert all operands to 80-bit
194       format.
195       ?? Might be some mileage in avoiding this conversion if possible.
196       Eg, if both operands are 32-bit, detect this and do a 32-bit
197       comparison (cheaper than an 80-bit one).  */
198    switch (fpa11->fType[Fn])
199    {
200       case typeSingle:
201         //printk("single.\n");
202         if (float32_is_any_nan(fpa11->fpreg[Fn].fSingle))
203            goto unordered;
204         rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
205       break;
206
207       case typeDouble:
208         //printk("double.\n");
209         if (float64_is_any_nan(fpa11->fpreg[Fn].fDouble))
210            goto unordered;
211         rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
212       break;
213
214       case typeExtended:
215         //printk("extended.\n");
216         if (floatx80_is_any_nan(fpa11->fpreg[Fn].fExtended))
217            goto unordered;
218         rFn = fpa11->fpreg[Fn].fExtended;
219       break;
220
221       default: return 0;
222    }
223
224    if (CONSTANT_FM(opcode))
225    {
226      //printk("Fm is a constant: #%d.\n",Fm);
227      rFm = getExtendedConstant(Fm);
228      if (floatx80_is_any_nan(rFm))
229         goto unordered;
230    }
231    else
232    {
233      //printk("Fm = r%d which contains a ",Fm);
234       switch (fpa11->fType[Fm])
235       {
236          case typeSingle:
237            //printk("single.\n");
238            if (float32_is_any_nan(fpa11->fpreg[Fm].fSingle))
239               goto unordered;
240            rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
241          break;
242
243          case typeDouble:
244            //printk("double.\n");
245            if (float64_is_any_nan(fpa11->fpreg[Fm].fDouble))
246               goto unordered;
247            rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
248          break;
249
250          case typeExtended:
251            //printk("extended.\n");
252            if (floatx80_is_any_nan(fpa11->fpreg[Fm].fExtended))
253               goto unordered;
254            rFm = fpa11->fpreg[Fm].fExtended;
255          break;
256
257          default: return 0;
258       }
259    }
260
261    if (n_flag)
262    {
263       rFm.high ^= 0x8000;
264    }
265
266    return PerformComparisonOperation(rFn,rFm);
267
268  unordered:
269    /* ?? The FPA data sheet is pretty vague about this, in particular
270       about whether the non-E comparisons can ever raise exceptions.
271       This implementation is based on a combination of what it says in
272       the data sheet, observation of how the Acorn emulator actually
273       behaves (and how programs expect it to) and guesswork.  */
274    flags |= CC_OVERFLOW;
275    flags &= ~(CC_ZERO | CC_NEGATIVE);
276
277    if (BIT_AC & readFPSR()) flags |= CC_CARRY;
278
279    if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status);
280
281    writeConditionCodes(flags);
282    return 1;
283 }