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