static floatx80 READ_EA_PACK(m68ki_cpu_core *m68k, int ea) { floatx80 fpr; int mode = (ea >> 3) & 0x7; int reg = (ea & 0x7); switch (mode) { case 2: // (An) { UINT32 ea = REG_A(m68k)[reg]; fpr = load_pack_float80(m68k, ea); break; } case 3: // (An)+ { UINT32 ea = REG_A(m68k)[reg]; REG_A(m68k)[reg] += 12; fpr = load_pack_float80(m68k, ea); break; } case 7: // extended modes { switch (reg) { case 3: // (d16,PC,Dx.w) { UINT32 ea = EA_PCIX_32(m68k); fpr = load_pack_float80(m68k, ea); } break; default: fatalerror("M68kFPU: READ_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); break; } } break; default: fatalerror("M68kFPU: READ_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); break; } return fpr; }
static void WRITE_EA_8(m68ki_cpu_core *m68k, int ea, UINT8 data) { int mode = (ea >> 3) & 0x7; int reg = (ea & 0x7); switch (mode) { case 0: // Dn { REG_D(m68k)[reg] = data; break; } case 2: // (An) { UINT32 ea = REG_A(m68k)[reg]; m68ki_write_8(m68k, ea, data); break; } case 3: // (An)+ { UINT32 ea = EA_AY_PI_8(m68k); m68ki_write_8(m68k, ea, data); break; } case 4: // -(An) { UINT32 ea = EA_AY_PD_8(m68k); m68ki_write_8(m68k, ea, data); break; } case 5: // (d16, An) { UINT32 ea = EA_AY_DI_8(m68k); m68ki_write_8(m68k, ea, data); break; } case 6: // (An) + (Xn) + d8 { UINT32 ea = EA_AY_IX_8(m68k); m68ki_write_8(m68k, ea, data); break; } case 7: { switch (reg) { case 1: // (xxx).B { UINT32 d1 = OPER_I_16(m68k); UINT32 d2 = OPER_I_16(m68k); UINT32 ea = (d1 << 16) | d2; m68ki_write_8(m68k, ea, data); break; } case 2: // (d16, PC) { UINT32 ea = EA_PCDI_16(m68k); m68ki_write_8(m68k, ea, data); break; } default: fatalerror("M68kFPU: WRITE_EA_8: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); } break; } default: fatalerror("M68kFPU: WRITE_EA_8: unhandled mode %d, reg %d, data %08X at %08X\n", mode, reg, data, REG_PC(m68k)); } }
static UINT64 READ_EA_64(m68ki_cpu_core *m68k, int ea) { int mode = (ea >> 3) & 0x7; int reg = (ea & 0x7); UINT32 h1, h2; switch (mode) { case 2: // (An) { UINT32 ea = REG_A(m68k)[reg]; h1 = m68ki_read_32(m68k, ea+0); h2 = m68ki_read_32(m68k, ea+4); return (UINT64)(h1) << 32 | (UINT64)(h2); } case 3: // (An)+ { UINT32 ea = REG_A(m68k)[reg]; REG_A(m68k)[reg] += 8; h1 = m68ki_read_32(m68k, ea+0); h2 = m68ki_read_32(m68k, ea+4); return (UINT64)(h1) << 32 | (UINT64)(h2); } case 4: // -(An) { UINT32 ea = REG_A(m68k)[reg]-8; REG_A(m68k)[reg] -= 8; h1 = m68ki_read_32(m68k, ea+0); h2 = m68ki_read_32(m68k, ea+4); return (UINT64)(h1) << 32 | (UINT64)(h2); } case 5: // (d16, An) { UINT32 ea = EA_AY_DI_32(m68k); h1 = m68ki_read_32(m68k, ea+0); h2 = m68ki_read_32(m68k, ea+4); return (UINT64)(h1) << 32 | (UINT64)(h2); } case 6: // (An) + (Xn) + d8 { UINT32 ea = EA_AY_IX_32(m68k); h1 = m68ki_read_32(m68k, ea+0); h2 = m68ki_read_32(m68k, ea+4); return (UINT64)(h1) << 32 | (UINT64)(h2); } case 7: { switch (reg) { case 1: // (xxx).L { UINT32 d1 = OPER_I_16(m68k); UINT32 d2 = OPER_I_16(m68k); UINT32 ea = (d1 << 16) | d2; return (UINT64)(m68ki_read_32(m68k, ea)) << 32 | (UINT64)(m68ki_read_32(m68k, ea+4)); } case 3: // (PC) + (Xn) + d8 { UINT32 ea = EA_PCIX_32(m68k); h1 = m68ki_read_32(m68k, ea+0); h2 = m68ki_read_32(m68k, ea+4); return (UINT64)(h1) << 32 | (UINT64)(h2); } case 4: // #<data> { h1 = OPER_I_32(m68k); h2 = OPER_I_32(m68k); return (UINT64)(h1) << 32 | (UINT64)(h2); } case 2: // (d16, PC) { UINT32 ea = EA_PCDI_32(m68k); h1 = m68ki_read_32(m68k, ea+0); h2 = m68ki_read_32(m68k, ea+4); return (UINT64)(h1) << 32 | (UINT64)(h2); } default: fatalerror("M68kFPU: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); } break; } default: fatalerror("M68kFPU: READ_EA_64: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); } return 0; }
static floatx80 READ_EA_FPE(m68ki_cpu_core *m68k, int ea) { floatx80 fpr; int mode = (ea >> 3) & 0x7; int reg = (ea & 0x7); switch (mode) { case 2: // (An) { UINT32 ea = REG_A(m68k)[reg]; fpr = load_extended_float80(m68k, ea); break; } case 3: // (An)+ { UINT32 ea = REG_A(m68k)[reg]; REG_A(m68k)[reg] += 12; fpr = load_extended_float80(m68k, ea); break; } case 4: // -(An) { UINT32 ea = REG_A(m68k)[reg]-12; REG_A(m68k)[reg] -= 12; fpr = load_extended_float80(m68k, ea); break; } case 5: // (d16, An) { // FIXME: will fail for fmovem UINT32 ea = EA_AY_DI_32(m68k); fpr = load_extended_float80(m68k, ea); break; } case 6: // (An) + (Xn) + d8 { // FIXME: will fail for fmovem UINT32 ea = EA_AY_IX_32(m68k); fpr = load_extended_float80(m68k, ea); break; } case 7: // extended modes { switch (reg) { case 2: // (d16, PC) { UINT32 ea = EA_PCDI_32(m68k); fpr = load_extended_float80(m68k, ea); } break; case 3: // (d16,PC,Dx.w) { UINT32 ea = EA_PCIX_32(m68k); fpr = load_extended_float80(m68k, ea); } break; default: fatalerror("M68kFPU: READ_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); break; } } break; default: fatalerror("M68kFPU: READ_EA_FPE: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); break; } return fpr; }
static UINT32 READ_EA_32(m68ki_cpu_core *m68k, int ea) { int mode = (ea >> 3) & 0x7; int reg = (ea & 0x7); switch (mode) { case 0: // Dn { return REG_D(m68k)[reg]; } case 2: // (An) { UINT32 ea = REG_A(m68k)[reg]; return m68ki_read_32(m68k, ea); } case 3: // (An)+ { UINT32 ea = EA_AY_PI_32(m68k); return m68ki_read_32(m68k, ea); } case 4: // -(An) { UINT32 ea = EA_AY_PD_32(m68k); return m68ki_read_32(m68k, ea); } case 5: // (d16, An) { UINT32 ea = EA_AY_DI_32(m68k); return m68ki_read_32(m68k, ea); } case 6: // (An) + (Xn) + d8 { UINT32 ea = EA_AY_IX_32(m68k); return m68ki_read_32(m68k, ea); } case 7: { switch (reg) { case 0: // (xxx).W { UINT32 ea = (UINT32)OPER_I_16(m68k); return m68ki_read_32(m68k, ea); } case 1: // (xxx).L { UINT32 d1 = OPER_I_16(m68k); UINT32 d2 = OPER_I_16(m68k); UINT32 ea = (d1 << 16) | d2; return m68ki_read_32(m68k, ea); } case 2: // (d16, PC) { UINT32 ea = EA_PCDI_32(m68k); return m68ki_read_32(m68k, ea); } case 3: // (PC) + (Xn) + d8 { UINT32 ea = EA_PCIX_32(m68k); return m68ki_read_32(m68k, ea); } case 4: // #<data> { return OPER_I_32(m68k); } default: fatalerror("M68kFPU: READ_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); } break; } default: fatalerror("M68kFPU: READ_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC(m68k)); } return 0; }
static void fmovem(m68ki_cpu_core *m68k, UINT16 w2) { int i; int ea = m68k->ir & 0x3f; int dir = (w2 >> 13) & 0x1; int mode = (w2 >> 11) & 0x3; int reglist = w2 & 0xff; UINT32 mem_addr = 0; switch (ea >> 3) { case 5: // (d16, An) mem_addr= EA_AY_DI_32(m68k); break; case 6: // (An) + (Xn) + d8 mem_addr= EA_AY_IX_32(m68k); break; } if (dir) // From FP regs to mem { switch (mode) { case 1: // Dynamic register list, postincrement or control addressing mode. // FIXME: not really tested, but seems to work reglist = REG_D(m68k)[(reglist >> 4) & 7]; case 0: // Static register list, predecrement or control addressing mode { for (i=0; i < 8; i++) { if (reglist & (1 << i)) { switch (ea >> 3) { case 5: // (d16, An) case 6: // (An) + (Xn) + d8 store_extended_float80(m68k, mem_addr, REG_FP(m68k)[i]); mem_addr += 12; break; default: WRITE_EA_FPE(m68k, ea, REG_FP(m68k)[i]); break; } m68k->remaining_cycles -= 2; } } break; } case 2: // Static register list, postdecrement or control addressing mode { for (i=0; i < 8; i++) { if (reglist & (1 << i)) { switch (ea >> 3) { case 5: // (d16, An) case 6: // (An) + (Xn) + d8 store_extended_float80(m68k, mem_addr, REG_FP(m68k)[7-i]); mem_addr += 12; break; default: WRITE_EA_FPE(m68k, ea, REG_FP(m68k)[7-i]); break; } m68k->remaining_cycles -= 2; } } break; } default: fatalerror("M680x0: FMOVEM: mode %d unimplemented at %08X\n", mode, REG_PC(m68k)-4); } } else // From mem to FP regs { switch (mode)
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)); } }
static void WRITE_EA_PACK(m68ki_cpu_core *m68k, int ea, int k, floatx80 fpr) { int mode = (ea >> 3) & 0x7; int reg = (ea & 0x7); switch (mode) { case 2: // (An) { UINT32 ea; ea = REG_A(m68k)[reg]; store_pack_float80(m68k, ea, k, fpr); break; } case 3: // (An)+ { UINT32 ea; ea = REG_A(m68k)[reg]; store_pack_float80(m68k, ea, k, fpr); REG_A(m68k)[reg] += 12; break; } case 4: // -(An) { UINT32 ea; REG_A(m68k)[reg] -= 12; ea = REG_A(m68k)[reg]; store_pack_float80(m68k, ea, k, fpr); break; } case 7: { switch (reg) { default: fatalerror("M68kFPU: WRITE_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); } } default: fatalerror("M68kFPU: WRITE_EA_PACK: unhandled mode %d, reg %d, at %08X\n", mode, reg, REG_PC(m68k)); } }
int apollo_debug_instruction_hook(device_t *device, offs_t curpc) { // trap data remembered for next rte static struct { UINT32 pc; UINT32 sp; UINT16 trap_no; UINT16 trap_code; } trap = { 0, 0, 0, 0 }; if (apollo_config( APOLLO_CONF_TRAP_TRACE | APOLLO_CONF_FPU_TRACE)) { UINT32 ppc_save; UINT16 ir; m68ki_cpu_core *m68k = (m68ki_cpu_core *) downcast<legacy_cpu_device *> (device)->token(); m68k->mmu_tmp_buserror_occurred = 0; /* Read next instruction */ ir = (m68k->pref_addr == REG_PC(m68k)) ? m68k->pref_data : m68k->memory.readimm16(REG_PC(m68k)); // apollo_cpu_context expects the PC of current opcode in REG_PPC (not the previous PC) ppc_save = REG_PPC(m68k); REG_PPC(m68k) = REG_PC(m68k); if (m68k->mmu_tmp_buserror_occurred) { m68k->mmu_tmp_buserror_occurred = 0; // give up } else if ((ir & 0xff00) == 0xf200 && (apollo_config( APOLLO_CONF_FPU_TRACE))) { char sb[256]; LOG(("%s sp=%08x FPU: %x %s", apollo_cpu_context(device->machine().firstcpu), REG_A(m68k)[7], ir, disassemble(m68k, REG_PC(m68k), sb))); } else if (!m68k->pmmu_enabled) { // skip } else if (ir == 0x4e73) // RTE { const UINT16 *data = get_data(m68k, REG_A(m68k)[7]); if ( REG_USP(m68k) == 0 && (data[0] & 0x2000) == 0) { LOG(("%s sp=%08x RTE: sr=%04x pc=%04x%04x v=%04x usp=%08x", apollo_cpu_context(device->machine().firstcpu), REG_A(m68k)[7], data[0], data[1], data[2], data[3], REG_USP(m68k))); } } else if ((ir & 0xfff0) == 0x4e40 && (ir & 0x0f) <= 8 && apollo_config(APOLLO_CONF_TRAP_TRACE)) { // trap n trap.pc = REG_PC(m68k); trap.sp = REG_A(m68k)[7]; trap.trap_no = ir & 0x0f; trap.trap_code = REG_D(m68k)[0] & 0xffff; char sb[1000]; LOG(("%s sp=%08x Domain/OS SVC: trap %x 0x%02x: %s", apollo_cpu_context(device->machine().firstcpu), trap.sp, trap.trap_no, trap.trap_code, get_svc_call(m68k, trap.trap_no, trap.trap_code, sb))); } else if (trap.pc == REG_PC(m68k) - 2 && trap.sp == REG_A(m68k)[7]) { // rte char sb[1000]; LOG(("%s sp=%08x Domain/OS SVC: %s D0=0x%x", apollo_cpu_context(device->machine().firstcpu), trap.sp, get_svc_call(m68k, trap.trap_no, trap.trap_code, sb), REG_D(m68k)[0])); trap.pc = 0; trap.sp = 0; trap.trap_no = 0; trap.trap_code = 0; } // restore previous PC REG_PPC(m68k) = ppc_save; } return 0; }