2 NetWinder Floating Point Emulator
3 (c) Rebel.COM, 1998,1999
4 (c) Philip Blundell, 1999
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, see <http://www.gnu.org/licenses/>.
22 #include "qemu/osdep.h"
24 #include "fpu/softfloat.h"
27 //#include "fpmodule.h"
28 //#include "fpmodule.inl"
30 unsigned int PerformFLT(const unsigned int opcode
);
31 unsigned int PerformFIX(const unsigned int opcode
);
34 PerformComparison(const unsigned int opcode
);
36 unsigned int EmulateCPRT(const unsigned int opcode
)
40 //printk("EmulateCPRT(0x%08x)\n",opcode);
42 if (opcode
& 0x800000)
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
);
51 /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
52 switch ((opcode
& 0x700000) >> 20)
54 case FLT_CODE
>> 20: nRc
= PerformFLT(opcode
); break;
55 case FIX_CODE
>> 20: nRc
= PerformFIX(opcode
); break;
57 case WFS_CODE
>> 20: writeFPSR(readRegister(getRd(opcode
))); break;
58 case RFS_CODE
>> 20: writeRegister(getRd(opcode
),readFPSR()); break;
60 #if 0 /* We currently have no use for the FPCR, so there's no point
62 case WFC_CODE
>> 20: writeFPCR(readRegister(getRd(opcode
)));
63 case RFC_CODE
>> 20: writeRegister(getRd(opcode
),readFPCR()); break;
72 unsigned int PerformFLT(const unsigned int opcode
)
74 FPA11
*fpa11
= GET_FPA11();
77 SetRoundingMode(opcode
);
79 switch (opcode
& MASK_ROUNDING_PRECISION
)
83 fpa11
->fType
[getFn(opcode
)] = typeSingle
;
84 fpa11
->fpreg
[getFn(opcode
)].fSingle
=
85 int32_to_float32(readRegister(getRd(opcode
)), &fpa11
->fp_status
);
91 fpa11
->fType
[getFn(opcode
)] = typeDouble
;
92 fpa11
->fpreg
[getFn(opcode
)].fDouble
=
93 int32_to_float64(readRegister(getRd(opcode
)), &fpa11
->fp_status
);
99 fpa11
->fType
[getFn(opcode
)] = typeExtended
;
100 fpa11
->fpreg
[getFn(opcode
)].fExtended
=
101 int32_to_floatx80(readRegister(getRd(opcode
)), &fpa11
->fp_status
);
111 unsigned int PerformFIX(const unsigned int opcode
)
113 FPA11
*fpa11
= GET_FPA11();
114 unsigned int nRc
= 1;
115 unsigned int Fn
= getFm(opcode
);
117 SetRoundingMode(opcode
);
119 switch (fpa11
->fType
[Fn
])
123 writeRegister(getRd(opcode
),
124 float32_to_int32(fpa11
->fpreg
[Fn
].fSingle
, &fpa11
->fp_status
));
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
));
138 writeRegister(getRd(opcode
),
139 floatx80_to_int32(fpa11
->fpreg
[Fn
].fExtended
, &fpa11
->fp_status
));
150 static __inline
unsigned int
151 PerformComparisonOperation(floatx80 Fn
, floatx80 Fm
)
153 FPA11
*fpa11
= GET_FPA11();
154 unsigned int flags
= 0;
156 /* test for less than condition */
157 if (floatx80_lt(Fn
,Fm
, &fpa11
->fp_status
))
159 flags
|= CC_NEGATIVE
;
162 /* test for equal condition */
163 if (floatx80_eq_quiet(Fn
,Fm
, &fpa11
->fp_status
))
168 /* test for greater than or equal condition */
169 if (floatx80_lt(Fm
,Fn
, &fpa11
->fp_status
))
174 writeConditionCodes(flags
);
178 /* This instruction sets the flags N, Z, C, V in the FPSR. */
180 static unsigned int PerformComparison(const unsigned int opcode
)
182 FPA11
*fpa11
= GET_FPA11();
185 int e_flag
= opcode
& 0x400000; /* 1 if CxFE */
186 int n_flag
= opcode
& 0x200000; /* 1 if CNxx */
187 unsigned int flags
= 0;
189 //printk("PerformComparison(0x%08x)\n",opcode);
194 /* Check for unordered condition and convert all operands to 80-bit
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
])
202 //printk("single.\n");
203 if (float32_is_any_nan(fpa11
->fpreg
[Fn
].fSingle
))
205 rFn
= float32_to_floatx80(fpa11
->fpreg
[Fn
].fSingle
, &fpa11
->fp_status
);
209 //printk("double.\n");
210 if (float64_is_any_nan(fpa11
->fpreg
[Fn
].fDouble
))
212 rFn
= float64_to_floatx80(fpa11
->fpreg
[Fn
].fDouble
, &fpa11
->fp_status
);
216 //printk("extended.\n");
217 if (floatx80_is_any_nan(fpa11
->fpreg
[Fn
].fExtended
))
219 rFn
= fpa11
->fpreg
[Fn
].fExtended
;
225 if (CONSTANT_FM(opcode
))
227 //printk("Fm is a constant: #%d.\n",Fm);
228 rFm
= getExtendedConstant(Fm
);
229 if (floatx80_is_any_nan(rFm
))
234 //printk("Fm = r%d which contains a ",Fm);
235 switch (fpa11
->fType
[Fm
])
238 //printk("single.\n");
239 if (float32_is_any_nan(fpa11
->fpreg
[Fm
].fSingle
))
241 rFm
= float32_to_floatx80(fpa11
->fpreg
[Fm
].fSingle
, &fpa11
->fp_status
);
245 //printk("double.\n");
246 if (float64_is_any_nan(fpa11
->fpreg
[Fm
].fDouble
))
248 rFm
= float64_to_floatx80(fpa11
->fpreg
[Fm
].fDouble
, &fpa11
->fp_status
);
252 //printk("extended.\n");
253 if (floatx80_is_any_nan(fpa11
->fpreg
[Fm
].fExtended
))
255 rFm
= fpa11
->fpreg
[Fm
].fExtended
;
267 return PerformComparisonOperation(rFn
,rFm
);
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
);
278 if (BIT_AC
& readFPSR()) flags
|= CC_CARRY
;
280 if (e_flag
) float_raise(float_flag_invalid
, &fpa11
->fp_status
);
282 writeConditionCodes(flags
);