static void fmove_fpcr(UINT16 w2) { int ea = REG_IR & 0x3f; int dir = (w2 >> 13) & 0x1; int reg = (w2 >> 10) & 0x7; if (dir) // From system control reg to <ea> { switch (reg) { case 1: WRITE_EA_32(ea, REG_FPIAR); break; case 2: WRITE_EA_32(ea, REG_FPSR); break; case 4: WRITE_EA_32(ea, REG_FPCR); break; default: fatalerror("fmove_fpcr: unknown reg %d, dir %d\n", reg, dir); } } else // From <ea> to system control reg { switch (reg) { case 1: REG_FPIAR = READ_EA_32(ea); break; case 2: REG_FPSR = READ_EA_32(ea); break; case 4: REG_FPCR = READ_EA_32(ea); break; default: fatalerror("fmove_fpcr: unknown reg %d, dir %d\n", reg, dir); } } USE_CYCLES(10); }
static void fmove_fpcr(m68ki_cpu_core *m68k, UINT16 w2) { int ea = m68k->ir & 0x3f; int dir = (w2 >> 13) & 0x1; int reg = (w2 >> 10) & 0x7; if (dir) // From system control reg to <ea> { switch (reg) { case 1: WRITE_EA_32(m68k, ea, REG_FPIAR); break; case 2: WRITE_EA_32(m68k, ea, REG_FPSR); break; case 4: WRITE_EA_32(m68k, ea, REG_FPCR); break; default: fatalerror("fmove_fpcr: unknown reg %d, dir %d\n", reg, dir); } } else // From <ea> to system control reg { switch (reg) { case 1: REG_FPIAR = READ_EA_32(m68k, ea); break; case 2: REG_FPSR = READ_EA_32(m68k, ea); break; case 4: REG_FPCR = READ_EA_32(m68k, ea); break; default: fatalerror("fmove_fpcr: unknown reg %d, dir %d\n", reg, dir); } } m68k->remaining_cycles -= 10; }
static void fmove_fpcr(m68ki_cpu_core *m68k, UINT16 w2) { int ea = m68k->ir & 0x3f; int dir = (w2 >> 13) & 0x1; int regsel = (w2 >> 10) & 0x7; int mode = (ea >> 3) & 0x7; if ((mode == 5) || (mode == 6)) { UINT32 address = 0xffffffff; // force a bus error if this doesn't get assigned if (mode == 5) { address = EA_AY_DI_32(m68k); } else if (mode == 6) { address = EA_AY_IX_32(m68k); } if (dir) // From system control reg to <ea> { if (regsel & 4) { m68ki_write_32(m68k, address, REG_FPCR(m68k)); address += 4; } if (regsel & 2) { m68ki_write_32(m68k, address, REG_FPSR(m68k)); address += 4; } if (regsel & 1) { m68ki_write_32(m68k, address, REG_FPIAR(m68k)); address += 4; } } else // From <ea> to system control reg { if (regsel & 4) { REG_FPCR(m68k) = m68ki_read_32(m68k, address); address += 4; } if (regsel & 2) { REG_FPSR(m68k) = m68ki_read_32(m68k, address); address += 4; } if (regsel & 1) { REG_FPIAR(m68k) = m68ki_read_32(m68k, address); address += 4; } } } else { if (dir) // From system control reg to <ea> { if (regsel & 4) WRITE_EA_32(m68k, ea, REG_FPCR(m68k)); if (regsel & 2) WRITE_EA_32(m68k, ea, REG_FPSR(m68k)); if (regsel & 1) WRITE_EA_32(m68k, ea, REG_FPIAR(m68k)); } else // From <ea> to system control reg { if (regsel & 4) REG_FPCR(m68k) = READ_EA_32(m68k, ea); if (regsel & 2) REG_FPSR(m68k) = READ_EA_32(m68k, ea); if (regsel & 1) REG_FPIAR(m68k) = READ_EA_32(m68k, ea); } } m68k->remaining_cycles -= 10; }
void m68040_fpu_op1(m68ki_cpu_core *m68k) { int ea = m68k->ir & 0x3f; switch ((m68k->ir >> 6) & 0x3) { case 0: // FSAVE <ea> { WRITE_EA_32(m68k, ea, 0x00000000); // TODO: correct state frame break; } case 1: // FRESTORE <ea> { READ_EA_32(m68k, ea); // TODO: correct state frame break; } default: fatalerror("m68040_fpu_op1: unimplemented op %d at %08X\n", (m68k->ir >> 6) & 0x3, REG_PC-2); } }
void m68040_fpu_op1(void) { int ea = REG_IR & 0x3f; switch ((REG_IR >> 6) & 0x3) { case 0: // FSAVE <ea> { WRITE_EA_32(ea, 0x00000000); // TODO: correct state frame break; } case 1: // FRESTORE <ea> { READ_EA_32(ea); // TODO: correct state frame break; } default: fatalerror("m68040_fpu_op1: unimplemented op %d at %08X\n", (REG_IR >> 6) & 0x3, REG_PC-2); } }
static void fpgen_rm_reg(m68ki_cpu_core *m68k, UINT16 w2) { int ea = m68k->ir & 0x3f; int rm = (w2 >> 14) & 0x1; int src = (w2 >> 10) & 0x7; int dst = (w2 >> 7) & 0x7; int opmode = w2 & 0x7f; double source; if (rm) { switch (src) { case 0: // Long-Word Integer { INT32 d = READ_EA_32(m68k, ea); source = (double)(d); break; } case 1: // Single-precision Real { UINT32 d = READ_EA_32(m68k, ea); source = (double)(*(float*)&d); break; } case 2: // Extended-precision Real { fatalerror("fpgen_rm_reg: extended-precision real load unimplemented at %08X\n", REG_PC-4); break; } case 3: // Packed-decimal Real { fatalerror("fpgen_rm_reg: packed-decimal real load unimplemented at %08X\n", REG_PC-4); break; } case 4: // Word Integer { INT16 d = READ_EA_16(m68k, ea); source = (double)(d); break; } case 5: // Double-precision Real { UINT64 d = READ_EA_64(m68k, ea); source = *(double*)&d; break; } case 6: // Byte Integer { INT8 d = READ_EA_8(m68k, ea); source = (double)(d); break; } default: fatalerror("fmove_rm_reg: invalid source specifier at %08X\n", REG_PC-4); } } else { source = REG_FP[src].f; } switch (opmode) { case 0x00: // FMOVE { REG_FP[dst].f = source; m68k->remaining_cycles -= 4; break; } case 0x04: // FSQRT { REG_FP[dst].f = sqrt(source); SET_CONDITION_CODES(m68k, REG_FP[dst]); m68k->remaining_cycles -= 109; break; } case 0x18: // FABS { REG_FP[dst].f = fabs(source); SET_CONDITION_CODES(m68k, REG_FP[dst]); m68k->remaining_cycles -= 3; break; } case 0x1a: // FNEG { REG_FP[dst].f = -source; SET_CONDITION_CODES(m68k, REG_FP[dst]); m68k->remaining_cycles -= 3; break; } case 0x20: // FDIV { REG_FP[dst].f /= source; m68k->remaining_cycles -= 43; break; } case 0x22: // FADD { REG_FP[dst].f += source; SET_CONDITION_CODES(m68k, REG_FP[dst]); m68k->remaining_cycles -= 9; break; } case 0x23: // FMUL { REG_FP[dst].f *= source; SET_CONDITION_CODES(m68k, REG_FP[dst]); m68k->remaining_cycles -= 11; break; } case 0x28: // FSUB { REG_FP[dst].f -= source; SET_CONDITION_CODES(m68k, REG_FP[dst]); m68k->remaining_cycles -= 9; break; } case 0x38: // FCMP { fp_reg res; res.f = REG_FP[dst].f - source; SET_CONDITION_CODES(m68k, res); m68k->remaining_cycles -= 7; break; } case 0x3a: // FTST { fp_reg res; res.f = source; SET_CONDITION_CODES(m68k, res); m68k->remaining_cycles -= 7; break; } default: fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PC-4); } }
static void fmove_fpcr(m68000_base_device *m68k, UINT16 w2) { int ea = m68k->ir & 0x3f; int dir = (w2 >> 13) & 0x1; int regsel = (w2 >> 10) & 0x7; int mode = (ea >> 3) & 0x7; if ((mode == 5) || (mode == 6)) { UINT32 address = 0xffffffff; // force a bus error if this doesn't get assigned if (mode == 5) { address = EA_AY_DI_32(m68k); } else if (mode == 6) { address = EA_AY_IX_32(m68k); } if (dir) // From system control reg to <ea> { if (regsel & 4) { m68ki_write_32(m68k, address, REG_FPCR(m68k)); address += 4; } if (regsel & 2) { m68ki_write_32(m68k, address, REG_FPSR(m68k)); address += 4; } if (regsel & 1) { m68ki_write_32(m68k, address, REG_FPIAR(m68k)); address += 4; } } else // From <ea> to system control reg { if (regsel & 4) { REG_FPCR(m68k) = m68ki_read_32(m68k, address); address += 4; } if (regsel & 2) { REG_FPSR(m68k) = m68ki_read_32(m68k, address); address += 4; } if (regsel & 1) { REG_FPIAR(m68k) = m68ki_read_32(m68k, address); address += 4; } } } else { if (dir) // From system control reg to <ea> { if (regsel & 4) WRITE_EA_32(m68k, ea, REG_FPCR(m68k)); if (regsel & 2) WRITE_EA_32(m68k, ea, REG_FPSR(m68k)); if (regsel & 1) WRITE_EA_32(m68k, ea, REG_FPIAR(m68k)); } else // From <ea> to system control reg { if (regsel & 4) REG_FPCR(m68k) = READ_EA_32(m68k, ea); if (regsel & 2) REG_FPSR(m68k) = READ_EA_32(m68k, ea); if (regsel & 1) REG_FPIAR(m68k) = READ_EA_32(m68k, ea); } } #if 0 // FIXME: (2011-12-18 ost) // rounding_mode and rounding_precision of softfloat.c should be set according to current fpcr // but: with this code on Apollo the following programs in /systest/fptest will fail: // 1. Single Precision Whetstone will return wrong results never the less // 2. Vector Test will fault with 00040004: reference to illegal address if ((regsel & 4) && dir == 0) { int rnd = (REG_FPCR(m68k) >> 4) & 3; int prec = (REG_FPCR(m68k) >> 6) & 3; logerror("m68k_fpsp:fmove_fpcr fpcr=%04x prec=%d rnd=%d\n", REG_FPCR(m68k), prec, rnd); #ifdef FLOATX80 switch (prec) { case 0: // Extend (X) floatx80_rounding_precision = 80; break; case 1: // Single (S) floatx80_rounding_precision = 32; break; case 2: // Double (D) floatx80_rounding_precision = 64; break; case 3: // Undefined floatx80_rounding_precision = 80; break; } #endif switch (rnd) { case 0: // To Nearest (RN) float_rounding_mode = float_round_nearest_even; break; case 1: // To Zero (RZ) float_rounding_mode = float_round_to_zero; break; case 2: // To Minus Infinitiy (RM) float_rounding_mode = float_round_down; break; case 3: // To Plus Infinitiy (RP) float_rounding_mode = float_round_up; break; } }
static void fpgen_rm_reg(m68000_base_device *m68k, UINT16 w2) { int ea = m68k->ir & 0x3f; int rm = (w2 >> 14) & 0x1; int src = (w2 >> 10) & 0x7; int dst = (w2 >> 7) & 0x7; int opmode = w2 & 0x7f; floatx80 source; // fmovecr #$f, fp0 f200 5c0f if (rm) { switch (src) { case 0: // Long-Word Integer { INT32 d = READ_EA_32(m68k, ea); source = int32_to_floatx80(d); break; } case 1: // Single-precision Real { UINT32 d = READ_EA_32(m68k, ea); source = float32_to_floatx80(d); break; } case 2: // Extended-precision Real { source = READ_EA_FPE(m68k, ea); break; } case 3: // Packed-decimal Real { source = READ_EA_PACK(m68k, ea); break; } case 4: // Word Integer { INT16 d = READ_EA_16(m68k, ea); source = int32_to_floatx80((INT32)d); break; } case 5: // Double-precision Real { UINT64 d = READ_EA_64(m68k, ea); source = float64_to_floatx80(d); break; } case 6: // Byte Integer { INT8 d = READ_EA_8(m68k, ea); source = int32_to_floatx80((INT32)d); break; } case 7: // FMOVECR load from constant ROM { switch (w2 & 0x7f) { case 0x0: // Pi source.high = 0x4000; source.low = U64(0xc90fdaa22168c235); break; case 0xb: // log10(2) source.high = 0x3ffd; source.low = U64(0x9a209a84fbcff798); break; case 0xc: // e source.high = 0x4000; source.low = U64(0xadf85458a2bb4a9b); break; case 0xd: // log2(e) source.high = 0x3fff; source.low = U64(0xb8aa3b295c17f0bc); break; case 0xe: // log10(e) source.high = 0x3ffd; source.low = U64(0xde5bd8a937287195); break; case 0xf: // 0.0 source = int32_to_floatx80((INT32)0); break; case 0x30: // ln(2) source.high = 0x3ffe; source.low = U64(0xb17217f7d1cf79ac); break; case 0x31: // ln(10) source.high = 0x4000; source.low = U64(0x935d8dddaaa8ac17); break; case 0x32: // 1 (or 100? manuals are unclear, but 1 would make more sense) source = int32_to_floatx80((INT32)1); break; case 0x33: // 10^1 source = int32_to_floatx80((INT32)10); break; case 0x34: // 10^2 source = int32_to_floatx80((INT32)10*10); break; case 0x35: // 10^4 source = int32_to_floatx80((INT32)1000*10); break; case 0x36: // 1.0e8 source = int32_to_floatx80((INT32)10000000*10); break; case 0x37: // 1.0e16 - can't get the right precision from INT32 so go "direct" with constants from h/w source.high = 0x4034; source.low = U64(0x8e1bc9bf04000000); break; case 0x38: // 1.0e32 source.high = 0x4069; source.low = U64(0x9dc5ada82b70b59e); break; case 0x39: // 1.0e64 source.high = 0x40d3; source.low = U64(0xc2781f49ffcfa6d5); break; case 0x3a: // 1.0e128 source.high = 0x41a8; source.low = U64(0x93ba47c980e98ce0); break; case 0x3b: // 1.0e256 source.high = 0x4351; source.low = U64(0xaa7eebfb9df9de8e); break; case 0x3c: // 1.0e512 source.high = 0x46a3; source.low = U64(0xe319a0aea60e91c7); break; case 0x3d: // 1.0e1024 source.high = 0x4d48; source.low = U64(0xc976758681750c17); break; case 0x3e: // 1.0e2048 source.high = 0x5a92; source.low = U64(0x9e8b3b5dc53d5de5); break; case 0x3f: // 1.0e4096 source.high = 0x7525; source.low = U64(0xc46052028a20979b); break; default: fatalerror("fmove_rm_reg: unknown constant ROM offset %x at %08x\n", w2&0x7f, REG_PC(m68k)-4); break; } // handle it right here, the usual opmode bits aren't valid in the FMOVECR case REG_FP(m68k)[dst] = source; m68k->remaining_cycles -= 4; return; } default: fatalerror("fmove_rm_reg: invalid source specifier %x at %08X\n", src, REG_PC(m68k)-4); } } else { source = REG_FP(m68k)[src]; } switch (opmode) { case 0x00: // FMOVE { REG_FP(m68k)[dst] = source; SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 4; break; } case 0x01: // FINT { INT32 temp; temp = floatx80_to_int32(source); REG_FP(m68k)[dst] = int32_to_floatx80(temp); break; } case 0x03: // FINTRZ { INT32 temp; temp = floatx80_to_int32_round_to_zero(source); REG_FP(m68k)[dst] = int32_to_floatx80(temp); break; } case 0x04: // FSQRT { REG_FP(m68k)[dst] = floatx80_sqrt(source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 109; break; } case 0x06: // FLOGNP1 { REG_FP(m68k)[dst] = floatx80_flognp1 (source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 594; // for MC68881 break; } case 0x0e: // FSIN { REG_FP(m68k)[dst] = source; floatx80_fsin(REG_FP(m68k)[dst]); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 75; break; } case 0x0f: // FTAN { REG_FP(m68k)[dst] = source; floatx80_ftan(REG_FP(m68k)[dst]); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 75; break; } case 0x14: // FLOGN { REG_FP(m68k)[dst] = floatx80_flogn (source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 548; // for MC68881 break; } case 0x15: // FLOG10 { REG_FP(m68k)[dst] = floatx80_flog10 (source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 604; // for MC68881 break; } case 0x16: // FLOG2 { REG_FP(m68k)[dst] = floatx80_flog2 (source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 604; // for MC68881 break; } case 0x18: // FABS { REG_FP(m68k)[dst] = source; REG_FP(m68k)[dst].high &= 0x7fff; SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 3; break; } case 0x1a: // FNEG { REG_FP(m68k)[dst] = source; REG_FP(m68k)[dst].high ^= 0x8000; SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 3; break; } case 0x1d: // FCOS { REG_FP(m68k)[dst] = source; floatx80_fcos(REG_FP(m68k)[dst]); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 75; break; } case 0x1e: // FGETEXP { INT16 temp2; temp2 = source.high; // get the exponent temp2 -= 0x3fff; // take off the bias REG_FP(m68k)[dst] = double_to_fx80((double)temp2); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 6; break; } case 0x20: // FDIV { REG_FP(m68k)[dst] = floatx80_div(REG_FP(m68k)[dst], source); m68k->remaining_cycles -= 43; break; } case 0x22: // FADD { REG_FP(m68k)[dst] = floatx80_add(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 9; break; } case 0x23: // FMUL { REG_FP(m68k)[dst] = floatx80_mul(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 11; break; } case 0x24: // FSGLDIV { float32 a = floatx80_to_float32( REG_FP(m68k)[dst] ); float32 b = floatx80_to_float32( source ); REG_FP(m68k)[dst] = float32_to_floatx80( float32_div(a, b) ); m68k->remaining_cycles -= 43; // // ? (value is from FDIV) break; } case 0x25: // FREM { REG_FP(m68k)[dst] = floatx80_rem(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 43; // guess break; } case 0x27: // FSGLMUL { float32 a = floatx80_to_float32( REG_FP(m68k)[dst] ); float32 b = floatx80_to_float32( source ); REG_FP(m68k)[dst] = float32_to_floatx80( float32_mul(a, b) ); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 11; // ? (value is from FMUL) break; } case 0x28: // FSUB { REG_FP(m68k)[dst] = floatx80_sub(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 9; break; } case 0x38: // FCMP { floatx80 res; res = floatx80_sub(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, res); m68k->remaining_cycles -= 7; break; } case 0x3a: // FTST { floatx80 res; res = source; SET_CONDITION_CODES(m68k, res); m68k->remaining_cycles -= 7; break; } default: fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PPC(m68k)); } }
static void fpgen_rm_reg(UINT16 w2) { int ea = REG_IR & 0x3f; int rm = (w2 >> 14) & 0x1; int src = (w2 >> 10) & 0x7; int dst = (w2 >> 7) & 0x7; int opmode = w2 & 0x7f; double source; if (rm) { switch (src) { case 0: // Long-Word Integer { INT32 d = READ_EA_32(ea); source = (double)(d); break; } case 1: // Single-precision Real { UINT32 d = READ_EA_32(ea); source = (double)(*(float*)&d); break; } case 2: // Extended-precision Real { fatalerror("fpgen_rm_reg: extended-precision real load unimplemented at %08X\n", REG_PC-4); break; } case 3: // Packed-decimal Real { fatalerror("fpgen_rm_reg: packed-decimal real load unimplemented at %08X\n", REG_PC-4); break; } case 4: // Word Integer { INT16 d = READ_EA_16(ea); source = (double)(d); break; } case 5: // Double-precision Real { UINT64 d = READ_EA_64(ea); source = *(double*)&d; break; } case 6: // Byte Integer { INT8 d = READ_EA_8(ea); source = (double)(d); break; } default: fatalerror("fmove_rm_reg: invalid source specifier at %08X\n", REG_PC-4); } } else { source = REG_FP[src].f; } switch (opmode) { case 0x00: // FMOVE { REG_FP[dst].f = source; USE_CYCLES(4); break; } case 0x04: // FSQRT { REG_FP[dst].f = sqrt(source); // TODO: condition codes USE_CYCLES(109); break; } case 0x18: // FABS { REG_FP[dst].f = fabs(source); // TODO: condition codes USE_CYCLES(3); break; } case 0x1a: // FNEG { REG_FP[dst].f = -source; // TODO: condition codes USE_CYCLES(3); break; } case 0x20: // FDIV { REG_FP[dst].f /= source; USE_CYCLES(43); break; } case 0x22: // FADD { REG_FP[dst].f += source; // TODO: condition codes USE_CYCLES(9); break; } case 0x23: // FMUL { REG_FP[dst].f *= source; // TODO: condition codes USE_CYCLES(11); break; } case 0x28: // FSUB { REG_FP[dst].f -= source; // TODO: condition codes USE_CYCLES(9); break; } case 0x38: // FCMP { // TODO: condition codes !!! USE_CYCLES(7); break; } case 0x3a: // FTST { // TODO: condition codes !!! USE_CYCLES(7); break; } default: fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PC-4); } }
static void fpgen_rm_reg(m68ki_cpu_core *m68k, UINT16 w2) { int ea = m68k->ir & 0x3f; int rm = (w2 >> 14) & 0x1; int src = (w2 >> 10) & 0x7; int dst = (w2 >> 7) & 0x7; int opmode = w2 & 0x7f; floatx80 source; // fmovecr #$f, fp0 f200 5c0f if (rm) { switch (src) { case 0: // Long-Word Integer { INT32 d = READ_EA_32(m68k, ea); source = int32_to_floatx80(d); break; } case 1: // Single-precision Real { UINT32 d = READ_EA_32(m68k, ea); source = float32_to_floatx80(d); break; } case 2: // Extended-precision Real { source = READ_EA_FPE(m68k, ea); break; } case 3: // Packed-decimal Real { source = READ_EA_PACK(m68k, ea); break; } case 4: // Word Integer { INT16 d = READ_EA_16(m68k, ea); source = int32_to_floatx80((INT32)d); break; } case 5: // Double-precision Real { UINT64 d = READ_EA_64(m68k, ea); source = float64_to_floatx80(d); break; } case 6: // Byte Integer { INT8 d = READ_EA_8(m68k, ea); source = int32_to_floatx80((INT32)d); break; } case 7: // FMOVECR load from constant ROM { switch (w2 & 0x7f) { case 0x0: // Pi source.high = 0x4000; source.low = U64(0xc90fdaa22168c235); break; case 0xb: // log10(2) source.high = 0x3ffd; source.low = U64(0x9a209a84fbcff798); break; case 0xc: // e source.high = 0x4000; source.low = U64(0xadf85458a2bb4a9b); break; case 0xd: // log2(e) source.high = 0x3fff; source.low = U64(0xb8aa3b295c17f0bc); break; case 0xe: // log10(e) source.high = 0x3ffd; source.low = U64(0xde5bd8a937287195); break; case 0xf: // 0.0 source = int32_to_floatx80((INT32)0); break; case 0x30: // ln(2) source.high = 0x3ffe; source.low = U64(0xb17217f7d1cf79ac); break; case 0x31: // ln(10) source.high = 0x4000; source.low = U64(0x935d8dddaaa8ac17); break; case 0x32: // 1 (or 100? manuals are unclear, but 1 would make more sense) source = int32_to_floatx80((INT32)1); break; case 0x33: // 10^1 source = int32_to_floatx80((INT32)10); break; case 0x34: // 10^2 source = int32_to_floatx80((INT32)10*10); break; default: fatalerror("fmove_rm_reg: unknown constant ROM offset %x at %08x\n", w2&0x7f, REG_PC(m68k)-4); break; } // handle it right here, the usual opmode bits aren't valid in the FMOVECR case REG_FP(m68k)[dst] = source; m68k->remaining_cycles -= 4; return; } default: fatalerror("fmove_rm_reg: invalid source specifier %x at %08X\n", src, REG_PC(m68k)-4); } } else { source = REG_FP(m68k)[src]; } switch (opmode) { case 0x00: // FMOVE { REG_FP(m68k)[dst] = source; SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 4; break; } case 0x01: // FINT { INT32 temp; temp = floatx80_to_int32(source); REG_FP(m68k)[dst] = int32_to_floatx80(temp); break; } case 0x03: // FINTRZ { INT32 temp; temp = floatx80_to_int32_round_to_zero(source); REG_FP(m68k)[dst] = int32_to_floatx80(temp); break; } case 0x04: // FSQRT { REG_FP(m68k)[dst] = floatx80_sqrt(source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 109; break; } case 0x0e: // FSIN { REG_FP(m68k)[dst] = source; floatx80_fsin(REG_FP(m68k)[dst]); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 75; break; } case 0x0f: // FTAN { REG_FP(m68k)[dst] = source; floatx80_ftan(REG_FP(m68k)[dst]); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 75; break; } case 0x18: // FABS { REG_FP(m68k)[dst] = source; REG_FP(m68k)[dst].high &= 0x7fff; SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 3; break; } case 0x1a: // FNEG { REG_FP(m68k)[dst] = source; REG_FP(m68k)[dst].high ^= 0x8000; SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 3; break; } case 0x1d: // FCOS { REG_FP(m68k)[dst] = source; floatx80_fcos(REG_FP(m68k)[dst]); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 75; break; } case 0x1e: // FGETEXP { INT16 temp2; temp2 = source.high; // get the exponent temp2 -= 0x3fff; // take off the bias REG_FP(m68k)[dst] = double_to_fx80((double)temp2); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 6; } case 0x20: // FDIV { REG_FP(m68k)[dst] = floatx80_div(REG_FP(m68k)[dst], source); m68k->remaining_cycles -= 43; break; } case 0x22: // FADD { REG_FP(m68k)[dst] = floatx80_add(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 9; break; } case 0x23: // FMUL { REG_FP(m68k)[dst] = floatx80_mul(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 11; break; } case 0x24: // FSGLDIV { REG_FP(m68k)[dst] = floatx80_div(REG_FP(m68k)[dst], source); m68k->remaining_cycles -= 43; // // ? (value is from FDIV) break; } case 0x25: // FREM { REG_FP(m68k)[dst] = floatx80_rem(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 43; // guess break; } case 0x27: // FSGLMUL { REG_FP(m68k)[dst] = floatx80_mul(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 11; // ? (value is from FMUL) break; } case 0x28: // FSUB { REG_FP(m68k)[dst] = floatx80_sub(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, REG_FP(m68k)[dst]); m68k->remaining_cycles -= 9; break; } case 0x38: // FCMP { floatx80 res; res = floatx80_sub(REG_FP(m68k)[dst], source); SET_CONDITION_CODES(m68k, res); m68k->remaining_cycles -= 7; break; } case 0x3a: // FTST { floatx80 res; res = source; SET_CONDITION_CODES(m68k, res); m68k->remaining_cycles -= 7; break; } default: fatalerror("fpgen_rm_reg: unimplemented opmode %02X at %08X\n", opmode, REG_PPC(m68k)); } }