2 NetWinder Floating Point Emulator
3 (c) Rebel.COM, 1998,1999
4 (c) Philip Blundell, 1999, 2001
6 Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
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.
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.
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.
27 #include "fpmodule.inl"
28 #include "softfloat.h"
30 unsigned int PerformFLT(const unsigned int opcode
);
31 unsigned int PerformFIX(const unsigned int opcode
);
33 static unsigned int PerformComparison(const unsigned int opcode
);
35 unsigned int EmulateCPRT(const unsigned int opcode
)
38 if (opcode
& 0x800000) {
39 /* This is some variant of a comparison (PerformComparison
40 will sort out which one). Since most of the other CPRT
41 instructions are oddball cases of some sort or other it
42 makes sense to pull this out into a fast path. */
43 return PerformComparison(opcode
);
46 /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
47 switch ((opcode
& 0x700000) >> 20) {
49 return PerformFLT(opcode
);
52 return PerformFIX(opcode
);
56 writeFPSR(readRegister(getRd(opcode
)));
59 writeRegister(getRd(opcode
), readFPSR());
69 unsigned int PerformFLT(const unsigned int opcode
)
71 FPA11
*fpa11
= GET_FPA11();
72 struct roundingData roundData
;
74 roundData
.mode
= SetRoundingMode(opcode
);
75 roundData
.precision
= SetRoundingPrecision(opcode
);
76 roundData
.exception
= 0;
78 switch (opcode
& MASK_ROUNDING_PRECISION
) {
81 fpa11
->fType
[getFn(opcode
)] = typeSingle
;
82 fpa11
->fpreg
[getFn(opcode
)].fSingle
= int32_to_float32(&roundData
, readRegister(getRd(opcode
)));
88 fpa11
->fType
[getFn(opcode
)] = typeDouble
;
89 fpa11
->fpreg
[getFn(opcode
)].fDouble
= int32_to_float64(readRegister(getRd(opcode
)));
93 #ifdef CONFIG_FPE_NWFPE_XP
96 fpa11
->fType
[getFn(opcode
)] = typeExtended
;
97 fpa11
->fpreg
[getFn(opcode
)].fExtended
= int32_to_floatx80(readRegister(getRd(opcode
)));
106 if (roundData
.exception
)
107 float_raise(roundData
.exception
);
112 unsigned int PerformFIX(const unsigned int opcode
)
114 FPA11
*fpa11
= GET_FPA11();
115 unsigned int Fn
= getFm(opcode
);
116 struct roundingData roundData
;
118 roundData
.mode
= SetRoundingMode(opcode
);
119 roundData
.precision
= SetRoundingPrecision(opcode
);
120 roundData
.exception
= 0;
122 switch (fpa11
->fType
[Fn
]) {
125 writeRegister(getRd(opcode
), float32_to_int32(&roundData
, fpa11
->fpreg
[Fn
].fSingle
));
131 writeRegister(getRd(opcode
), float64_to_int32(&roundData
, fpa11
->fpreg
[Fn
].fDouble
));
135 #ifdef CONFIG_FPE_NWFPE_XP
138 writeRegister(getRd(opcode
), floatx80_to_int32(&roundData
, fpa11
->fpreg
[Fn
].fExtended
));
147 if (roundData
.exception
)
148 float_raise(roundData
.exception
);
153 /* This instruction sets the flags N, Z, C, V in the FPSR. */
154 static unsigned int PerformComparison(const unsigned int opcode
)
156 FPA11
*fpa11
= GET_FPA11();
157 unsigned int Fn
= getFn(opcode
), Fm
= getFm(opcode
);
158 int e_flag
= opcode
& 0x400000; /* 1 if CxFE */
159 int n_flag
= opcode
& 0x200000; /* 1 if CNxx */
160 unsigned int flags
= 0;
162 #ifdef CONFIG_FPE_NWFPE_XP
165 /* Check for unordered condition and convert all operands to 80-bit
167 ?? Might be some mileage in avoiding this conversion if possible.
168 Eg, if both operands are 32-bit, detect this and do a 32-bit
169 comparison (cheaper than an 80-bit one). */
170 switch (fpa11
->fType
[Fn
]) {
172 //printk("single.\n");
173 if (float32_is_nan(fpa11
->fpreg
[Fn
].fSingle
))
175 rFn
= float32_to_floatx80(fpa11
->fpreg
[Fn
].fSingle
);
179 //printk("double.\n");
180 if (float64_is_nan(fpa11
->fpreg
[Fn
].fDouble
))
182 rFn
= float64_to_floatx80(fpa11
->fpreg
[Fn
].fDouble
);
186 //printk("extended.\n");
187 if (floatx80_is_nan(fpa11
->fpreg
[Fn
].fExtended
))
189 rFn
= fpa11
->fpreg
[Fn
].fExtended
;
196 if (CONSTANT_FM(opcode
)) {
197 //printk("Fm is a constant: #%d.\n",Fm);
198 rFm
= getExtendedConstant(Fm
);
199 if (floatx80_is_nan(rFm
))
202 //printk("Fm = r%d which contains a ",Fm);
203 switch (fpa11
->fType
[Fm
]) {
205 //printk("single.\n");
206 if (float32_is_nan(fpa11
->fpreg
[Fm
].fSingle
))
208 rFm
= float32_to_floatx80(fpa11
->fpreg
[Fm
].fSingle
);
212 //printk("double.\n");
213 if (float64_is_nan(fpa11
->fpreg
[Fm
].fDouble
))
215 rFm
= float64_to_floatx80(fpa11
->fpreg
[Fm
].fDouble
);
219 //printk("extended.\n");
220 if (floatx80_is_nan(fpa11
->fpreg
[Fm
].fExtended
))
222 rFm
= fpa11
->fpreg
[Fm
].fExtended
;
233 /* test for less than condition */
234 if (floatx80_lt(rFn
, rFm
))
235 flags
|= CC_NEGATIVE
;
237 /* test for equal condition */
238 if (floatx80_eq(rFn
, rFm
))
241 /* test for greater than or equal condition */
242 if (floatx80_lt(rFm
, rFn
))
246 if (CONSTANT_FM(opcode
)) {
247 /* Fm is a constant. Do the comparison in whatever precision
248 Fn happens to be stored in. */
249 if (fpa11
->fType
[Fn
] == typeSingle
) {
250 float32 rFm
= getSingleConstant(Fm
);
251 float32 rFn
= fpa11
->fpreg
[Fn
].fSingle
;
253 if (float32_is_nan(rFn
))
259 /* test for less than condition */
260 if (float32_lt_nocheck(rFn
, rFm
))
261 flags
|= CC_NEGATIVE
;
263 /* test for equal condition */
264 if (float32_eq_nocheck(rFn
, rFm
))
267 /* test for greater than or equal condition */
268 if (float32_lt_nocheck(rFm
, rFn
))
271 float64 rFm
= getDoubleConstant(Fm
);
272 float64 rFn
= fpa11
->fpreg
[Fn
].fDouble
;
274 if (float64_is_nan(rFn
))
278 rFm
^= 0x8000000000000000ULL
;
280 /* test for less than condition */
281 if (float64_lt_nocheck(rFn
, rFm
))
282 flags
|= CC_NEGATIVE
;
284 /* test for equal condition */
285 if (float64_eq_nocheck(rFn
, rFm
))
288 /* test for greater than or equal condition */
289 if (float64_lt_nocheck(rFm
, rFn
))
293 /* Both operands are in registers. */
294 if (fpa11
->fType
[Fn
] == typeSingle
295 && fpa11
->fType
[Fm
] == typeSingle
) {
296 float32 rFm
= fpa11
->fpreg
[Fm
].fSingle
;
297 float32 rFn
= fpa11
->fpreg
[Fn
].fSingle
;
299 if (float32_is_nan(rFn
)
300 || float32_is_nan(rFm
))
306 /* test for less than condition */
307 if (float32_lt_nocheck(rFn
, rFm
))
308 flags
|= CC_NEGATIVE
;
310 /* test for equal condition */
311 if (float32_eq_nocheck(rFn
, rFm
))
314 /* test for greater than or equal condition */
315 if (float32_lt_nocheck(rFm
, rFn
))
318 /* Promote 32-bit operand to 64 bits. */
321 rFm
= (fpa11
->fType
[Fm
] == typeSingle
) ?
322 float32_to_float64(fpa11
->fpreg
[Fm
].fSingle
)
323 : fpa11
->fpreg
[Fm
].fDouble
;
325 rFn
= (fpa11
->fType
[Fn
] == typeSingle
) ?
326 float32_to_float64(fpa11
->fpreg
[Fn
].fSingle
)
327 : fpa11
->fpreg
[Fn
].fDouble
;
329 if (float64_is_nan(rFn
)
330 || float64_is_nan(rFm
))
334 rFm
^= 0x8000000000000000ULL
;
336 /* test for less than condition */
337 if (float64_lt_nocheck(rFn
, rFm
))
338 flags
|= CC_NEGATIVE
;
340 /* test for equal condition */
341 if (float64_eq_nocheck(rFn
, rFm
))
344 /* test for greater than or equal condition */
345 if (float64_lt_nocheck(rFm
, rFn
))
352 writeConditionCodes(flags
);
357 /* ?? The FPA data sheet is pretty vague about this, in particular
358 about whether the non-E comparisons can ever raise exceptions.
359 This implementation is based on a combination of what it says in
360 the data sheet, observation of how the Acorn emulator actually
361 behaves (and how programs expect it to) and guesswork. */
362 flags
|= CC_OVERFLOW
;
363 flags
&= ~(CC_ZERO
| CC_NEGATIVE
);
365 if (BIT_AC
& readFPSR())
369 float_raise(float_flag_invalid
);
371 writeConditionCodes(flags
);