|
|
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: extern flag floatx80_is_nan(floatx80); ! 31: extern flag float64_is_nan( float64); ! 32: extern flag float32_is_nan( float32); ! 33: ! 34: void SetRoundingMode(const unsigned int opcode); ! 35: ! 36: unsigned int PerformFLT(const unsigned int opcode); ! 37: unsigned int PerformFIX(const unsigned int opcode); ! 38: ! 39: static unsigned int ! 40: PerformComparison(const unsigned int opcode); ! 41: ! 42: unsigned int EmulateCPRT(const unsigned int opcode) ! 43: { ! 44: unsigned int nRc = 1; ! 45: ! 46: //printk("EmulateCPRT(0x%08x)\n",opcode); ! 47: ! 48: if (opcode & 0x800000) ! 49: { ! 50: /* This is some variant of a comparison (PerformComparison will ! 51: sort out which one). Since most of the other CPRT ! 52: instructions are oddball cases of some sort or other it makes ! 53: sense to pull this out into a fast path. */ ! 54: return PerformComparison(opcode); ! 55: } ! 56: ! 57: /* Hint to GCC that we'd like a jump table rather than a load of CMPs */ ! 58: switch ((opcode & 0x700000) >> 20) ! 59: { ! 60: case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; ! 61: case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; ! 62: ! 63: case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; ! 64: case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; ! 65: ! 66: #if 0 /* We currently have no use for the FPCR, so there's no point ! 67: in emulating it. */ ! 68: case WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode))); ! 69: case RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break; ! 70: #endif ! 71: ! 72: default: nRc = 0; ! 73: } ! 74: ! 75: return nRc; ! 76: } ! 77: ! 78: unsigned int PerformFLT(const unsigned int opcode) ! 79: { ! 80: FPA11 *fpa11 = GET_FPA11(); ! 81: ! 82: unsigned int nRc = 1; ! 83: SetRoundingMode(opcode); ! 84: ! 85: switch (opcode & MASK_ROUNDING_PRECISION) ! 86: { ! 87: case ROUND_SINGLE: ! 88: { ! 89: fpa11->fType[getFn(opcode)] = typeSingle; ! 90: fpa11->fpreg[getFn(opcode)].fSingle = ! 91: int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status); ! 92: } ! 93: break; ! 94: ! 95: case ROUND_DOUBLE: ! 96: { ! 97: fpa11->fType[getFn(opcode)] = typeDouble; ! 98: fpa11->fpreg[getFn(opcode)].fDouble = ! 99: int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status); ! 100: } ! 101: break; ! 102: ! 103: case ROUND_EXTENDED: ! 104: { ! 105: fpa11->fType[getFn(opcode)] = typeExtended; ! 106: fpa11->fpreg[getFn(opcode)].fExtended = ! 107: int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status); ! 108: } ! 109: break; ! 110: ! 111: default: nRc = 0; ! 112: } ! 113: ! 114: return nRc; ! 115: } ! 116: ! 117: unsigned int PerformFIX(const unsigned int opcode) ! 118: { ! 119: FPA11 *fpa11 = GET_FPA11(); ! 120: unsigned int nRc = 1; ! 121: unsigned int Fn = getFm(opcode); ! 122: ! 123: SetRoundingMode(opcode); ! 124: ! 125: switch (fpa11->fType[Fn]) ! 126: { ! 127: case typeSingle: ! 128: { ! 129: writeRegister(getRd(opcode), ! 130: float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status)); ! 131: } ! 132: break; ! 133: ! 134: case typeDouble: ! 135: { ! 136: //printf("F%d is 0x%llx\n",Fn,fpa11->fpreg[Fn].fDouble); ! 137: writeRegister(getRd(opcode), ! 138: float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status)); ! 139: } ! 140: break; ! 141: ! 142: case typeExtended: ! 143: { ! 144: writeRegister(getRd(opcode), ! 145: floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status)); ! 146: } ! 147: break; ! 148: ! 149: default: nRc = 0; ! 150: } ! 151: ! 152: return nRc; ! 153: } ! 154: ! 155: ! 156: static unsigned int __inline__ ! 157: PerformComparisonOperation(floatx80 Fn, floatx80 Fm) ! 158: { ! 159: FPA11 *fpa11 = GET_FPA11(); ! 160: unsigned int flags = 0; ! 161: ! 162: /* test for less than condition */ ! 163: if (floatx80_lt(Fn,Fm, &fpa11->fp_status)) ! 164: { ! 165: flags |= CC_NEGATIVE; ! 166: } ! 167: ! 168: /* test for equal condition */ ! 169: if (floatx80_eq(Fn,Fm, &fpa11->fp_status)) ! 170: { ! 171: flags |= CC_ZERO; ! 172: } ! 173: ! 174: /* test for greater than or equal condition */ ! 175: if (floatx80_lt(Fm,Fn, &fpa11->fp_status)) ! 176: { ! 177: flags |= CC_CARRY; ! 178: } ! 179: ! 180: writeConditionCodes(flags); ! 181: return 1; ! 182: } ! 183: ! 184: /* This instruction sets the flags N, Z, C, V in the FPSR. */ ! 185: ! 186: static unsigned int PerformComparison(const unsigned int opcode) ! 187: { ! 188: FPA11 *fpa11 = GET_FPA11(); ! 189: unsigned int Fn, Fm; ! 190: floatx80 rFn, rFm; ! 191: int e_flag = opcode & 0x400000; /* 1 if CxFE */ ! 192: int n_flag = opcode & 0x200000; /* 1 if CNxx */ ! 193: unsigned int flags = 0; ! 194: ! 195: //printk("PerformComparison(0x%08x)\n",opcode); ! 196: ! 197: Fn = getFn(opcode); ! 198: Fm = getFm(opcode); ! 199: ! 200: /* Check for unordered condition and convert all operands to 80-bit ! 201: format. ! 202: ?? Might be some mileage in avoiding this conversion if possible. ! 203: Eg, if both operands are 32-bit, detect this and do a 32-bit ! 204: comparison (cheaper than an 80-bit one). */ ! 205: switch (fpa11->fType[Fn]) ! 206: { ! 207: case typeSingle: ! 208: //printk("single.\n"); ! 209: if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) ! 210: goto unordered; ! 211: rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); ! 212: break; ! 213: ! 214: case typeDouble: ! 215: //printk("double.\n"); ! 216: if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) ! 217: goto unordered; ! 218: rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); ! 219: break; ! 220: ! 221: case typeExtended: ! 222: //printk("extended.\n"); ! 223: if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) ! 224: goto unordered; ! 225: rFn = fpa11->fpreg[Fn].fExtended; ! 226: break; ! 227: ! 228: default: return 0; ! 229: } ! 230: ! 231: if (CONSTANT_FM(opcode)) ! 232: { ! 233: //printk("Fm is a constant: #%d.\n",Fm); ! 234: rFm = getExtendedConstant(Fm); ! 235: if (floatx80_is_nan(rFm)) ! 236: goto unordered; ! 237: } ! 238: else ! 239: { ! 240: //printk("Fm = r%d which contains a ",Fm); ! 241: switch (fpa11->fType[Fm]) ! 242: { ! 243: case typeSingle: ! 244: //printk("single.\n"); ! 245: if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) ! 246: goto unordered; ! 247: rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status); ! 248: break; ! 249: ! 250: case typeDouble: ! 251: //printk("double.\n"); ! 252: if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) ! 253: goto unordered; ! 254: rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status); ! 255: break; ! 256: ! 257: case typeExtended: ! 258: //printk("extended.\n"); ! 259: if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) ! 260: goto unordered; ! 261: rFm = fpa11->fpreg[Fm].fExtended; ! 262: break; ! 263: ! 264: default: return 0; ! 265: } ! 266: } ! 267: ! 268: if (n_flag) ! 269: { ! 270: rFm.high ^= 0x8000; ! 271: } ! 272: ! 273: return PerformComparisonOperation(rFn,rFm); ! 274: ! 275: unordered: ! 276: /* ?? The FPA data sheet is pretty vague about this, in particular ! 277: about whether the non-E comparisons can ever raise exceptions. ! 278: This implementation is based on a combination of what it says in ! 279: the data sheet, observation of how the Acorn emulator actually ! 280: behaves (and how programs expect it to) and guesswork. */ ! 281: flags |= CC_OVERFLOW; ! 282: flags &= ~(CC_ZERO | CC_NEGATIVE); ! 283: ! 284: if (BIT_AC & readFPSR()) flags |= CC_CARRY; ! 285: ! 286: if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status); ! 287: ! 288: writeConditionCodes(flags); ! 289: return 1; ! 290: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.