/* * emul_op.cpp - 68k opcodes for ROM patches * * SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "sysdeps.h" #include "main.h" #include "version.h" #include "prefs.h" #include "cpu_emulation.h" #include "xlowmem.h" #include "xpram.h" #include "timer.h" #include "adb.h" #include "sony.h" #include "disk.h" #include "cdrom.h" #include "scsi.h" #include "video.h" #include "audio.h" #include "ether.h" #include "serial.h" #include "clip.h" #include "extfs.h" #include "macos_util.h" #include "rom_patches.h" #include "rsrc_patches.h" #include "name_registry.h" #include "user_strings.h" #include "emul_op.h" #include "thunks.h" #define DEBUG 0 #include "debug.h" // TVector of MakeExecutable static uint32 MakeExecutableTvec; /* * Execute EMUL_OP opcode (called by 68k emulator) */ void EmulOp(M68kRegisters *r, uint32 pc, int selector) { D(bug("EmulOp %04x at %08x\n", selector, pc)); switch (selector) { case OP_BREAK: // Breakpoint printf("*** Breakpoint\n"); Dump68kRegs(r); break; case OP_XPRAM1: { // Read/write from/to XPRam uint32 len = r->d[3]; uint8 *adr = Mac2HostAddr(r->a[3]); D(bug("XPRAMReadWrite d3: %08lx, a3: %p\n", len, adr)); int ofs = len & 0xffff; len >>= 16; if (len & 0x8000) { len &= 0x7fff; for (uint32 i=0; id[1] = XPRAM[(r->d[1] & 0xff) + 0x1300]; break; case OP_XPRAM3: // Write to XPRam XPRAM[(r->d[1] & 0xff) + 0x1300] = r->d[2]; break; case OP_NVRAM1: { // Read from NVRAM int ofs = r->d[0]; r->d[0] = XPRAM[ofs & 0x1fff]; bool localtalk = !(XPRAM[0x13e0] || XPRAM[0x13e1]); // LocalTalk enabled? switch (ofs) { case 0x13e0: // Disable LocalTalk (use EtherTalk instead) if (localtalk) r->d[0] = 0x00; break; case 0x13e1: if (localtalk) r->d[0] = 0x01; break; case 0x13e2: if (localtalk) r->d[0] = 0x00; break; case 0x13e3: if (localtalk) r->d[0] = 0x0a; break; } break; } case OP_NVRAM2: // Write to NVRAM XPRAM[r->d[0] & 0x1fff] = r->d[1]; break; case OP_NVRAM3: // Read/write from/to NVRAM if (r->d[3]) { r->d[0] = XPRAM[(r->d[4] + 0x1300) & 0x1fff]; } else { XPRAM[(r->d[4] + 0x1300) & 0x1fff] = r->d[5]; r->d[0] = 0; } break; case OP_FIX_MEMTOP: // Fixes MemTop in BootGlobs during startup D(bug("Fix MemTop\n")); WriteMacInt32(BootGlobsAddr - 20, RAMBase + RAMSize); // MemTop r->a[6] = RAMBase + RAMSize; break; case OP_FIX_MEMSIZE: { // Fixes physical/logical RAM size during startup D(bug("Fix MemSize\n")); uint32 diff = ReadMacInt32(0x1ef8) - ReadMacInt32(0x1ef4); WriteMacInt32(0x1ef8, RAMSize); // Physical RAM size WriteMacInt32(0x1ef4, RAMSize - diff); // Logical RAM size break; } case OP_FIX_BOOTSTACK: // Fixes boot stack pointer in boot 3 resource D(bug("Fix BootStack\n")); r->a[1] = r->a[7] = RAMBase + RAMSize * 3 / 4; break; case OP_SONY_OPEN: // Floppy driver functions r->d[0] = SonyOpen(r->a[0], r->a[1]); break; case OP_SONY_PRIME: r->d[0] = SonyPrime(r->a[0], r->a[1]); break; case OP_SONY_CONTROL: r->d[0] = SonyControl(r->a[0], r->a[1]); break; case OP_SONY_STATUS: r->d[0] = SonyStatus(r->a[0], r->a[1]); break; case OP_DISK_OPEN: // Disk driver functions r->d[0] = DiskOpen(r->a[0], r->a[1]); break; case OP_DISK_PRIME: r->d[0] = DiskPrime(r->a[0], r->a[1]); break; case OP_DISK_CONTROL: r->d[0] = DiskControl(r->a[0], r->a[1]); break; case OP_DISK_STATUS: r->d[0] = DiskStatus(r->a[0], r->a[1]); break; case OP_CDROM_OPEN: // CD-ROM driver functions r->d[0] = CDROMOpen(r->a[0], r->a[1]); break; case OP_CDROM_PRIME: r->d[0] = CDROMPrime(r->a[0], r->a[1]); break; case OP_CDROM_CONTROL: r->d[0] = CDROMControl(r->a[0], r->a[1]); break; case OP_CDROM_STATUS: r->d[0] = CDROMStatus(r->a[0], r->a[1]); break; case OP_AUDIO_DISPATCH: // Audio component functions r->d[0] = AudioDispatch(r->a[3], r->a[4]); break; case OP_SOUNDIN_OPEN: // Sound input driver functions r->d[0] = SoundInOpen(r->a[0], r->a[1]); break; case OP_SOUNDIN_PRIME: r->d[0] = SoundInPrime(r->a[0], r->a[1]); break; case OP_SOUNDIN_CONTROL: r->d[0] = SoundInControl(r->a[0], r->a[1]); break; case OP_SOUNDIN_STATUS: r->d[0] = SoundInStatus(r->a[0], r->a[1]); break; case OP_SOUNDIN_CLOSE: r->d[0] = SoundInClose(r->a[0], r->a[1]); break; case OP_ADBOP: // ADBOp() replacement ADBOp(r->d[0], Mac2HostAddr(ReadMacInt32(r->a[0]))); break; case OP_INSTIME: // InsTime() replacement r->d[0] = InsTime(r->a[0], r->d[1]); break; case OP_RMVTIME: // RmvTime() replacement r->d[0] = RmvTime(r->a[0]); break; case OP_PRIMETIME: // PrimeTime() replacement r->d[0] = PrimeTime(r->a[0], r->d[0]); break; case OP_MICROSECONDS: // Microseconds() replacement Microseconds(r->a[0], r->d[0]); break; case OP_PUT_SCRAP: // PutScrap() patch PutScrap(ReadMacInt32(r->a[7] + 8), Mac2HostAddr(ReadMacInt32(r->a[7] + 4)), ReadMacInt32(r->a[7] + 12)); break; case OP_GET_SCRAP: // GetScrap() patch GetScrap((void **)Mac2HostAddr(ReadMacInt32(r->a[7] + 4)), ReadMacInt32(r->a[7] + 8), ReadMacInt32(r->a[7] + 12)); break; case OP_DEBUG_STR: // DebugStr() shows warning message if (PrefsFindBool("nogui")) { uint8 *pstr = Mac2HostAddr(ReadMacInt32(r->a[7] + 4)); char str[256]; int i; for (i=0; i> 8, M68K_EMUL_OP_DEBUG_STR, 0x4e, 0x74, // rtd #4 0x00, 0x04 }; BUILD_SHEEPSHAVER_PROCEDURE(proc); WriteMacInt32(0x1dfc, proc); break; } case OP_NAME_REGISTRY: // Patch Name Registry and initialize CallUniversalProc r->d[0] = (uint32)-1; PatchNameRegistry(); InitCallUniversalProc(); break; case OP_RESET: // Early in MacOS reset D(bug("*** RESET ***\n")); TimerReset(); MacOSUtilReset(); AudioReset(); // Enable DR emulator (disabled for now) if (PrefsFindBool("jit68k") && 0) { D(bug("DR activated\n")); WriteMacInt32(KernelDataAddr + 0x17a0, 3); // Prepare for DR emulator activation WriteMacInt32(KernelDataAddr + 0x17c0, DR_CACHE_BASE); WriteMacInt32(KernelDataAddr + 0x17c4, DR_CACHE_SIZE); WriteMacInt32(KernelDataAddr + 0x1b04, DR_CACHE_BASE); WriteMacInt32(KernelDataAddr + 0x1b00, DR_EMULATOR_BASE); memcpy((void *)DR_EMULATOR_BASE, (void *)(ROM_BASE + 0x370000), DR_EMULATOR_SIZE); MakeExecutable(0, DR_EMULATOR_BASE, DR_EMULATOR_SIZE); } break; case OP_IRQ: // Level 1 interrupt WriteMacInt16(ReadMacInt32(KernelDataAddr + 0x67c), 0); // Clear interrupt r->d[0] = 0; if (HasMacStarted()) { if (InterruptFlags & INTFLAG_VIA) { ClearInterruptFlag(INTFLAG_VIA); #if !PRECISE_TIMING TimerInterrupt(); #endif ExecuteNative(NATIVE_VIDEO_VBL); static int tick_counter = 0; if (++tick_counter >= 60) { tick_counter = 0; SonyInterrupt(); DiskInterrupt(); CDROMInterrupt(); } r->d[0] = 1; // Flag: 68k interrupt routine executes VBLTasks etc. } if (InterruptFlags & INTFLAG_SERIAL) { ClearInterruptFlag(INTFLAG_SERIAL); SerialInterrupt(); } if (InterruptFlags & INTFLAG_ETHER) { ClearInterruptFlag(INTFLAG_ETHER); ExecuteNative(NATIVE_ETHER_IRQ); } if (InterruptFlags & INTFLAG_TIMER) { ClearInterruptFlag(INTFLAG_TIMER); TimerInterrupt(); } if (InterruptFlags & INTFLAG_AUDIO) { ClearInterruptFlag(INTFLAG_AUDIO); AudioInterrupt(); } if (InterruptFlags & INTFLAG_ADB) { ClearInterruptFlag(INTFLAG_ADB); ADBInterrupt(); } } else r->d[0] = 1; break; case OP_SCSI_DISPATCH: { // SCSIDispatch() replacement uint32 ret = ReadMacInt32(r->a[7]); uint16 sel = ReadMacInt16(r->a[7] + 4); r->a[7] += 6; // D(bug("SCSIDispatch(%d)\n", sel)); int stack; switch (sel) { case 0: // SCSIReset WriteMacInt16(r->a[7], SCSIReset()); stack = 0; break; case 1: // SCSIGet WriteMacInt16(r->a[7], SCSIGet()); stack = 0; break; case 2: // SCSISelect case 11: // SCSISelAtn WriteMacInt16(r->a[7] + 2, SCSISelect(ReadMacInt8(r->a[7] + 1))); stack = 2; break; case 3: // SCSICmd WriteMacInt16(r->a[7] + 6, SCSICmd(ReadMacInt16(r->a[7]), Mac2HostAddr(ReadMacInt32(r->a[7] + 2)))); stack = 6; break; case 4: // SCSIComplete WriteMacInt16(r->a[7] + 12, SCSIComplete(ReadMacInt32(r->a[7]), ReadMacInt32(r->a[7] + 4), ReadMacInt32(r->a[7] + 8))); stack = 12; break; case 5: // SCSIRead case 8: // SCSIRBlind WriteMacInt16(r->a[7] + 4, SCSIRead(ReadMacInt32(r->a[7]))); stack = 4; break; case 6: // SCSIWrite case 9: // SCSIWBlind WriteMacInt16(r->a[7] + 4, SCSIWrite(ReadMacInt32(r->a[7]))); stack = 4; break; case 10: // SCSIStat WriteMacInt16(r->a[7], SCSIStat()); stack = 0; break; case 12: // SCSIMsgIn WriteMacInt16(r->a[7] + 4, 0); stack = 4; break; case 13: // SCSIMsgOut WriteMacInt16(r->a[7] + 2, 0); stack = 2; break; case 14: // SCSIMgrBusy WriteMacInt16(r->a[7], SCSIMgrBusy()); stack = 0; break; default: printf("FATAL: SCSIDispatch: illegal selector\n"); stack = 0; //!! SysError(12) } r->a[0] = ret; r->a[7] += stack; break; } case OP_SCSI_ATOMIC: // SCSIAtomic() replacement D(bug("SCSIAtomic\n")); r->d[0] = (uint32)-7887; break; case OP_NTRB_17_PATCH: r->a[2] = ReadMacInt32(r->a[7]); r->a[7] += 4; if (ReadMacInt16(r->a[2] + 6) == 17) PatchNativeResourceManager(); break; case OP_NTRB_17_PATCH2: r->a[7] += 8; PatchNativeResourceManager(); break; case OP_NTRB_17_PATCH3: r->a[2] = ReadMacInt32(r->a[7]); r->a[7] += 4; D(bug("%d %d\n", ReadMacInt16(r->a[2]), ReadMacInt16(r->a[2] + 6))); if (ReadMacInt16(r->a[2]) == 11 && ReadMacInt16(r->a[2] + 6) == 17) PatchNativeResourceManager(); break; case OP_NTRB_17_PATCH4: r->d[0] = ReadMacInt16(r->a[7]); r->a[7] += 2; D(bug("%d %d\n", ReadMacInt16(r->a[2]), ReadMacInt16(r->a[2] + 6))); if (ReadMacInt16(r->a[2]) == 11 && ReadMacInt16(r->a[2] + 6) == 17) PatchNativeResourceManager(); break; case OP_CHECKLOAD: { // vCheckLoad() patch uint32 type = ReadMacInt32(r->a[7]); r->a[7] += 4; int16 id = ReadMacInt16(r->a[2]); if (r->a[0] == 0) break; uint32 adr = ReadMacInt32(r->a[0]); if (adr == 0) break; uint16 *p = (uint16 *)Mac2HostAddr(adr); uint32 size = ReadMacInt32(adr - 8) & 0xffffff; CheckLoad(type, id, p, size); break; } case OP_EXTFS_COMM: // External file system routines WriteMacInt16(r->a[7] + 14, ExtFSComm(ReadMacInt16(r->a[7] + 12), ReadMacInt32(r->a[7] + 8), ReadMacInt32(r->a[7] + 4))); break; case OP_EXTFS_HFS: WriteMacInt16(r->a[7] + 20, ExtFSHFS(ReadMacInt32(r->a[7] + 16), ReadMacInt16(r->a[7] + 14), ReadMacInt32(r->a[7] + 10), ReadMacInt32(r->a[7] + 6), ReadMacInt16(r->a[7] + 4))); break; case OP_IDLE_TIME: // Sleep if no events pending if (ReadMacInt32(0x14c) == 0) idle_wait(); r->a[0] = ReadMacInt32(0x2b6); break; case OP_IDLE_TIME_2: // Sleep if no events pending if (ReadMacInt32(0x14c) == 0) idle_wait(); r->d[0] = (uint32)-2; break; default: printf("FATAL: EMUL_OP called with bogus selector %08x\n", selector); QuitEmulator(); break; } }