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/>.
23 #include "softfloat.h"
26 //#include "fpmodule.h"
27 //#include "fpmodule.inl"
29 unsigned int PerformFLT(const unsigned int opcode
);
30 unsigned int PerformFIX(const unsigned int opcode
);
33 PerformComparison(const unsigned int opcode
);
35 unsigned int EmulateCPRT(const unsigned int opcode
)
39 //printk("EmulateCPRT(0x%08x)\n",opcode);
41 if (opcode
& 0x800000)
43 /* This is some variant of a comparison (PerformComparison will
44 sort out which one). Since most of the other CPRT
45 instructions are oddball cases of some sort or other it makes
46 sense to pull this out into a fast path. */
47 return PerformComparison(opcode
);
50 /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
51 switch ((opcode
& 0x700000) >> 20)
53 case FLT_CODE
>> 20: nRc
= PerformFLT(opcode
); break;
54 case FIX_CODE
>> 20: nRc
= PerformFIX(opcode
); break;
56 case WFS_CODE
>> 20: writeFPSR(readRegister(getRd(opcode
))); break;
57 case RFS_CODE
>> 20: writeRegister(getRd(opcode
),readFPSR()); break;
59 #if 0 /* We currently have no use for the FPCR, so there's no point
61 case WFC_CODE
>> 20: writeFPCR(readRegister(getRd(opcode
)));
62 case RFC_CODE
>> 20: writeRegister(getRd(opcode
),readFPCR()); break;
71 unsigned int PerformFLT(const unsigned int opcode
)
73 FPA11
*fpa11
= GET_FPA11();
76 SetRoundingMode(opcode
);
78 switch (opcode
& MASK_ROUNDING_PRECISION
)
82 fpa11
->fType
[getFn(opcode
)] = typeSingle
;
83 fpa11
->fpreg
[getFn(opcode
)].fSingle
=
84 int32_to_float32(readRegister(getRd(opcode
)), &fpa11
->fp_status
);
90 fpa11
->fType
[getFn(opcode
)] = typeDouble
;
91 fpa11
->fpreg
[getFn(opcode
)].fDouble
=
92 int32_to_float64(readRegister(getRd(opcode
)), &fpa11
->fp_status
);
98 fpa11
->fType
[getFn(opcode
)] = typeExtended
;
99 fpa11
->fpreg
[getFn(opcode
)].fExtended
=
100 int32_to_floatx80(readRegister(getRd(opcode
)), &fpa11
->fp_status
);
110 unsigned int PerformFIX(const unsigned int opcode
)
112 FPA11
*fpa11
= GET_FPA11();
113 unsigned int nRc
= 1;
114 unsigned int Fn
= getFm(opcode
);
116 SetRoundingMode(opcode
);
118 switch (fpa11
->fType
[Fn
])
122 writeRegister(getRd(opcode
),
123 float32_to_int32(fpa11
->fpreg
[Fn
].fSingle
, &fpa11
->fp_status
));
129 //printf("F%d is 0x%" PRIx64 "\n",Fn,fpa11->fpreg[Fn].fDouble);
130 writeRegister(getRd(opcode
),
131 float64_to_int32(fpa11
->fpreg
[Fn
].fDouble
, &fpa11
->fp_status
));
137 writeRegister(getRd(opcode
),
138 floatx80_to_int32(fpa11
->fpreg
[Fn
].fExtended
, &fpa11
->fp_status
));
149 static __inline
unsigned int
150 PerformComparisonOperation(floatx80 Fn
, floatx80 Fm
)
152 FPA11
*fpa11
= GET_FPA11();
153 unsigned int flags
= 0;
155 /* test for less than condition */
156 if (floatx80_lt(Fn
,Fm
, &fpa11
->fp_status
))
158 flags
|= CC_NEGATIVE
;
161 /* test for equal condition */
162 if (floatx80_eq_quiet(Fn
,Fm
, &fpa11
->fp_status
))
167 /* test for greater than or equal condition */
168 if (floatx80_lt(Fm
,Fn
, &fpa11
->fp_status
))
173 writeConditionCodes(flags
);
177 /* This instruction sets the flags N, Z, C, V in the FPSR. */
179 static unsigned int PerformComparison(const unsigned int opcode
)
181 FPA11
*fpa11
= GET_FPA11();
184 int e_flag
= opcode
& 0x400000; /* 1 if CxFE */
185 int n_flag
= opcode
& 0x200000; /* 1 if CNxx */
186 unsigned int flags
= 0;
188 //printk("PerformComparison(0x%08x)\n",opcode);
193 /* Check for unordered condition and convert all operands to 80-bit
195 ?? Might be some mileage in avoiding this conversion if possible.
196 Eg, if both operands are 32-bit, detect this and do a 32-bit
197 comparison (cheaper than an 80-bit one). */
198 switch (fpa11
->fType
[Fn
])
201 //printk("single.\n");
202 if (float32_is_any_nan(fpa11
->fpreg
[Fn
].fSingle
))
204 rFn
= float32_to_floatx80(fpa11
->fpreg
[Fn
].fSingle
, &fpa11
->fp_status
);
208 //printk("double.\n");
209 if (float64_is_any_nan(fpa11
->fpreg
[Fn
].fDouble
))
211 rFn
= float64_to_floatx80(fpa11
->fpreg
[Fn
].fDouble
, &fpa11
->fp_status
);
215 //printk("extended.\n");
216 if (floatx80_is_any_nan(fpa11
->fpreg
[Fn
].fExtended
))
218 rFn
= fpa11
->fpreg
[Fn
].fExtended
;
224 if (CONSTANT_FM(opcode
))
226 //printk("Fm is a constant: #%d.\n",Fm);
227 rFm
= getExtendedConstant(Fm
);
228 if (floatx80_is_any_nan(rFm
))
233 //printk("Fm = r%d which contains a ",Fm);
234 switch (fpa11
->fType
[Fm
])
237 //printk("single.\n");
238 if (float32_is_any_nan(fpa11
->fpreg
[Fm
].fSingle
))
240 rFm
= float32_to_floatx80(fpa11
->fpreg
[Fm
].fSingle
, &fpa11
->fp_status
);
244 //printk("double.\n");
245 if (float64_is_any_nan(fpa11
->fpreg
[Fm
].fDouble
))
247 rFm
= float64_to_floatx80(fpa11
->fpreg
[Fm
].fDouble
, &fpa11
->fp_status
);
251 //printk("extended.\n");
252 if (floatx80_is_any_nan(fpa11
->fpreg
[Fm
].fExtended
))
254 rFm
= fpa11
->fpreg
[Fm
].fExtended
;
266 return PerformComparisonOperation(rFn
,rFm
);
269 /* ?? The FPA data sheet is pretty vague about this, in particular
270 about whether the non-E comparisons can ever raise exceptions.
271 This implementation is based on a combination of what it says in
272 the data sheet, observation of how the Acorn emulator actually
273 behaves (and how programs expect it to) and guesswork. */
274 flags
|= CC_OVERFLOW
;
275 flags
&= ~(CC_ZERO
| CC_NEGATIVE
);
277 if (BIT_AC
& readFPSR()) flags
|= CC_CARRY
;
279 if (e_flag
) float_raise(float_flag_invalid
, &fpa11
->fp_status
);
281 writeConditionCodes(flags
);