]> git.proxmox.com Git - qemu.git/blame - target-arm/nwfpe/fpa11_cprt.c
find -type f | xargs sed -i 's/[\t ]*$//g' # Yes, again. Note the star in the regex.
[qemu.git] / target-arm / nwfpe / fpa11_cprt.c
CommitLineData
00406dff
FB
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"
00406dff
FB
24#include "softfloat.h"
25#include "fpopcode.h"
26#include "fpa11.inl"
27//#include "fpmodule.h"
28//#include "fpmodule.inl"
29
00406dff
FB
30void SetRoundingMode(const unsigned int opcode);
31
32unsigned int PerformFLT(const unsigned int opcode);
33unsigned int PerformFIX(const unsigned int opcode);
34
35static unsigned int
36PerformComparison(const unsigned int opcode);
37
38unsigned 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;
3b46e624 58
00406dff
FB
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 }
3b46e624 70
00406dff
FB
71 return nRc;
72}
73
74unsigned int PerformFLT(const unsigned int opcode)
75{
76 FPA11 *fpa11 = GET_FPA11();
3b46e624 77
00406dff
FB
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 =
20495218 87 int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status);
00406dff
FB
88 }
89 break;
90
91 case ROUND_DOUBLE:
92 {
93 fpa11->fType[getFn(opcode)] = typeDouble;
94 fpa11->fpreg[getFn(opcode)].fDouble =
20495218 95 int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status);
00406dff
FB
96 }
97 break;
3b46e624 98
00406dff
FB
99 case ROUND_EXTENDED:
100 {
101 fpa11->fType[getFn(opcode)] = typeExtended;
102 fpa11->fpreg[getFn(opcode)].fExtended =
20495218 103 int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status);
00406dff
FB
104 }
105 break;
3b46e624 106
00406dff
FB
107 default: nRc = 0;
108 }
3b46e624 109
00406dff
FB
110 return nRc;
111}
112
113unsigned int PerformFIX(const unsigned int opcode)
114{
115 FPA11 *fpa11 = GET_FPA11();
116 unsigned int nRc = 1;
117 unsigned int Fn = getFm(opcode);
3b46e624 118
00406dff
FB
119 SetRoundingMode(opcode);
120
121 switch (fpa11->fType[Fn])
122 {
123 case typeSingle:
124 {
125 writeRegister(getRd(opcode),
20495218 126 float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status));
00406dff
FB
127 }
128 break;
129
130 case typeDouble:
131 {
26a76461 132 //printf("F%d is 0x%" PRIx64 "\n",Fn,fpa11->fpreg[Fn].fDouble);
00406dff 133 writeRegister(getRd(opcode),
20495218 134 float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status));
00406dff
FB
135 }
136 break;
3b46e624 137
00406dff
FB
138 case typeExtended:
139 {
140 writeRegister(getRd(opcode),
20495218 141 floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status));
00406dff
FB
142 }
143 break;
3b46e624 144
00406dff
FB
145 default: nRc = 0;
146 }
3b46e624 147
00406dff
FB
148 return nRc;
149}
150
3b46e624 151
00406dff
FB
152static unsigned int __inline__
153PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
154{
20495218 155 FPA11 *fpa11 = GET_FPA11();
00406dff
FB
156 unsigned int flags = 0;
157
158 /* test for less than condition */
20495218 159 if (floatx80_lt(Fn,Fm, &fpa11->fp_status))
00406dff
FB
160 {
161 flags |= CC_NEGATIVE;
162 }
3b46e624 163
00406dff 164 /* test for equal condition */
20495218 165 if (floatx80_eq(Fn,Fm, &fpa11->fp_status))
00406dff
FB
166 {
167 flags |= CC_ZERO;
168 }
169
170 /* test for greater than or equal condition */
20495218 171 if (floatx80_lt(Fm,Fn, &fpa11->fp_status))
00406dff
FB
172 {
173 flags |= CC_CARRY;
174 }
3b46e624 175
00406dff
FB
176 writeConditionCodes(flags);
177 return 1;
178}
179
180/* This instruction sets the flags N, Z, C, V in the FPSR. */
3b46e624 181
00406dff
FB
182static 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 {
5fafdf24 203 case typeSingle:
00406dff
FB
204 //printk("single.\n");
205 if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
206 goto unordered;
20495218 207 rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
00406dff
FB
208 break;
209
5fafdf24 210 case typeDouble:
00406dff
FB
211 //printk("double.\n");
212 if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
213 goto unordered;
20495218 214 rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
00406dff 215 break;
3b46e624 216
5fafdf24 217 case typeExtended:
00406dff
FB
218 //printk("extended.\n");
219 if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
220 goto unordered;
221 rFn = fpa11->fpreg[Fn].fExtended;
222 break;
3b46e624 223
00406dff
FB
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 {
5fafdf24 239 case typeSingle:
00406dff
FB
240 //printk("single.\n");
241 if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
242 goto unordered;
20495218 243 rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
00406dff
FB
244 break;
245
5fafdf24 246 case typeDouble:
00406dff
FB
247 //printk("double.\n");
248 if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
249 goto unordered;
20495218 250 rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
00406dff 251 break;
3b46e624 252
5fafdf24 253 case typeExtended:
00406dff
FB
254 //printk("extended.\n");
255 if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
256 goto unordered;
257 rFm = fpa11->fpreg[Fm].fExtended;
258 break;
3b46e624 259
00406dff
FB
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
20495218 282 if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status);
00406dff
FB
283
284 writeConditionCodes(flags);
285 return 1;
286}