|
|
1.1 ! root 1: /* ! 2: NetWinder Floating Point Emulator ! 3: (c) Rebel.com, 1998-1999 ! 4: (c) Philip Blundell, 1998 ! 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 "fpmodule.h" ! 27: //#include "fpmodule.inl" ! 28: ! 29: //#include <asm/uaccess.h> ! 30: ! 31: static inline ! 32: void loadSingle(const unsigned int Fn,const unsigned int *pMem) ! 33: { ! 34: target_ulong addr = (target_ulong)(long)pMem; ! 35: FPA11 *fpa11 = GET_FPA11(); ! 36: fpa11->fType[Fn] = typeSingle; ! 37: /* FIXME - handle failure of get_user() */ ! 38: get_user_u32(fpa11->fpreg[Fn].fSingle, addr); ! 39: } ! 40: ! 41: static inline ! 42: void loadDouble(const unsigned int Fn,const unsigned int *pMem) ! 43: { ! 44: target_ulong addr = (target_ulong)(long)pMem; ! 45: FPA11 *fpa11 = GET_FPA11(); ! 46: unsigned int *p; ! 47: p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; ! 48: fpa11->fType[Fn] = typeDouble; ! 49: #ifdef WORDS_BIGENDIAN ! 50: /* FIXME - handle failure of get_user() */ ! 51: get_user_u32(p[0], addr); /* sign & exponent */ ! 52: get_user_u32(p[1], addr + 4); ! 53: #else ! 54: /* FIXME - handle failure of get_user() */ ! 55: get_user_u32(p[0], addr + 4); ! 56: get_user_u32(p[1], addr); /* sign & exponent */ ! 57: #endif ! 58: } ! 59: ! 60: static inline ! 61: void loadExtended(const unsigned int Fn,const unsigned int *pMem) ! 62: { ! 63: target_ulong addr = (target_ulong)(long)pMem; ! 64: FPA11 *fpa11 = GET_FPA11(); ! 65: unsigned int *p; ! 66: p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; ! 67: fpa11->fType[Fn] = typeExtended; ! 68: /* FIXME - handle failure of get_user() */ ! 69: get_user_u32(p[0], addr); /* sign & exponent */ ! 70: get_user_u32(p[1], addr + 8); /* ls bits */ ! 71: get_user_u32(p[2], addr + 4); /* ms bits */ ! 72: } ! 73: ! 74: static inline ! 75: void loadMultiple(const unsigned int Fn,const unsigned int *pMem) ! 76: { ! 77: target_ulong addr = (target_ulong)(long)pMem; ! 78: FPA11 *fpa11 = GET_FPA11(); ! 79: register unsigned int *p; ! 80: unsigned long x; ! 81: ! 82: p = (unsigned int*)&(fpa11->fpreg[Fn]); ! 83: /* FIXME - handle failure of get_user() */ ! 84: get_user_u32(x, addr); ! 85: fpa11->fType[Fn] = (x >> 14) & 0x00000003; ! 86: ! 87: switch (fpa11->fType[Fn]) ! 88: { ! 89: case typeSingle: ! 90: case typeDouble: ! 91: { ! 92: /* FIXME - handle failure of get_user() */ ! 93: get_user_u32(p[0], addr + 8); /* Single */ ! 94: get_user_u32(p[1], addr + 4); /* double msw */ ! 95: p[2] = 0; /* empty */ ! 96: } ! 97: break; ! 98: ! 99: case typeExtended: ! 100: { ! 101: /* FIXME - handle failure of get_user() */ ! 102: get_user_u32(p[1], addr + 8); ! 103: get_user_u32(p[2], addr + 4); /* msw */ ! 104: p[0] = (x & 0x80003fff); ! 105: } ! 106: break; ! 107: } ! 108: } ! 109: ! 110: static inline ! 111: void storeSingle(const unsigned int Fn,unsigned int *pMem) ! 112: { ! 113: target_ulong addr = (target_ulong)(long)pMem; ! 114: FPA11 *fpa11 = GET_FPA11(); ! 115: float32 val; ! 116: register unsigned int *p = (unsigned int*)&val; ! 117: ! 118: switch (fpa11->fType[Fn]) ! 119: { ! 120: case typeDouble: ! 121: val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); ! 122: break; ! 123: ! 124: case typeExtended: ! 125: val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status); ! 126: break; ! 127: ! 128: default: val = fpa11->fpreg[Fn].fSingle; ! 129: } ! 130: ! 131: /* FIXME - handle put_user() failures */ ! 132: put_user_u32(p[0], addr); ! 133: } ! 134: ! 135: static inline ! 136: void storeDouble(const unsigned int Fn,unsigned int *pMem) ! 137: { ! 138: target_ulong addr = (target_ulong)(long)pMem; ! 139: FPA11 *fpa11 = GET_FPA11(); ! 140: float64 val; ! 141: register unsigned int *p = (unsigned int*)&val; ! 142: ! 143: switch (fpa11->fType[Fn]) ! 144: { ! 145: case typeSingle: ! 146: val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); ! 147: break; ! 148: ! 149: case typeExtended: ! 150: val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status); ! 151: break; ! 152: ! 153: default: val = fpa11->fpreg[Fn].fDouble; ! 154: } ! 155: /* FIXME - handle put_user() failures */ ! 156: #ifdef WORDS_BIGENDIAN ! 157: put_user_u32(p[0], addr); /* msw */ ! 158: put_user_u32(p[1], addr + 4); /* lsw */ ! 159: #else ! 160: put_user_u32(p[1], addr); /* msw */ ! 161: put_user_u32(p[0], addr + 4); /* lsw */ ! 162: #endif ! 163: } ! 164: ! 165: static inline ! 166: void storeExtended(const unsigned int Fn,unsigned int *pMem) ! 167: { ! 168: target_ulong addr = (target_ulong)(long)pMem; ! 169: FPA11 *fpa11 = GET_FPA11(); ! 170: floatx80 val; ! 171: register unsigned int *p = (unsigned int*)&val; ! 172: ! 173: switch (fpa11->fType[Fn]) ! 174: { ! 175: case typeSingle: ! 176: val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); ! 177: break; ! 178: ! 179: case typeDouble: ! 180: val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); ! 181: break; ! 182: ! 183: default: val = fpa11->fpreg[Fn].fExtended; ! 184: } ! 185: ! 186: /* FIXME - handle put_user() failures */ ! 187: put_user_u32(p[0], addr); /* sign & exp */ ! 188: put_user_u32(p[1], addr + 8); ! 189: put_user_u32(p[2], addr + 4); /* msw */ ! 190: } ! 191: ! 192: static inline ! 193: void storeMultiple(const unsigned int Fn,unsigned int *pMem) ! 194: { ! 195: target_ulong addr = (target_ulong)(long)pMem; ! 196: FPA11 *fpa11 = GET_FPA11(); ! 197: register unsigned int nType, *p; ! 198: ! 199: p = (unsigned int*)&(fpa11->fpreg[Fn]); ! 200: nType = fpa11->fType[Fn]; ! 201: ! 202: switch (nType) ! 203: { ! 204: case typeSingle: ! 205: case typeDouble: ! 206: { ! 207: put_user_u32(p[0], addr + 8); /* single */ ! 208: put_user_u32(p[1], addr + 4); /* double msw */ ! 209: put_user_u32(nType << 14, addr); ! 210: } ! 211: break; ! 212: ! 213: case typeExtended: ! 214: { ! 215: put_user_u32(p[2], addr + 4); /* msw */ ! 216: put_user_u32(p[1], addr + 8); ! 217: put_user_u32((p[0] & 0x80003fff) | (nType << 14), addr); ! 218: } ! 219: break; ! 220: } ! 221: } ! 222: ! 223: unsigned int PerformLDF(const unsigned int opcode) ! 224: { ! 225: unsigned int *pBase, *pAddress, *pFinal, nRc = 1, ! 226: write_back = WRITE_BACK(opcode); ! 227: ! 228: //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); ! 229: ! 230: pBase = (unsigned int*)readRegister(getRn(opcode)); ! 231: if (REG_PC == getRn(opcode)) ! 232: { ! 233: pBase += 2; ! 234: write_back = 0; ! 235: } ! 236: ! 237: pFinal = pBase; ! 238: if (BIT_UP_SET(opcode)) ! 239: pFinal += getOffset(opcode); ! 240: else ! 241: pFinal -= getOffset(opcode); ! 242: ! 243: if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; ! 244: ! 245: switch (opcode & MASK_TRANSFER_LENGTH) ! 246: { ! 247: case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break; ! 248: case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break; ! 249: case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; ! 250: default: nRc = 0; ! 251: } ! 252: ! 253: if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); ! 254: return nRc; ! 255: } ! 256: ! 257: unsigned int PerformSTF(const unsigned int opcode) ! 258: { ! 259: unsigned int *pBase, *pAddress, *pFinal, nRc = 1, ! 260: write_back = WRITE_BACK(opcode); ! 261: ! 262: //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); ! 263: SetRoundingMode(ROUND_TO_NEAREST); ! 264: ! 265: pBase = (unsigned int*)readRegister(getRn(opcode)); ! 266: if (REG_PC == getRn(opcode)) ! 267: { ! 268: pBase += 2; ! 269: write_back = 0; ! 270: } ! 271: ! 272: pFinal = pBase; ! 273: if (BIT_UP_SET(opcode)) ! 274: pFinal += getOffset(opcode); ! 275: else ! 276: pFinal -= getOffset(opcode); ! 277: ! 278: if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; ! 279: ! 280: switch (opcode & MASK_TRANSFER_LENGTH) ! 281: { ! 282: case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break; ! 283: case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break; ! 284: case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; ! 285: default: nRc = 0; ! 286: } ! 287: ! 288: if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); ! 289: return nRc; ! 290: } ! 291: ! 292: unsigned int PerformLFM(const unsigned int opcode) ! 293: { ! 294: unsigned int i, Fd, *pBase, *pAddress, *pFinal, ! 295: write_back = WRITE_BACK(opcode); ! 296: ! 297: pBase = (unsigned int*)readRegister(getRn(opcode)); ! 298: if (REG_PC == getRn(opcode)) ! 299: { ! 300: pBase += 2; ! 301: write_back = 0; ! 302: } ! 303: ! 304: pFinal = pBase; ! 305: if (BIT_UP_SET(opcode)) ! 306: pFinal += getOffset(opcode); ! 307: else ! 308: pFinal -= getOffset(opcode); ! 309: ! 310: if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; ! 311: ! 312: Fd = getFd(opcode); ! 313: for (i=getRegisterCount(opcode);i>0;i--) ! 314: { ! 315: loadMultiple(Fd,pAddress); ! 316: pAddress += 3; Fd++; ! 317: if (Fd == 8) Fd = 0; ! 318: } ! 319: ! 320: if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); ! 321: return 1; ! 322: } ! 323: ! 324: unsigned int PerformSFM(const unsigned int opcode) ! 325: { ! 326: unsigned int i, Fd, *pBase, *pAddress, *pFinal, ! 327: write_back = WRITE_BACK(opcode); ! 328: ! 329: pBase = (unsigned int*)readRegister(getRn(opcode)); ! 330: if (REG_PC == getRn(opcode)) ! 331: { ! 332: pBase += 2; ! 333: write_back = 0; ! 334: } ! 335: ! 336: pFinal = pBase; ! 337: if (BIT_UP_SET(opcode)) ! 338: pFinal += getOffset(opcode); ! 339: else ! 340: pFinal -= getOffset(opcode); ! 341: ! 342: if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; ! 343: ! 344: Fd = getFd(opcode); ! 345: for (i=getRegisterCount(opcode);i>0;i--) ! 346: { ! 347: storeMultiple(Fd,pAddress); ! 348: pAddress += 3; Fd++; ! 349: if (Fd == 8) Fd = 0; ! 350: } ! 351: ! 352: if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); ! 353: return 1; ! 354: } ! 355: ! 356: #if 1 ! 357: unsigned int EmulateCPDT(const unsigned int opcode) ! 358: { ! 359: unsigned int nRc = 0; ! 360: ! 361: //printk("EmulateCPDT(0x%08x)\n",opcode); ! 362: ! 363: if (LDF_OP(opcode)) ! 364: { ! 365: nRc = PerformLDF(opcode); ! 366: } ! 367: else if (LFM_OP(opcode)) ! 368: { ! 369: nRc = PerformLFM(opcode); ! 370: } ! 371: else if (STF_OP(opcode)) ! 372: { ! 373: nRc = PerformSTF(opcode); ! 374: } ! 375: else if (SFM_OP(opcode)) ! 376: { ! 377: nRc = PerformSFM(opcode); ! 378: } ! 379: else ! 380: { ! 381: nRc = 0; ! 382: } ! 383: ! 384: return nRc; ! 385: } ! 386: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.