^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) NetWinder Floating Point Emulator
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) (c) Rebel.COM, 1998,1999
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) (c) Philip Blundell, 1999, 2001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "fpa11.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "fpopcode.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "fpa11.inl"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "fpmodule.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "fpmodule.inl"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "softfloat.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) unsigned int PerformFLT(const unsigned int opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) unsigned int PerformFIX(const unsigned int opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static unsigned int PerformComparison(const unsigned int opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) unsigned int EmulateCPRT(const unsigned int opcode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) if (opcode & 0x800000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /* This is some variant of a comparison (PerformComparison
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) will sort out which one). Since most of the other CPRT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) instructions are oddball cases of some sort or other it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) makes sense to pull this out into a fast path. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) return PerformComparison(opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) switch ((opcode & 0x700000) >> 20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) case FLT_CODE >> 20:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return PerformFLT(opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) case FIX_CODE >> 20:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return PerformFIX(opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) case WFS_CODE >> 20:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) writeFPSR(readRegister(getRd(opcode)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) case RFS_CODE >> 20:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) writeRegister(getRd(opcode), readFPSR());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) unsigned int PerformFLT(const unsigned int opcode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) FPA11 *fpa11 = GET_FPA11();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct roundingData roundData;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) roundData.mode = SetRoundingMode(opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) roundData.precision = SetRoundingPrecision(opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) roundData.exception = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) switch (opcode & MASK_ROUNDING_PRECISION) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) case ROUND_SINGLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) fpa11->fType[getFn(opcode)] = typeSingle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(&roundData, readRegister(getRd(opcode)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) case ROUND_DOUBLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) fpa11->fType[getFn(opcode)] = typeDouble;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #ifdef CONFIG_FPE_NWFPE_XP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) case ROUND_EXTENDED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) fpa11->fType[getFn(opcode)] = typeExtended;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (roundData.exception)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) float_raise(roundData.exception);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) unsigned int PerformFIX(const unsigned int opcode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) FPA11 *fpa11 = GET_FPA11();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) unsigned int Fn = getFm(opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct roundingData roundData;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) roundData.mode = SetRoundingMode(opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) roundData.precision = SetRoundingPrecision(opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) roundData.exception = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) switch (fpa11->fType[Fn]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) case typeSingle:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) writeRegister(getRd(opcode), float32_to_int32(&roundData, fpa11->fpreg[Fn].fSingle));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) case typeDouble:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) writeRegister(getRd(opcode), float64_to_int32(&roundData, fpa11->fpreg[Fn].fDouble));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #ifdef CONFIG_FPE_NWFPE_XP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) case typeExtended:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) writeRegister(getRd(opcode), floatx80_to_int32(&roundData, fpa11->fpreg[Fn].fExtended));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (roundData.exception)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) float_raise(roundData.exception);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /* This instruction sets the flags N, Z, C, V in the FPSR. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static unsigned int PerformComparison(const unsigned int opcode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) FPA11 *fpa11 = GET_FPA11();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) unsigned int Fn = getFn(opcode), Fm = getFm(opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) int e_flag = opcode & 0x400000; /* 1 if CxFE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) int n_flag = opcode & 0x200000; /* 1 if CNxx */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) unsigned int flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) #ifdef CONFIG_FPE_NWFPE_XP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) floatx80 rFn, rFm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /* Check for unordered condition and convert all operands to 80-bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) format.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) ?? Might be some mileage in avoiding this conversion if possible.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) Eg, if both operands are 32-bit, detect this and do a 32-bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) comparison (cheaper than an 80-bit one). */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) switch (fpa11->fType[Fn]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case typeSingle:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) //printk("single.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) goto unordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) case typeDouble:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) //printk("double.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) goto unordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) case typeExtended:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) //printk("extended.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) goto unordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) rFn = fpa11->fpreg[Fn].fExtended;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (CONSTANT_FM(opcode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) //printk("Fm is a constant: #%d.\n",Fm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) rFm = getExtendedConstant(Fm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (floatx80_is_nan(rFm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) goto unordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) //printk("Fm = r%d which contains a ",Fm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) switch (fpa11->fType[Fm]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) case typeSingle:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) //printk("single.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) goto unordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) case typeDouble:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) //printk("double.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) goto unordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) case typeExtended:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) //printk("extended.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) goto unordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) rFm = fpa11->fpreg[Fm].fExtended;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (n_flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) rFm.high ^= 0x8000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) /* test for less than condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (floatx80_lt(rFn, rFm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) flags |= CC_NEGATIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) /* test for equal condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (floatx80_eq(rFn, rFm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) flags |= CC_ZERO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) /* test for greater than or equal condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (floatx80_lt(rFm, rFn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) flags |= CC_CARRY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (CONSTANT_FM(opcode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) /* Fm is a constant. Do the comparison in whatever precision
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) Fn happens to be stored in. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (fpa11->fType[Fn] == typeSingle) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) float32 rFm = getSingleConstant(Fm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) float32 rFn = fpa11->fpreg[Fn].fSingle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (float32_is_nan(rFn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) goto unordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (n_flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) rFm ^= 0x80000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* test for less than condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (float32_lt_nocheck(rFn, rFm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) flags |= CC_NEGATIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) /* test for equal condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (float32_eq_nocheck(rFn, rFm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) flags |= CC_ZERO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) /* test for greater than or equal condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (float32_lt_nocheck(rFm, rFn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) flags |= CC_CARRY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) float64 rFm = getDoubleConstant(Fm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) float64 rFn = fpa11->fpreg[Fn].fDouble;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (float64_is_nan(rFn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) goto unordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (n_flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) rFm ^= 0x8000000000000000ULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) /* test for less than condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) if (float64_lt_nocheck(rFn, rFm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) flags |= CC_NEGATIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) /* test for equal condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) if (float64_eq_nocheck(rFn, rFm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) flags |= CC_ZERO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) /* test for greater than or equal condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (float64_lt_nocheck(rFm, rFn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) flags |= CC_CARRY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /* Both operands are in registers. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (fpa11->fType[Fn] == typeSingle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) && fpa11->fType[Fm] == typeSingle) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) float32 rFm = fpa11->fpreg[Fm].fSingle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) float32 rFn = fpa11->fpreg[Fn].fSingle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (float32_is_nan(rFn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) || float32_is_nan(rFm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) goto unordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (n_flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) rFm ^= 0x80000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) /* test for less than condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (float32_lt_nocheck(rFn, rFm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) flags |= CC_NEGATIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) /* test for equal condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (float32_eq_nocheck(rFn, rFm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) flags |= CC_ZERO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) /* test for greater than or equal condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) if (float32_lt_nocheck(rFm, rFn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) flags |= CC_CARRY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) /* Promote 32-bit operand to 64 bits. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) float64 rFm, rFn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) rFm = (fpa11->fType[Fm] == typeSingle) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) float32_to_float64(fpa11->fpreg[Fm].fSingle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) : fpa11->fpreg[Fm].fDouble;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) rFn = (fpa11->fType[Fn] == typeSingle) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) float32_to_float64(fpa11->fpreg[Fn].fSingle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) : fpa11->fpreg[Fn].fDouble;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (float64_is_nan(rFn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) || float64_is_nan(rFm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) goto unordered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (n_flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) rFm ^= 0x8000000000000000ULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) /* test for less than condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (float64_lt_nocheck(rFn, rFm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) flags |= CC_NEGATIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) /* test for equal condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) if (float64_eq_nocheck(rFn, rFm))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) flags |= CC_ZERO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) /* test for greater than or equal condition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (float64_lt_nocheck(rFm, rFn))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) flags |= CC_CARRY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) writeConditionCodes(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) unordered:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /* ?? The FPA data sheet is pretty vague about this, in particular
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) about whether the non-E comparisons can ever raise exceptions.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) This implementation is based on a combination of what it says in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) the data sheet, observation of how the Acorn emulator actually
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) behaves (and how programs expect it to) and guesswork. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) flags |= CC_OVERFLOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) flags &= ~(CC_ZERO | CC_NEGATIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (BIT_AC & readFPSR())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) flags |= CC_CARRY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (e_flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) float_raise(float_flag_invalid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) writeConditionCodes(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }