]> git.proxmox.com Git - mirror_qemu.git/blame - linux-user/arm/nwfpe/fpa11_cprt.c
static and inline should came before the type of the functions
[mirror_qemu.git] / linux-user / 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
30unsigned int PerformFLT(const unsigned int opcode);
31unsigned int PerformFIX(const unsigned int opcode);
32
33static unsigned int
34PerformComparison(const unsigned int opcode);
35
36unsigned 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;
3b46e624 56
00406dff
FB
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 }
3b46e624 68
00406dff
FB
69 return nRc;
70}
71
72unsigned int PerformFLT(const unsigned int opcode)
73{
74 FPA11 *fpa11 = GET_FPA11();
3b46e624 75
00406dff
FB
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 =
20495218 85 int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status);
00406dff
FB
86 }
87 break;
88
89 case ROUND_DOUBLE:
90 {
91 fpa11->fType[getFn(opcode)] = typeDouble;
92 fpa11->fpreg[getFn(opcode)].fDouble =
20495218 93 int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status);
00406dff
FB
94 }
95 break;
3b46e624 96
00406dff
FB
97 case ROUND_EXTENDED:
98 {
99 fpa11->fType[getFn(opcode)] = typeExtended;
100 fpa11->fpreg[getFn(opcode)].fExtended =
20495218 101 int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status);
00406dff
FB
102 }
103 break;
3b46e624 104
00406dff
FB
105 default: nRc = 0;
106 }
3b46e624 107
00406dff
FB
108 return nRc;
109}
110
111unsigned int PerformFIX(const unsigned int opcode)
112{
113 FPA11 *fpa11 = GET_FPA11();
114 unsigned int nRc = 1;
115 unsigned int Fn = getFm(opcode);
3b46e624 116
00406dff
FB
117 SetRoundingMode(opcode);
118
119 switch (fpa11->fType[Fn])
120 {
121 case typeSingle:
122 {
123 writeRegister(getRd(opcode),
20495218 124 float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status));
00406dff
FB
125 }
126 break;
127
128 case typeDouble:
129 {
26a76461 130 //printf("F%d is 0x%" PRIx64 "\n",Fn,fpa11->fpreg[Fn].fDouble);
00406dff 131 writeRegister(getRd(opcode),
20495218 132 float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status));
00406dff
FB
133 }
134 break;
3b46e624 135
00406dff
FB
136 case typeExtended:
137 {
138 writeRegister(getRd(opcode),
20495218 139 floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status));
00406dff
FB
140 }
141 break;
3b46e624 142
00406dff
FB
143 default: nRc = 0;
144 }
3b46e624 145
00406dff
FB
146 return nRc;
147}
148
3b46e624 149
86178a57 150static __inline unsigned int
00406dff
FB
151PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
152{
20495218 153 FPA11 *fpa11 = GET_FPA11();
00406dff
FB
154 unsigned int flags = 0;
155
156 /* test for less than condition */
20495218 157 if (floatx80_lt(Fn,Fm, &fpa11->fp_status))
00406dff
FB
158 {
159 flags |= CC_NEGATIVE;
160 }
3b46e624 161
00406dff 162 /* test for equal condition */
20495218 163 if (floatx80_eq(Fn,Fm, &fpa11->fp_status))
00406dff
FB
164 {
165 flags |= CC_ZERO;
166 }
167
168 /* test for greater than or equal condition */
20495218 169 if (floatx80_lt(Fm,Fn, &fpa11->fp_status))
00406dff
FB
170 {
171 flags |= CC_CARRY;
172 }
3b46e624 173
00406dff
FB
174 writeConditionCodes(flags);
175 return 1;
176}
177
178/* This instruction sets the flags N, Z, C, V in the FPSR. */
3b46e624 179
00406dff
FB
180static 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 {
5fafdf24 201 case typeSingle:
00406dff
FB
202 //printk("single.\n");
203 if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
204 goto unordered;
20495218 205 rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
00406dff
FB
206 break;
207
5fafdf24 208 case typeDouble:
00406dff
FB
209 //printk("double.\n");
210 if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
211 goto unordered;
20495218 212 rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
00406dff 213 break;
3b46e624 214
5fafdf24 215 case typeExtended:
00406dff
FB
216 //printk("extended.\n");
217 if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
218 goto unordered;
219 rFn = fpa11->fpreg[Fn].fExtended;
220 break;
3b46e624 221
00406dff
FB
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_nan(rFm))
230 goto unordered;
231 }
232 else
233 {
234 //printk("Fm = r%d which contains a ",Fm);
235 switch (fpa11->fType[Fm])
236 {
5fafdf24 237 case typeSingle:
00406dff
FB
238 //printk("single.\n");
239 if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
240 goto unordered;
20495218 241 rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
00406dff
FB
242 break;
243
5fafdf24 244 case typeDouble:
00406dff
FB
245 //printk("double.\n");
246 if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
247 goto unordered;
20495218 248 rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
00406dff 249 break;
3b46e624 250
5fafdf24 251 case typeExtended:
00406dff
FB
252 //printk("extended.\n");
253 if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
254 goto unordered;
255 rFm = fpa11->fpreg[Fm].fExtended;
256 break;
3b46e624 257
00406dff
FB
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
20495218 280 if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status);
00406dff
FB
281
282 writeConditionCodes(flags);
283 return 1;
284}