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