mirror of
https://github.com/kanjitalk755/macemu.git
synced 2025-01-14 14:33:46 +00:00
7cc1bbc7b8
NewWorld ROM. That may be 8.1.0 included but original iMac had a NewWorld ROM compatible system. Otherwise we will crash because the boot routine is trying to execute code through unitialized descriptor that points to 0x13ff, which is obviously wrong (and unaligned on word-boundaries for 68k code).
493 lines
13 KiB
C++
493 lines
13 KiB
C++
/*
|
|
* 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 <stdio.h>
|
|
|
|
#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; i<len; i++)
|
|
XPRAM[((ofs + i) & 0xff) + 0x1300] = *adr++;
|
|
} else {
|
|
for (uint32 i=0; i<len; i++)
|
|
*adr++ = XPRAM[((ofs + i) & 0xff) + 0x1300];
|
|
}
|
|
break;
|
|
}
|
|
|
|
case OP_XPRAM2: // Read from XPRam
|
|
r->d[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<pstr[0]; i++)
|
|
str[i] = pstr[i+1];
|
|
str[i] = 0;
|
|
WarningAlert(str);
|
|
}
|
|
break;
|
|
|
|
case OP_INSTALL_DRIVERS: { // Patch to install our own drivers during startup
|
|
// Install drivers
|
|
InstallDrivers();
|
|
|
|
// Patch MakeExecutable()
|
|
MakeExecutableTvec = FindLibSymbol("\023PrivateInterfaceLib", "\016MakeExecutable");
|
|
D(bug("MakeExecutable TVECT at %08x\n", MakeExecutableTvec));
|
|
WriteMacInt32(MakeExecutableTvec, NativeFunction(NATIVE_MAKE_EXECUTABLE));
|
|
#if !EMULATED_PPC
|
|
WriteMacInt32(MakeExecutableTvec + 4, (uint32)TOC);
|
|
#endif
|
|
|
|
// Patch DebugStr()
|
|
static const uint8 proc_template[] = {
|
|
M68K_EMUL_OP_DEBUG_STR >> 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_CHECK_SYSV: { // Check we are not using MacOS < 8.1 with a NewWorld ROM
|
|
r->a[1] = r->d[1];
|
|
r->a[0] = ReadMacInt32(r->d[1]);
|
|
uint32 sysv = ReadMacInt16(r->a[0]);
|
|
D(bug("Detected MacOS version %d.%d.%d\n", (sysv >> 8) & 0xf, (sysv >> 4) & 0xf, sysv & 0xf));
|
|
if (ROMType == ROMTYPE_NEWWORLD && sysv < 0x0801)
|
|
r->d[1] = 0;
|
|
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;
|
|
}
|
|
}
|