|
|
1.1 ! root 1: /* ! 2: NetWinder Floating Point Emulator ! 3: (c) Rebel.COM, 1998,1999 ! 4: (c) Philip Blundell, 1999 ! 5: ! 6: Direct questions, comments to Scott Bambrough <[email protected]> ! 7: ! 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. ! 12: ! 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. ! 17: ! 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. ! 21: */ ! 22: ! 23: #include "fpa11.h" ! 24: #include "softfloat.h" ! 25: #include "fpopcode.h" ! 26: #include "fpa11.inl" ! 27: //#include "fpmodule.h" ! 28: //#include "fpmodule.inl" ! 29: ! 30: unsigned int PerformFLT(const unsigned int opcode); ! 31: unsigned int PerformFIX(const unsigned int opcode); ! 32: ! 33: static unsigned int ! 34: PerformComparison(const unsigned int opcode); ! 35: ! 36: unsigned int EmulateCPRT(const unsigned int opcode) ! 37: { ! 38: unsigned int nRc = 1; ! 39: ! 40: //printk("EmulateCPRT(0x%08x)\n",opcode); ! 41: ! 42: if (opcode & 0x800000) ! 43: { ! 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); ! 49: } ! 50: ! 51: /* Hint to GCC that we'd like a jump table rather than a load of CMPs */ ! 52: switch ((opcode & 0x700000) >> 20) ! 53: { ! 54: case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; ! 55: case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; ! 56: ! 57: case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; ! 58: case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; ! 59: ! 60: #if 0 /* We currently have no use for the FPCR, so there's no point ! 61: in emulating it. */ ! 62: case WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode))); ! 63: case RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break; ! 64: #endif ! 65: ! 66: default: nRc = 0; ! 67: } ! 68: ! 69: return nRc; ! 70: } ! 71: ! 72: unsigned int PerformFLT(const unsigned int opcode) ! 73: { ! 74: FPA11 *fpa11 = GET_FPA11(); ! 75: ! 76: unsigned int nRc = 1; ! 77: SetRoundingMode(opcode); ! 78: ! 79: switch (opcode & MASK_ROUNDING_PRECISION) ! 80: { ! 81: case ROUND_SINGLE: ! 82: { ! 83: fpa11->fType[getFn(opcode)] = typeSingle; ! 84: fpa11->fpreg[getFn(opcode)].fSingle = ! 85: int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status); ! 86: } ! 87: break; ! 88: ! 89: case ROUND_DOUBLE: ! 90: { ! 91: fpa11->fType[getFn(opcode)] = typeDouble; ! 92: fpa11->fpreg[getFn(opcode)].fDouble = ! 93: int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status); ! 94: } ! 95: break; ! 96: ! 97: case ROUND_EXTENDED: ! 98: { ! 99: fpa11->fType[getFn(opcode)] = typeExtended; ! 100: fpa11->fpreg[getFn(opcode)].fExtended = ! 101: int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status); ! 102: } ! 103: break; ! 104: ! 105: default: nRc = 0; ! 106: } ! 107: ! 108: return nRc; ! 109: } ! 110: ! 111: unsigned int PerformFIX(const unsigned int opcode) ! 112: { ! 113: FPA11 *fpa11 = GET_FPA11(); ! 114: unsigned int nRc = 1; ! 115: unsigned int Fn = getFm(opcode); ! 116: ! 117: SetRoundingMode(opcode); ! 118: ! 119: switch (fpa11->fType[Fn]) ! 120: { ! 121: case typeSingle: ! 122: { ! 123: writeRegister(getRd(opcode), ! 124: float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status)); ! 125: } ! 126: break; ! 127: ! 128: case typeDouble: ! 129: { ! 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)); ! 133: } ! 134: break; ! 135: ! 136: case typeExtended: ! 137: { ! 138: writeRegister(getRd(opcode), ! 139: floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status)); ! 140: } ! 141: break; ! 142: ! 143: default: nRc = 0; ! 144: } ! 145: ! 146: return nRc; ! 147: } ! 148: ! 149: ! 150: static unsigned int __inline__ ! 151: PerformComparisonOperation(floatx80 Fn, floatx80 Fm) ! 152: { ! 153: FPA11 *fpa11 = GET_FPA11(); ! 154: unsigned int flags = 0; ! 155: ! 156: /* test for less than condition */ ! 157: if (floatx80_lt(Fn,Fm, &fpa11->fp_status)) ! 158: { ! 159: flags |= CC_NEGATIVE; ! 160: } ! 161: ! 162: /* test for equal condition */ ! 163: if (floatx80_eq(Fn,Fm, &fpa11->fp_status)) ! 164: { ! 165: flags |= CC_ZERO; ! 166: } ! 167: ! 168: /* test for greater than or equal condition */ ! 169: if (floatx80_lt(Fm,Fn, &fpa11->fp_status)) ! 170: { ! 171: flags |= CC_CARRY; ! 172: } ! 173: ! 174: writeConditionCodes(flags); ! 175: return 1; ! 176: } ! 177: ! 178: /* This instruction sets the flags N, Z, C, V in the FPSR. */ ! 179: ! 180: static unsigned int PerformComparison(const unsigned int opcode) ! 181: { ! 182: FPA11 *fpa11 = GET_FPA11(); ! 183: unsigned int Fn, Fm; ! 184: floatx80 rFn, rFm; ! 185: int e_flag = opcode & 0x400000; /* 1 if CxFE */ ! 186: int n_flag = opcode & 0x200000; /* 1 if CNxx */ ! 187: unsigned int flags = 0; ! 188: ! 189: //printk("PerformComparison(0x%08x)\n",opcode); ! 190: ! 191: Fn = getFn(opcode); ! 192: Fm = getFm(opcode); ! 193: ! 194: /* Check for unordered condition and convert all operands to 80-bit ! 195: format. ! 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]) ! 200: { ! 201: case typeSingle: ! 202: //printk("single.\n"); ! 203: if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) ! 204: goto unordered; ! 205: rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); ! 206: break; ! 207: ! 208: case typeDouble: ! 209: //printk("double.\n"); ! 210: if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) ! 211: goto unordered; ! 212: rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); ! 213: break; ! 214: ! 215: case typeExtended: ! 216: //printk("extended.\n"); ! 217: if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) ! 218: goto unordered; ! 219: rFn = fpa11->fpreg[Fn].fExtended; ! 220: break; ! 221: ! 222: default: return 0; ! 223: } ! 224: ! 225: if (CONSTANT_FM(opcode)) ! 226: { ! 227: //printk("Fm is a constant: #%d.\n",Fm); ! 228: rFm = getExtendedConstant(Fm); ! 229: if (floatx80_is_nan(rFm)) ! 230: goto unordered; ! 231: } ! 232: else ! 233: { ! 234: //printk("Fm = r%d which contains a ",Fm); ! 235: switch (fpa11->fType[Fm]) ! 236: { ! 237: case typeSingle: ! 238: //printk("single.\n"); ! 239: if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) ! 240: goto unordered; ! 241: rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); ! 242: break; ! 243: ! 244: case typeDouble: ! 245: //printk("double.\n"); ! 246: if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) ! 247: goto unordered; ! 248: rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); ! 249: break; ! 250: ! 251: case typeExtended: ! 252: //printk("extended.\n"); ! 253: if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) ! 254: goto unordered; ! 255: rFm = fpa11->fpreg[Fm].fExtended; ! 256: break; ! 257: ! 258: default: return 0; ! 259: } ! 260: } ! 261: ! 262: if (n_flag) ! 263: { ! 264: rFm.high ^= 0x8000; ! 265: } ! 266: ! 267: return PerformComparisonOperation(rFn,rFm); ! 268: ! 269: unordered: ! 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); ! 277: ! 278: if (BIT_AC & readFPSR()) flags |= CC_CARRY; ! 279: ! 280: if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status); ! 281: ! 282: writeConditionCodes(flags); ! 283: return 1; ! 284: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.