|
@@ -0,0 +1,108 @@
|
|
|
+/*
|
|
|
+ NetWinder Floating Point Emulator
|
|
|
+ (c) Rebel.COM, 1998,1999
|
|
|
+ (c) Philip Blundell, 1999, 2001
|
|
|
+
|
|
|
+ Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
|
|
|
+
|
|
|
+ This program is free software; you can redistribute it and/or modify
|
|
|
+ it under the terms of the GNU General Public License as published by
|
|
|
+ the Free Software Foundation; either version 2 of the License, or
|
|
|
+ (at your option) any later version.
|
|
|
+
|
|
|
+ This program is distributed in the hope that it will be useful,
|
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
+ GNU General Public License for more details.
|
|
|
+
|
|
|
+ You should have received a copy of the GNU General Public License
|
|
|
+ along with this program; if not, write to the Free Software
|
|
|
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
+*/
|
|
|
+
|
|
|
+#include "fpa11.h"
|
|
|
+#include "fpopcode.h"
|
|
|
+#include "fpa11.inl"
|
|
|
+#include "fpmodule.h"
|
|
|
+#include "fpmodule.inl"
|
|
|
+#include "softfloat.h"
|
|
|
+
|
|
|
+unsigned int PerformFLT(const unsigned int opcode);
|
|
|
+unsigned int PerformFIX(const unsigned int opcode);
|
|
|
+
|
|
|
+static unsigned int PerformComparison(const unsigned int opcode);
|
|
|
+
|
|
|
+unsigned int EmulateCPRT(const unsigned int opcode)
|
|
|
+{
|
|
|
+
|
|
|
+ if (opcode & 0x800000) {
|
|
|
+ /* This is some variant of a comparison (PerformComparison
|
|
|
+ will sort out which one). Since most of the other CPRT
|
|
|
+ instructions are oddball cases of some sort or other it
|
|
|
+ makes sense to pull this out into a fast path. */
|
|
|
+ return PerformComparison(opcode);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
|
|
|
+ switch ((opcode & 0x700000) >> 20) {
|
|
|
+ case FLT_CODE >> 20:
|
|
|
+ return PerformFLT(opcode);
|
|
|
+ break;
|
|
|
+ case FIX_CODE >> 20:
|
|
|
+ return PerformFIX(opcode);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case WFS_CODE >> 20:
|
|
|
+ writeFPSR(readRegister(getRd(opcode)));
|
|
|
+ break;
|
|
|
+ case RFS_CODE >> 20:
|
|
|
+ writeRegister(getRd(opcode), readFPSR());
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned int PerformFLT(const unsigned int opcode)
|
|
|
+{
|
|
|
+ FPA11 *fpa11 = GET_FPA11();
|
|
|
+ struct roundingData roundData;
|
|
|
+
|
|
|
+ roundData.mode = SetRoundingMode(opcode);
|
|
|
+ roundData.precision = SetRoundingPrecision(opcode);
|
|
|
+ roundData.exception = 0;
|
|
|
+
|
|
|
+ switch (opcode & MASK_ROUNDING_PRECISION) {
|
|
|
+ case ROUND_SINGLE:
|
|
|
+ {
|
|
|
+ fpa11->fType[getFn(opcode)] = typeSingle;
|
|
|
+ fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(&roundData, readRegister(getRd(opcode)));
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case ROUND_DOUBLE:
|
|
|
+ {
|
|
|
+ fpa11->fType[getFn(opcode)] = typeDouble;
|
|
|
+ fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode)));
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+#ifdef CONFIG_FPE_NWFPE_XP
|
|
|
+ case ROUND_EXTENDED:
|
|
|
+ {
|
|
|
+ fpa11->fType[getFn(opcode)] = typeExtended;
|
|
|
+ fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
|
|
|
+ }
|
|
|
+ break;
|
|
|
+#endif
|
|
|
+
|
|
|
+ default:
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (roundData.exception)
|
|
|
+ float_raise(roundData.exception);
|
|
|
+
|