INLINE void SET_CONDITION_CODES(m68000_base_device *m68k, floatx80 reg) { // UINT64 *regi; // regi = (UINT64 *)® REG_FPSR(m68k) &= ~(FPCC_N|FPCC_Z|FPCC_I|FPCC_NAN); // sign flag if (reg.high & 0x8000) { REG_FPSR(m68k) |= FPCC_N; } // zero flag if (((reg.high & 0x7fff) == 0) && ((reg.low<<1) == 0)) { REG_FPSR(m68k) |= FPCC_Z; } // infinity flag if (((reg.high & 0x7fff) == 0x7fff) && ((reg.low<<1) == 0)) { REG_FPSR(m68k) |= FPCC_I; } // NaN flag if (floatx80_is_nan(reg)) { REG_FPSR(m68k) |= FPCC_NAN; } }
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; }
INLINE int TEST_CONDITION(m68000_base_device *m68k, int condition) { int n = (REG_FPSR(m68k) & FPCC_N) != 0; int z = (REG_FPSR(m68k) & FPCC_Z) != 0; int nan = (REG_FPSR(m68k) & FPCC_NAN) != 0; int r = 0; switch (condition) { case 0x10: case 0x00: return 0; // False case 0x11: case 0x01: return (z); // Equal case 0x12: case 0x02: return (!(nan || z || n)); // Greater Than case 0x13: case 0x03: return (z || !(nan || n)); // Greater or Equal case 0x14: case 0x04: return (n && !(nan || z)); // Less Than case 0x15: case 0x05: return (z || (n && !nan)); // Less Than or Equal case 0x16: case 0x06: return !nan && !z; case 0x17: case 0x07: return !nan; case 0x18: case 0x08: return nan; case 0x19: case 0x09: return nan || z; case 0x1a: case 0x0a: return (nan || !(n || z)); // Not Less Than or Equal case 0x1b: case 0x0b: return (nan || z || !n); // Not Less Than case 0x1c: case 0x0c: return (nan || (n && !z)); // Not Greater or Equal Than case 0x1d: case 0x0d: return (nan || z || n); // Not Greater Than case 0x1e: case 0x0e: return (!z); // Not Equal case 0x1f: case 0x0f: return 1; // True default: fatalerror("M68kFPU: test_condition: unhandled condition %02X\n", condition); } return r; }
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 fmove_reg_mem(m68000_base_device *m68k, UINT16 w2) { int ea = m68k->ir & 0x3f; int src = (w2 >> 7) & 0x7; int dst = (w2 >> 10) & 0x7; int k = (w2 & 0x7f); switch (dst) { case 0: // Long-Word Integer { INT32 d = (INT32)floatx80_to_int32(REG_FP(m68k)[src]); WRITE_EA_32(m68k, ea, d); break; } case 1: // Single-precision Real { UINT32 d = floatx80_to_float32(REG_FP(m68k)[src]); WRITE_EA_32(m68k, ea, d); break; } case 2: // Extended-precision Real { WRITE_EA_FPE(m68k, ea, REG_FP(m68k)[src]); break; } case 3: // Packed-decimal Real with Static K-factor { // sign-extend k k = (k & 0x40) ? (k | 0xffffff80) : (k & 0x7f); WRITE_EA_PACK(m68k, ea, k, REG_FP(m68k)[src]); break; } case 4: // Word Integer { int32 value = floatx80_to_int32(REG_FP(m68k)[src]); if (value > 0x7fff || value < -0x8000 ) { REG_FPSR(m68k) |= FPES_OE | FPAE_IOP; } WRITE_EA_16(m68k, ea, (INT16)value); break; } case 5: // Double-precision Real { UINT64 d; d = floatx80_to_float64(REG_FP(m68k)[src]); WRITE_EA_64(m68k, ea, d); break; } case 6: // Byte Integer { int32 value = floatx80_to_int32(REG_FP(m68k)[src]); if (value > 127 || value < -128) { REG_FPSR(m68k) |= FPES_OE | FPAE_IOP; } WRITE_EA_8(m68k, ea, (INT8) value); break; } case 7: // Packed-decimal Real with Dynamic K-factor { WRITE_EA_PACK(m68k, ea, REG_D(m68k)[k>>4], REG_FP(m68k)[src]); break; } } m68k->remaining_cycles -= 12; }