macemu/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp

1238 lines
32 KiB
C++
Raw Normal View History

/*
* sheepshaver_glue.cpp - Glue Kheperix CPU to SheepShaver CPU engine interface
*
2008-01-01 09:47:39 +00:00
* SheepShaver (C) 1997-2008 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 "sysdeps.h"
#include "cpu_emulation.h"
#include "main.h"
#include "prefs.h"
#include "xlowmem.h"
#include "emul_op.h"
#include "rom_patches.h"
#include "macos_util.h"
#include "block-alloc.hpp"
#include "sigsegv.h"
#include "cpu/ppc/ppc-cpu.hpp"
#include "cpu/ppc/ppc-operations.hpp"
#include "cpu/ppc/ppc-instructions.hpp"
#include "thunks.h"
// Used for NativeOp trampolines
#include "video.h"
#include "name_registry.h"
#include "serial.h"
#include "ether.h"
#include "timer.h"
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#ifdef USE_SDL_VIDEO
#include <SDL_events.h>
#endif
#if ENABLE_MON
#include "mon.h"
#include "mon_disass.h"
#endif
#define DEBUG 0
#include "debug.h"
2012-06-16 02:16:40 +00:00
extern "C" {
#include "dis-asm.h"
}
// Emulation time statistics
#ifndef EMUL_TIME_STATS
#define EMUL_TIME_STATS 0
#endif
#if EMUL_TIME_STATS
static clock_t emul_start_time;
static uint32 interrupt_count = 0, ppc_interrupt_count = 0;
static clock_t interrupt_time = 0;
static uint32 exec68k_count = 0;
static clock_t exec68k_time = 0;
static uint32 native_exec_count = 0;
static clock_t native_exec_time = 0;
static uint32 macos_exec_count = 0;
static clock_t macos_exec_time = 0;
#endif
static void enter_mon(void)
{
// Start up mon in real-mode
#if ENABLE_MON
2017-12-02 17:21:13 +00:00
const char *arg[4] = {"mon", "-m", "-r", NULL};
mon(3, arg);
#endif
}
// From main_*.cpp
extern uintptr SignalStackBase();
// From rsrc_patches.cpp
extern "C" void check_load_invoc(uint32 type, int16 id, uint32 h);
extern "C" void named_check_load_invoc(uint32 type, uint32 name, uint32 h);
// PowerPC EmulOp to exit from emulation looop
const uint32 POWERPC_EXEC_RETURN = POWERPC_EMUL_OP | 1;
// Enable Execute68k() safety checks?
#define SAFE_EXEC_68K 1
// Save FP state in Execute68k()?
#define SAVE_FP_EXEC_68K 1
// Interrupts in EMUL_OP mode?
#define INTERRUPTS_IN_EMUL_OP_MODE 1
// Interrupts in native mode?
#define INTERRUPTS_IN_NATIVE_MODE 1
// Pointer to Kernel Data
static KernelData * kernel_data;
// SIGSEGV handler
sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t);
#if PPC_ENABLE_JIT && PPC_REENTRANT_JIT
// Special trampolines for EmulOp and NativeOp
static uint8 *emul_op_trampoline;
static uint8 *native_op_trampoline;
#endif
/**
* PowerPC emulator glue with special 'sheep' opcodes
**/
enum {
PPC_I(SHEEP) = PPC_I(MAX),
PPC_I(SHEEP_MAX)
};
class sheepshaver_cpu
: public powerpc_cpu
{
void init_decoder();
void execute_sheep(uint32 opcode);
public:
// Constructor
sheepshaver_cpu();
// CR & XER accessors
uint32 get_cr() const { return cr().get(); }
void set_cr(uint32 v) { cr().set(v); }
uint32 get_xer() const { return xer().get(); }
void set_xer(uint32 v) { xer().set(v); }
// Execute NATIVE_OP routine
void execute_native_op(uint32 native_op);
// Execute EMUL_OP routine
void execute_emul_op(uint32 emul_op);
// Execute 68k routine
void execute_68k(uint32 entry, M68kRegisters *r);
// Execute ppc routine
void execute_ppc(uint32 entry);
// Execute MacOS/PPC code
uint32 execute_macos_code(uint32 tvect, int nargs, uint32 const *args);
#if PPC_ENABLE_JIT
// Compile one instruction
virtual int compile1(codegen_context_t & cg_context);
#endif
// Resource manager thunk
void get_resource(uint32 old_get_resource);
// Handle MacOS interrupt
void interrupt(uint32 entry);
// Make sure the SIGSEGV handler can access CPU registers
2007-12-30 09:18:40 +00:00
friend sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip);
};
sheepshaver_cpu::sheepshaver_cpu()
{
init_decoder();
#if PPC_ENABLE_JIT
if (PrefsFindBool("jit"))
enable_jit();
#endif
}
void sheepshaver_cpu::init_decoder()
{
static const instr_info_t sheep_ii_table[] = {
{ "sheep",
(execute_pmf)&sheepshaver_cpu::execute_sheep,
PPC_I(SHEEP),
D_form, 6, 0, CFLOW_JUMP | CFLOW_TRAP
}
};
const int ii_count = sizeof(sheep_ii_table)/sizeof(sheep_ii_table[0]);
D(bug("SheepShaver extra decode table has %d entries\n", ii_count));
for (int i = 0; i < ii_count; i++) {
const instr_info_t * ii = &sheep_ii_table[i];
init_decoder_entry(ii);
}
}
/* NativeOp instruction format:
+------------+-------------------------+--+-----------+------------+
| 6 | |FN| OP | 2 |
+------------+-------------------------+--+-----------+------------+
0 5 |6 18 19 20 25 26 31
*/
typedef bit_field< 19, 19 > FN_field;
typedef bit_field< 20, 25 > NATIVE_OP_field;
typedef bit_field< 26, 31 > EMUL_OP_field;
// Execute EMUL_OP routine
void sheepshaver_cpu::execute_emul_op(uint32 emul_op)
{
M68kRegisters r68;
WriteMacInt32(XLM_68K_R25, gpr(25));
WriteMacInt32(XLM_RUN_MODE, MODE_EMUL_OP);
for (int i = 0; i < 8; i++)
r68.d[i] = gpr(8 + i);
for (int i = 0; i < 7; i++)
r68.a[i] = gpr(16 + i);
r68.a[7] = gpr(1);
uint32 saved_cr = get_cr() & 0xff9fffff; // mask_operand::compute(11, 8)
uint32 saved_xer = get_xer();
EmulOp(&r68, gpr(24), emul_op);
set_cr(saved_cr);
set_xer(saved_xer);
for (int i = 0; i < 8; i++)
gpr(8 + i) = r68.d[i];
for (int i = 0; i < 7; i++)
gpr(16 + i) = r68.a[i];
gpr(1) = r68.a[7];
WriteMacInt32(XLM_RUN_MODE, MODE_68K);
}
// Execute SheepShaver instruction
void sheepshaver_cpu::execute_sheep(uint32 opcode)
{
// D(bug("Extended opcode %08x at %08x (68k pc %08x)\n", opcode, pc(), gpr(24)));
assert((((opcode >> 26) & 0x3f) == 6) && OP_MAX <= 64 + 3);
switch (opcode & 0x3f) {
case 0: // EMUL_RETURN
QuitEmulator();
break;
case 1: // EXEC_RETURN
spcflags().set(SPCFLAG_CPU_EXEC_RETURN);
break;
case 2: // EXEC_NATIVE
execute_native_op(NATIVE_OP_field::extract(opcode));
if (FN_field::test(opcode))
pc() = lr();
else
pc() += 4;
break;
default: // EMUL_OP
execute_emul_op(EMUL_OP_field::extract(opcode) - 3);
pc() += 4;
break;
}
}
// Compile one instruction
#if PPC_ENABLE_JIT
int sheepshaver_cpu::compile1(codegen_context_t & cg_context)
{
const instr_info_t *ii = cg_context.instr_info;
if (ii->mnemo != PPC_I(SHEEP))
return COMPILE_FAILURE;
int status = COMPILE_FAILURE;
powerpc_dyngen & dg = cg_context.codegen;
uint32 opcode = cg_context.opcode;
switch (opcode & 0x3f) {
case 0: // EMUL_RETURN
dg.gen_invoke(QuitEmulator);
status = COMPILE_CODE_OK;
break;
case 1: // EXEC_RETURN
dg.gen_spcflags_set(SPCFLAG_CPU_EXEC_RETURN);
// Don't check for pending interrupts, we do know we have to
// get out of this block ASAP
dg.gen_exec_return();
status = COMPILE_EPILOGUE_OK;
break;
case 2: { // EXEC_NATIVE
uint32 selector = NATIVE_OP_field::extract(opcode);
switch (selector) {
#if !PPC_REENTRANT_JIT
// Filter out functions that may invoke Execute68k() or
// CallMacOS(), this would break reentrancy as they could
// invalidate the translation cache and even overwrite
// continuation code when we are done with them.
case NATIVE_PATCH_NAME_REGISTRY:
dg.gen_invoke(DoPatchNameRegistry);
status = COMPILE_CODE_OK;
break;
case NATIVE_VIDEO_INSTALL_ACCEL:
dg.gen_invoke(VideoInstallAccel);
status = COMPILE_CODE_OK;
break;
case NATIVE_VIDEO_VBL:
dg.gen_invoke(VideoVBL);
status = COMPILE_CODE_OK;
break;
case NATIVE_GET_RESOURCE:
case NATIVE_GET_1_RESOURCE:
case NATIVE_GET_IND_RESOURCE:
case NATIVE_GET_1_IND_RESOURCE:
case NATIVE_R_GET_RESOURCE: {
static const uint32 get_resource_ptr[] = {
XLM_GET_RESOURCE,
XLM_GET_1_RESOURCE,
XLM_GET_IND_RESOURCE,
XLM_GET_1_IND_RESOURCE,
XLM_R_GET_RESOURCE
};
uint32 old_get_resource = ReadMacInt32(get_resource_ptr[selector - NATIVE_GET_RESOURCE]);
typedef void (*func_t)(dyngen_cpu_base, uint32);
func_t func = (func_t)nv_mem_fun(&sheepshaver_cpu::get_resource).ptr();
dg.gen_invoke_CPU_im(func, old_get_resource);
status = COMPILE_CODE_OK;
break;
}
#endif
case NATIVE_CHECK_LOAD_INVOC:
dg.gen_load_T0_GPR(3);
dg.gen_load_T1_GPR(4);
dg.gen_se_16_32_T1();
dg.gen_load_T2_GPR(5);
dg.gen_invoke_T0_T1_T2((void (*)(uint32, uint32, uint32))check_load_invoc);
status = COMPILE_CODE_OK;
break;
case NATIVE_NAMED_CHECK_LOAD_INVOC:
dg.gen_load_T0_GPR(3);
dg.gen_load_T1_GPR(4);
dg.gen_load_T2_GPR(5);
dg.gen_invoke_T0_T1_T2((void (*)(uint32, uint32, uint32))named_check_load_invoc);
status = COMPILE_CODE_OK;
break;
case NATIVE_NQD_SYNC_HOOK:
dg.gen_load_T0_GPR(3);
dg.gen_invoke_T0_ret_T0((uint32 (*)(uint32))NQD_sync_hook);
dg.gen_store_T0_GPR(3);
status = COMPILE_CODE_OK;
break;
case NATIVE_NQD_BITBLT_HOOK:
dg.gen_load_T0_GPR(3);
dg.gen_invoke_T0_ret_T0((uint32 (*)(uint32))NQD_bitblt_hook);
dg.gen_store_T0_GPR(3);
status = COMPILE_CODE_OK;
break;
case NATIVE_NQD_FILLRECT_HOOK:
dg.gen_load_T0_GPR(3);
dg.gen_invoke_T0_ret_T0((uint32 (*)(uint32))NQD_fillrect_hook);
dg.gen_store_T0_GPR(3);
status = COMPILE_CODE_OK;
break;
case NATIVE_NQD_UNKNOWN_HOOK:
dg.gen_load_T0_GPR(3);
dg.gen_invoke_T0_ret_T0((uint32 (*)(uint32))NQD_unknown_hook);
dg.gen_store_T0_GPR(3);
status = COMPILE_CODE_OK;
break;
case NATIVE_NQD_BITBLT:
dg.gen_load_T0_GPR(3);
dg.gen_invoke_T0((void (*)(uint32))NQD_bitblt);
status = COMPILE_CODE_OK;
break;
case NATIVE_NQD_INVRECT:
dg.gen_load_T0_GPR(3);
dg.gen_invoke_T0((void (*)(uint32))NQD_invrect);
status = COMPILE_CODE_OK;
break;
case NATIVE_NQD_FILLRECT:
dg.gen_load_T0_GPR(3);
dg.gen_invoke_T0((void (*)(uint32))NQD_fillrect);
status = COMPILE_CODE_OK;
break;
}
// Could we fully translate this NativeOp?
if (status == COMPILE_CODE_OK) {
if (!FN_field::test(opcode))
cg_context.done_compile = false;
else {
dg.gen_load_T0_LR_aligned();
dg.gen_set_PC_T0();
cg_context.done_compile = true;
}
break;
}
#if PPC_REENTRANT_JIT
// Try to execute NativeOp trampoline
if (!FN_field::test(opcode))
dg.gen_set_PC_im(cg_context.pc + 4);
else {
dg.gen_load_T0_LR_aligned();
dg.gen_set_PC_T0();
}
dg.gen_mov_32_T0_im(selector);
dg.gen_jmp(native_op_trampoline);
cg_context.done_compile = true;
status = COMPILE_EPILOGUE_OK;
break;
#else
// Invoke NativeOp handler
if (!FN_field::test(opcode)) {
typedef void (*func_t)(dyngen_cpu_base, uint32);
func_t func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_native_op).ptr();
dg.gen_invoke_CPU_im(func, selector);
cg_context.done_compile = false;
status = COMPILE_CODE_OK;
}
// Otherwise, let it generate a call to execute_sheep() which
// will cause necessary updates to the program counter
break;
#endif
}
default: { // EMUL_OP
uint32 emul_op = EMUL_OP_field::extract(opcode) - 3;
#if PPC_REENTRANT_JIT
// Try to execute EmulOp trampoline
dg.gen_set_PC_im(cg_context.pc + 4);
dg.gen_mov_32_T0_im(emul_op);
dg.gen_jmp(emul_op_trampoline);
cg_context.done_compile = true;
status = COMPILE_EPILOGUE_OK;
break;
#else
// Invoke EmulOp handler
typedef void (*func_t)(dyngen_cpu_base, uint32);
func_t func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_emul_op).ptr();
dg.gen_invoke_CPU_im(func, emul_op);
cg_context.done_compile = false;
status = COMPILE_CODE_OK;
break;
#endif
}
}
return status;
}
#endif
// Handle MacOS interrupt
void sheepshaver_cpu::interrupt(uint32 entry)
{
#if EMUL_TIME_STATS
ppc_interrupt_count++;
const clock_t interrupt_start = clock();
#endif
// Save program counters and branch registers
uint32 saved_pc = pc();
uint32 saved_lr = lr();
uint32 saved_ctr= ctr();
uint32 saved_sp = gpr(1);
// Initialize stack pointer to SheepShaver alternate stack base
gpr(1) = SignalStackBase() - 64;
// Build trampoline to return from interrupt
SheepVar32 trampoline = POWERPC_EXEC_RETURN;
// Prepare registers for nanokernel interrupt routine
kernel_data->v[0x004 >> 2] = htonl(gpr(1));
kernel_data->v[0x018 >> 2] = htonl(gpr(6));
gpr(6) = ntohl(kernel_data->v[0x65c >> 2]);
assert(gpr(6) != 0);
WriteMacInt32(gpr(6) + 0x13c, gpr(7));
WriteMacInt32(gpr(6) + 0x144, gpr(8));
WriteMacInt32(gpr(6) + 0x14c, gpr(9));
WriteMacInt32(gpr(6) + 0x154, gpr(10));
WriteMacInt32(gpr(6) + 0x15c, gpr(11));
WriteMacInt32(gpr(6) + 0x164, gpr(12));
WriteMacInt32(gpr(6) + 0x16c, gpr(13));
gpr(1) = KernelDataAddr;
gpr(7) = ntohl(kernel_data->v[0x660 >> 2]);
gpr(8) = 0;
gpr(10) = trampoline.addr();
gpr(12) = trampoline.addr();
gpr(13) = get_cr();
// rlwimi. r7,r7,8,0,0
uint32 result = op_ppc_rlwimi::apply(gpr(7), 8, 0x80000000, gpr(7));
record_cr0(result);
gpr(7) = result;
gpr(11) = 0xf072; // MSR (SRR1)
cr().set((gpr(11) & 0x0fff0000) | (get_cr() & ~0x0fff0000));
// Enter nanokernel
execute(entry);
// Restore program counters and branch registers
pc() = saved_pc;
lr() = saved_lr;
ctr()= saved_ctr;
gpr(1) = saved_sp;
#if EMUL_TIME_STATS
interrupt_time += (clock() - interrupt_start);
#endif
}
// Execute 68k routine
void sheepshaver_cpu::execute_68k(uint32 entry, M68kRegisters *r)
{
#if EMUL_TIME_STATS
exec68k_count++;
const clock_t exec68k_start = clock();
#endif
#if SAFE_EXEC_68K
if (ReadMacInt32(XLM_RUN_MODE) != MODE_EMUL_OP)
printf("FATAL: Execute68k() not called from EMUL_OP mode\n");
#endif
// Save program counters and branch registers
uint32 saved_pc = pc();
uint32 saved_lr = lr();
uint32 saved_ctr= ctr();
uint32 saved_cr = get_cr();
// Create MacOS stack frame
// FIXME: make sure MacOS doesn't expect PPC registers to live on top
uint32 sp = gpr(1);
gpr(1) -= 56;
WriteMacInt32(gpr(1), sp);
// Save PowerPC registers
uint32 saved_GPRs[19];
memcpy(&saved_GPRs[0], &gpr(13), sizeof(uint32)*(32-13));
#if SAVE_FP_EXEC_68K
double saved_FPRs[18];
memcpy(&saved_FPRs[0], &fpr(14), sizeof(double)*(32-14));
#endif
// Setup registers for 68k emulator
cr().set(CR_SO_field<2>::mask()); // Supervisor mode
for (int i = 0; i < 8; i++) // d[0]..d[7]
gpr(8 + i) = r->d[i];
for (int i = 0; i < 7; i++) // a[0]..a[6]
gpr(16 + i) = r->a[i];
gpr(23) = 0;
gpr(24) = entry;
gpr(25) = ReadMacInt32(XLM_68K_R25); // MSB of SR
gpr(26) = 0;
gpr(28) = 0; // VBR
gpr(29) = ntohl(kernel_data->ed.v[0x74 >> 2]); // Pointer to opcode table
gpr(30) = ntohl(kernel_data->ed.v[0x78 >> 2]); // Address of emulator
gpr(31) = KernelDataAddr + 0x1000;
// Push return address (points to EXEC_RETURN opcode) on stack
gpr(1) -= 4;
WriteMacInt32(gpr(1), XLM_EXEC_RETURN_OPCODE);
// Rentering 68k emulator
WriteMacInt32(XLM_RUN_MODE, MODE_68K);
// Set r0 to 0 for 68k emulator
gpr(0) = 0;
// Execute 68k opcode
uint32 opcode = ReadMacInt16(gpr(24));
gpr(27) = (int32)(int16)ReadMacInt16(gpr(24) += 2);
gpr(29) += opcode * 8;
execute(gpr(29));
// Save r25 (contains current 68k interrupt level)
WriteMacInt32(XLM_68K_R25, gpr(25));
// Reentering EMUL_OP mode
WriteMacInt32(XLM_RUN_MODE, MODE_EMUL_OP);
// Save 68k registers
for (int i = 0; i < 8; i++) // d[0]..d[7]
r->d[i] = gpr(8 + i);
for (int i = 0; i < 7; i++) // a[0]..a[6]
r->a[i] = gpr(16 + i);
// Restore PowerPC registers
memcpy(&gpr(13), &saved_GPRs[0], sizeof(uint32)*(32-13));
#if SAVE_FP_EXEC_68K
memcpy(&fpr(14), &saved_FPRs[0], sizeof(double)*(32-14));
#endif
// Cleanup stack
gpr(1) += 56;
// Restore program counters and branch registers
pc() = saved_pc;
lr() = saved_lr;
ctr()= saved_ctr;
set_cr(saved_cr);
#if EMUL_TIME_STATS
exec68k_time += (clock() - exec68k_start);
#endif
}
// Call MacOS PPC code
uint32 sheepshaver_cpu::execute_macos_code(uint32 tvect, int nargs, uint32 const *args)
{
#if EMUL_TIME_STATS
macos_exec_count++;
const clock_t macos_exec_start = clock();
#endif
// Save program counters and branch registers
uint32 saved_pc = pc();
uint32 saved_lr = lr();
uint32 saved_ctr= ctr();
// Build trampoline with EXEC_RETURN
SheepVar32 trampoline = POWERPC_EXEC_RETURN;
lr() = trampoline.addr();
gpr(1) -= 64; // Create stack frame
uint32 proc = ReadMacInt32(tvect); // Get routine address
uint32 toc = ReadMacInt32(tvect + 4); // Get TOC pointer
// Save PowerPC registers
uint32 regs[8];
regs[0] = gpr(2);
for (int i = 0; i < nargs; i++)
regs[i + 1] = gpr(i + 3);
// Prepare and call MacOS routine
gpr(2) = toc;
for (int i = 0; i < nargs; i++)
gpr(i + 3) = args[i];
execute(proc);
uint32 retval = gpr(3);
// Restore PowerPC registers
for (int i = 0; i <= nargs; i++)
gpr(i + 2) = regs[i];
// Cleanup stack
gpr(1) += 64;
// Restore program counters and branch registers
pc() = saved_pc;
lr() = saved_lr;
ctr()= saved_ctr;
#if EMUL_TIME_STATS
macos_exec_time += (clock() - macos_exec_start);
#endif
return retval;
}
// Execute ppc routine
inline void sheepshaver_cpu::execute_ppc(uint32 entry)
{
// Save branch registers
uint32 saved_lr = lr();
SheepVar32 trampoline = POWERPC_EXEC_RETURN;
WriteMacInt32(trampoline.addr(), POWERPC_EXEC_RETURN);
lr() = trampoline.addr();
execute(entry);
// Restore branch registers
lr() = saved_lr;
}
// Resource Manager thunk
inline void sheepshaver_cpu::get_resource(uint32 old_get_resource)
{
uint32 type = gpr(3);
int16 id = gpr(4);
// Create stack frame
gpr(1) -= 56;
// Call old routine
execute_ppc(old_get_resource);
// Call CheckLoad()
uint32 handle = gpr(3);
check_load_invoc(type, id, handle);
gpr(3) = handle;
// Cleanup stack
gpr(1) += 56;
}
/**
* SheepShaver CPU engine interface
**/
// PowerPC CPU emulator
static sheepshaver_cpu *ppc_cpu = NULL;
void FlushCodeCache(uintptr start, uintptr end)
{
D(bug("FlushCodeCache(%08x, %08x)\n", start, end));
ppc_cpu->invalidate_cache_range(start, end);
}
// Dump PPC registers
static void dump_registers(void)
{
ppc_cpu->dump_registers();
}
// Dump log
static void dump_log(void)
{
ppc_cpu->dump_log();
}
2012-06-16 02:16:40 +00:00
static int read_mem(bfd_vma memaddr, bfd_byte *myaddr, int length, struct disassemble_info *info)
{
Mac2Host_memcpy(myaddr, memaddr, length);
return 0;
}
static void dump_disassembly(const uint32 pc, const int prefix_count, const int suffix_count)
{
struct disassemble_info info;
INIT_DISASSEMBLE_INFO(info, stderr, fprintf);
info.read_memory_func = read_mem;
const int count = prefix_count + suffix_count + 1;
const uint32 base_addr = pc - prefix_count * 4;
for (int i = 0; i < count; i++) {
const bfd_vma addr = base_addr + i * 4;
fprintf(stderr, "%s0x%8llx: ", addr == pc ? " >" : " ", addr);
print_insn_ppc(addr, &info);
fprintf(stderr, "\n");
}
}
2007-12-30 09:18:40 +00:00
sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip)
{
#if ENABLE_VOSF
// Handle screen fault
2007-12-30 09:18:40 +00:00
extern bool Screen_fault_handler(sigsegv_info_t *sip);
if (Screen_fault_handler(sip))
return SIGSEGV_RETURN_SUCCESS;
#endif
2007-12-30 09:18:40 +00:00
const uintptr addr = (uintptr)sigsegv_get_fault_address(sip);
#if HAVE_SIGSEGV_SKIP_INSTRUCTION
// Ignore writes to ROM
if ((addr - (uintptr)ROMBaseHost) < ROM_SIZE)
return SIGSEGV_RETURN_SKIP_INSTRUCTION;
// Get program counter of target CPU
sheepshaver_cpu * const cpu = ppc_cpu;
const uint32 pc = cpu->pc();
// Fault in Mac ROM or RAM?
2016-12-18 03:04:57 +00:00
bool mac_fault = (pc >= ROMBase && pc < (ROMBase + ROM_AREA_SIZE)) || (pc >= RAMBase && pc < (RAMBase + RAMSize)) || (pc >= DR_CACHE_BASE && pc < (DR_CACHE_BASE + DR_CACHE_SIZE));
if (mac_fault) {
// "VM settings" during MacOS 8 installation
[Michael Schmitt] Attached is a patch to SheepShaver to fix memory allocation problems when OS X 10.5 is the host. It also relaxes the 512 MB RAM limit on OS X hosts. Problem ------- Some users have been unable to run SheepShaver on OS X 10.5 (Leopard) hosts. The symptom is error "ERROR: Cannot map RAM: File already exists". SheepShaver allocates RAM at fixed addresses. If it is running in "Real" addressing mode, and can't allocate at address 0, then it was hard-coded to allocate the RAM area at 0x20000000. The ROM area as allocated at 0x40800000. The normal configuration is for SheepShaver to run under SDL, which is a Cocoa wrapper. By the time SheepShaver does its memory allocations, the Cocoa application has already started. The result is the SheepShaver memory address space already contains libraries, fonts, Input Managers, and IOKit areas. On Leopard hosts these areas can land on the same addresses SheepShaver needs, so SheepShaver's memory allocation fails. Solution -------- The approach is to change SheepShaver (on Unix & OS X hosts) to allocate the RAM area anywhere it can find the space, rather than at a fixed address. This could result in the RAM allocated higher than the ROM area, which causes a crash. To prevent this from occurring, the RAM and ROM areas are allocated contiguously. Previously the ROM starting address was a constant ROM_BASE, which was used throughout the source files. The ROM start address is now a variable ROMBase. ROMBase is allocated and set by main_*.cpp just like RAMBase. A side-effect of this change is that it lifts the 512 MB RAM limit for OS X hosts. The limit was because the fixed RAM and ROM addresses were such that the RAM could only be 512 MB before it overlapped the ROM area. Impact ------ The change to make ROMBase a variable is throughout all hosts & addressing modes. The RAM and ROM areas will only shift when run on Unix & OS X hosts, otherwise the same fixed allocation address is used as before. This change is limited to "Real" addressing mode. Unlike Basilisk II, SheepShaver *pre-calculates* the offset for "Direct" addressing mode; the offset is compiled into the program. If the RAM address were allowed to shift, it could result in the RAM area wrapping around address 0. Changes to main_unix.cpp ------------------------ 1. Real addressing mode no longer defines a RAM_BASE constant. 2. The base address of the Mac ROM (ROMBase) is defined and exported by this program. 3. Memory management helper vm_mac_acquire is renamed to vm_mac_acquire_fixed. Added a new memory management helper vm_mac_acquire, which allocates memory at any address. 4. Changed and rearranged the allocation of RAM and ROM areas. Before it worked like this: - Allocate ROM area - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0, allocate at fixed address We still want to try allocating the RAM at zero, and if using DIRECT addressing we're still going to use the fixed addresses. So we don't know where the ROM should be until after we do the RAM. The new logic is: - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0 if REAL addressing allocate RAM and ROM together. The ROM address is aligned to a 1 MB boundary else (direct addressing) allocate RAM at fixed address - If ROM hasn't been allocated yet, allocate at fixed address 5. Calculate ROMBase and ROMBaseHost based on where the ROM was loaded. 6. There is a crash if the RAM is allocated too high. To try and catch this, check if it was allocated higher than the kernel data address. 7. Change subsequent code from using constant ROM_BASE to variable ROMBase. Changes to Other Programs ------------------------- emul_op.cpp, main.cpp, name_registery.cpp, rom_patches.cpp, rsrc_patches.cpp, emul_ppc.cpp, sheepshaver_glue.cpp, ppc-translate-cpp: Change from constant ROM_BASE to variable ROMBase. ppc_asm.S: It was setting register to a hard-coded literal address: 0x40b0d000. Changed to set it to ROMBase + 0x30d000. ppc_asm.tmpl: It defined a macro ASM_LO16 but it assumed that the macro would always be used with operands that included a register specification. This is not true. Moved the register specification from the macro to the macro invocations. main_beos.cpp, main_windows.cpp: Since the subprograms are all expecting a variable ROMBase, all the main_*.cpp pgrams have to define and export it. The ROM_BASE constant is moved here for consistency. The mains for beos and windows just allocate the ROM at the same fixed address as before, set ROMBaseHost and ROMBase to that address, and then use ROMBase for the subsequent code. cpu_emulation.h: removed ROM_BASE constant. This value is moved to the main_*.cpp modules, to be consistent with RAM_BASE. user_strings_unix.cpp, user_strings_unix.h: Added new error messages related to errors that occur when the RAM and ROM are allocated anywhere.
2009-08-18 18:26:11 +00:00
if (pc == ROMBase + 0x488160 && cpu->gpr(20) == 0xf8000000)
return SIGSEGV_RETURN_SKIP_INSTRUCTION;
// MacOS 8.5 installation
[Michael Schmitt] Attached is a patch to SheepShaver to fix memory allocation problems when OS X 10.5 is the host. It also relaxes the 512 MB RAM limit on OS X hosts. Problem ------- Some users have been unable to run SheepShaver on OS X 10.5 (Leopard) hosts. The symptom is error "ERROR: Cannot map RAM: File already exists". SheepShaver allocates RAM at fixed addresses. If it is running in "Real" addressing mode, and can't allocate at address 0, then it was hard-coded to allocate the RAM area at 0x20000000. The ROM area as allocated at 0x40800000. The normal configuration is for SheepShaver to run under SDL, which is a Cocoa wrapper. By the time SheepShaver does its memory allocations, the Cocoa application has already started. The result is the SheepShaver memory address space already contains libraries, fonts, Input Managers, and IOKit areas. On Leopard hosts these areas can land on the same addresses SheepShaver needs, so SheepShaver's memory allocation fails. Solution -------- The approach is to change SheepShaver (on Unix & OS X hosts) to allocate the RAM area anywhere it can find the space, rather than at a fixed address. This could result in the RAM allocated higher than the ROM area, which causes a crash. To prevent this from occurring, the RAM and ROM areas are allocated contiguously. Previously the ROM starting address was a constant ROM_BASE, which was used throughout the source files. The ROM start address is now a variable ROMBase. ROMBase is allocated and set by main_*.cpp just like RAMBase. A side-effect of this change is that it lifts the 512 MB RAM limit for OS X hosts. The limit was because the fixed RAM and ROM addresses were such that the RAM could only be 512 MB before it overlapped the ROM area. Impact ------ The change to make ROMBase a variable is throughout all hosts & addressing modes. The RAM and ROM areas will only shift when run on Unix & OS X hosts, otherwise the same fixed allocation address is used as before. This change is limited to "Real" addressing mode. Unlike Basilisk II, SheepShaver *pre-calculates* the offset for "Direct" addressing mode; the offset is compiled into the program. If the RAM address were allowed to shift, it could result in the RAM area wrapping around address 0. Changes to main_unix.cpp ------------------------ 1. Real addressing mode no longer defines a RAM_BASE constant. 2. The base address of the Mac ROM (ROMBase) is defined and exported by this program. 3. Memory management helper vm_mac_acquire is renamed to vm_mac_acquire_fixed. Added a new memory management helper vm_mac_acquire, which allocates memory at any address. 4. Changed and rearranged the allocation of RAM and ROM areas. Before it worked like this: - Allocate ROM area - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0, allocate at fixed address We still want to try allocating the RAM at zero, and if using DIRECT addressing we're still going to use the fixed addresses. So we don't know where the ROM should be until after we do the RAM. The new logic is: - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0 if REAL addressing allocate RAM and ROM together. The ROM address is aligned to a 1 MB boundary else (direct addressing) allocate RAM at fixed address - If ROM hasn't been allocated yet, allocate at fixed address 5. Calculate ROMBase and ROMBaseHost based on where the ROM was loaded. 6. There is a crash if the RAM is allocated too high. To try and catch this, check if it was allocated higher than the kernel data address. 7. Change subsequent code from using constant ROM_BASE to variable ROMBase. Changes to Other Programs ------------------------- emul_op.cpp, main.cpp, name_registery.cpp, rom_patches.cpp, rsrc_patches.cpp, emul_ppc.cpp, sheepshaver_glue.cpp, ppc-translate-cpp: Change from constant ROM_BASE to variable ROMBase. ppc_asm.S: It was setting register to a hard-coded literal address: 0x40b0d000. Changed to set it to ROMBase + 0x30d000. ppc_asm.tmpl: It defined a macro ASM_LO16 but it assumed that the macro would always be used with operands that included a register specification. This is not true. Moved the register specification from the macro to the macro invocations. main_beos.cpp, main_windows.cpp: Since the subprograms are all expecting a variable ROMBase, all the main_*.cpp pgrams have to define and export it. The ROM_BASE constant is moved here for consistency. The mains for beos and windows just allocate the ROM at the same fixed address as before, set ROMBaseHost and ROMBase to that address, and then use ROMBase for the subsequent code. cpu_emulation.h: removed ROM_BASE constant. This value is moved to the main_*.cpp modules, to be consistent with RAM_BASE. user_strings_unix.cpp, user_strings_unix.h: Added new error messages related to errors that occur when the RAM and ROM are allocated anywhere.
2009-08-18 18:26:11 +00:00
else if (pc == ROMBase + 0x488140 && cpu->gpr(16) == 0xf8000000)
return SIGSEGV_RETURN_SKIP_INSTRUCTION;
// MacOS 8 serial drivers on startup
[Michael Schmitt] Attached is a patch to SheepShaver to fix memory allocation problems when OS X 10.5 is the host. It also relaxes the 512 MB RAM limit on OS X hosts. Problem ------- Some users have been unable to run SheepShaver on OS X 10.5 (Leopard) hosts. The symptom is error "ERROR: Cannot map RAM: File already exists". SheepShaver allocates RAM at fixed addresses. If it is running in "Real" addressing mode, and can't allocate at address 0, then it was hard-coded to allocate the RAM area at 0x20000000. The ROM area as allocated at 0x40800000. The normal configuration is for SheepShaver to run under SDL, which is a Cocoa wrapper. By the time SheepShaver does its memory allocations, the Cocoa application has already started. The result is the SheepShaver memory address space already contains libraries, fonts, Input Managers, and IOKit areas. On Leopard hosts these areas can land on the same addresses SheepShaver needs, so SheepShaver's memory allocation fails. Solution -------- The approach is to change SheepShaver (on Unix & OS X hosts) to allocate the RAM area anywhere it can find the space, rather than at a fixed address. This could result in the RAM allocated higher than the ROM area, which causes a crash. To prevent this from occurring, the RAM and ROM areas are allocated contiguously. Previously the ROM starting address was a constant ROM_BASE, which was used throughout the source files. The ROM start address is now a variable ROMBase. ROMBase is allocated and set by main_*.cpp just like RAMBase. A side-effect of this change is that it lifts the 512 MB RAM limit for OS X hosts. The limit was because the fixed RAM and ROM addresses were such that the RAM could only be 512 MB before it overlapped the ROM area. Impact ------ The change to make ROMBase a variable is throughout all hosts & addressing modes. The RAM and ROM areas will only shift when run on Unix & OS X hosts, otherwise the same fixed allocation address is used as before. This change is limited to "Real" addressing mode. Unlike Basilisk II, SheepShaver *pre-calculates* the offset for "Direct" addressing mode; the offset is compiled into the program. If the RAM address were allowed to shift, it could result in the RAM area wrapping around address 0. Changes to main_unix.cpp ------------------------ 1. Real addressing mode no longer defines a RAM_BASE constant. 2. The base address of the Mac ROM (ROMBase) is defined and exported by this program. 3. Memory management helper vm_mac_acquire is renamed to vm_mac_acquire_fixed. Added a new memory management helper vm_mac_acquire, which allocates memory at any address. 4. Changed and rearranged the allocation of RAM and ROM areas. Before it worked like this: - Allocate ROM area - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0, allocate at fixed address We still want to try allocating the RAM at zero, and if using DIRECT addressing we're still going to use the fixed addresses. So we don't know where the ROM should be until after we do the RAM. The new logic is: - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0 if REAL addressing allocate RAM and ROM together. The ROM address is aligned to a 1 MB boundary else (direct addressing) allocate RAM at fixed address - If ROM hasn't been allocated yet, allocate at fixed address 5. Calculate ROMBase and ROMBaseHost based on where the ROM was loaded. 6. There is a crash if the RAM is allocated too high. To try and catch this, check if it was allocated higher than the kernel data address. 7. Change subsequent code from using constant ROM_BASE to variable ROMBase. Changes to Other Programs ------------------------- emul_op.cpp, main.cpp, name_registery.cpp, rom_patches.cpp, rsrc_patches.cpp, emul_ppc.cpp, sheepshaver_glue.cpp, ppc-translate-cpp: Change from constant ROM_BASE to variable ROMBase. ppc_asm.S: It was setting register to a hard-coded literal address: 0x40b0d000. Changed to set it to ROMBase + 0x30d000. ppc_asm.tmpl: It defined a macro ASM_LO16 but it assumed that the macro would always be used with operands that included a register specification. This is not true. Moved the register specification from the macro to the macro invocations. main_beos.cpp, main_windows.cpp: Since the subprograms are all expecting a variable ROMBase, all the main_*.cpp pgrams have to define and export it. The ROM_BASE constant is moved here for consistency. The mains for beos and windows just allocate the ROM at the same fixed address as before, set ROMBaseHost and ROMBase to that address, and then use ROMBase for the subsequent code. cpu_emulation.h: removed ROM_BASE constant. This value is moved to the main_*.cpp modules, to be consistent with RAM_BASE. user_strings_unix.cpp, user_strings_unix.h: Added new error messages related to errors that occur when the RAM and ROM are allocated anywhere.
2009-08-18 18:26:11 +00:00
else if (pc == ROMBase + 0x48e080 && (cpu->gpr(8) == 0xf3012002 || cpu->gpr(8) == 0xf3012000))
return SIGSEGV_RETURN_SKIP_INSTRUCTION;
// MacOS 8.1 serial drivers on startup
[Michael Schmitt] Attached is a patch to SheepShaver to fix memory allocation problems when OS X 10.5 is the host. It also relaxes the 512 MB RAM limit on OS X hosts. Problem ------- Some users have been unable to run SheepShaver on OS X 10.5 (Leopard) hosts. The symptom is error "ERROR: Cannot map RAM: File already exists". SheepShaver allocates RAM at fixed addresses. If it is running in "Real" addressing mode, and can't allocate at address 0, then it was hard-coded to allocate the RAM area at 0x20000000. The ROM area as allocated at 0x40800000. The normal configuration is for SheepShaver to run under SDL, which is a Cocoa wrapper. By the time SheepShaver does its memory allocations, the Cocoa application has already started. The result is the SheepShaver memory address space already contains libraries, fonts, Input Managers, and IOKit areas. On Leopard hosts these areas can land on the same addresses SheepShaver needs, so SheepShaver's memory allocation fails. Solution -------- The approach is to change SheepShaver (on Unix & OS X hosts) to allocate the RAM area anywhere it can find the space, rather than at a fixed address. This could result in the RAM allocated higher than the ROM area, which causes a crash. To prevent this from occurring, the RAM and ROM areas are allocated contiguously. Previously the ROM starting address was a constant ROM_BASE, which was used throughout the source files. The ROM start address is now a variable ROMBase. ROMBase is allocated and set by main_*.cpp just like RAMBase. A side-effect of this change is that it lifts the 512 MB RAM limit for OS X hosts. The limit was because the fixed RAM and ROM addresses were such that the RAM could only be 512 MB before it overlapped the ROM area. Impact ------ The change to make ROMBase a variable is throughout all hosts & addressing modes. The RAM and ROM areas will only shift when run on Unix & OS X hosts, otherwise the same fixed allocation address is used as before. This change is limited to "Real" addressing mode. Unlike Basilisk II, SheepShaver *pre-calculates* the offset for "Direct" addressing mode; the offset is compiled into the program. If the RAM address were allowed to shift, it could result in the RAM area wrapping around address 0. Changes to main_unix.cpp ------------------------ 1. Real addressing mode no longer defines a RAM_BASE constant. 2. The base address of the Mac ROM (ROMBase) is defined and exported by this program. 3. Memory management helper vm_mac_acquire is renamed to vm_mac_acquire_fixed. Added a new memory management helper vm_mac_acquire, which allocates memory at any address. 4. Changed and rearranged the allocation of RAM and ROM areas. Before it worked like this: - Allocate ROM area - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0, allocate at fixed address We still want to try allocating the RAM at zero, and if using DIRECT addressing we're still going to use the fixed addresses. So we don't know where the ROM should be until after we do the RAM. The new logic is: - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0 if REAL addressing allocate RAM and ROM together. The ROM address is aligned to a 1 MB boundary else (direct addressing) allocate RAM at fixed address - If ROM hasn't been allocated yet, allocate at fixed address 5. Calculate ROMBase and ROMBaseHost based on where the ROM was loaded. 6. There is a crash if the RAM is allocated too high. To try and catch this, check if it was allocated higher than the kernel data address. 7. Change subsequent code from using constant ROM_BASE to variable ROMBase. Changes to Other Programs ------------------------- emul_op.cpp, main.cpp, name_registery.cpp, rom_patches.cpp, rsrc_patches.cpp, emul_ppc.cpp, sheepshaver_glue.cpp, ppc-translate-cpp: Change from constant ROM_BASE to variable ROMBase. ppc_asm.S: It was setting register to a hard-coded literal address: 0x40b0d000. Changed to set it to ROMBase + 0x30d000. ppc_asm.tmpl: It defined a macro ASM_LO16 but it assumed that the macro would always be used with operands that included a register specification. This is not true. Moved the register specification from the macro to the macro invocations. main_beos.cpp, main_windows.cpp: Since the subprograms are all expecting a variable ROMBase, all the main_*.cpp pgrams have to define and export it. The ROM_BASE constant is moved here for consistency. The mains for beos and windows just allocate the ROM at the same fixed address as before, set ROMBaseHost and ROMBase to that address, and then use ROMBase for the subsequent code. cpu_emulation.h: removed ROM_BASE constant. This value is moved to the main_*.cpp modules, to be consistent with RAM_BASE. user_strings_unix.cpp, user_strings_unix.h: Added new error messages related to errors that occur when the RAM and ROM are allocated anywhere.
2009-08-18 18:26:11 +00:00
else if (pc == ROMBase + 0x48c5e0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000))
return SIGSEGV_RETURN_SKIP_INSTRUCTION;
[Michael Schmitt] Attached is a patch to SheepShaver to fix memory allocation problems when OS X 10.5 is the host. It also relaxes the 512 MB RAM limit on OS X hosts. Problem ------- Some users have been unable to run SheepShaver on OS X 10.5 (Leopard) hosts. The symptom is error "ERROR: Cannot map RAM: File already exists". SheepShaver allocates RAM at fixed addresses. If it is running in "Real" addressing mode, and can't allocate at address 0, then it was hard-coded to allocate the RAM area at 0x20000000. The ROM area as allocated at 0x40800000. The normal configuration is for SheepShaver to run under SDL, which is a Cocoa wrapper. By the time SheepShaver does its memory allocations, the Cocoa application has already started. The result is the SheepShaver memory address space already contains libraries, fonts, Input Managers, and IOKit areas. On Leopard hosts these areas can land on the same addresses SheepShaver needs, so SheepShaver's memory allocation fails. Solution -------- The approach is to change SheepShaver (on Unix & OS X hosts) to allocate the RAM area anywhere it can find the space, rather than at a fixed address. This could result in the RAM allocated higher than the ROM area, which causes a crash. To prevent this from occurring, the RAM and ROM areas are allocated contiguously. Previously the ROM starting address was a constant ROM_BASE, which was used throughout the source files. The ROM start address is now a variable ROMBase. ROMBase is allocated and set by main_*.cpp just like RAMBase. A side-effect of this change is that it lifts the 512 MB RAM limit for OS X hosts. The limit was because the fixed RAM and ROM addresses were such that the RAM could only be 512 MB before it overlapped the ROM area. Impact ------ The change to make ROMBase a variable is throughout all hosts & addressing modes. The RAM and ROM areas will only shift when run on Unix & OS X hosts, otherwise the same fixed allocation address is used as before. This change is limited to "Real" addressing mode. Unlike Basilisk II, SheepShaver *pre-calculates* the offset for "Direct" addressing mode; the offset is compiled into the program. If the RAM address were allowed to shift, it could result in the RAM area wrapping around address 0. Changes to main_unix.cpp ------------------------ 1. Real addressing mode no longer defines a RAM_BASE constant. 2. The base address of the Mac ROM (ROMBase) is defined and exported by this program. 3. Memory management helper vm_mac_acquire is renamed to vm_mac_acquire_fixed. Added a new memory management helper vm_mac_acquire, which allocates memory at any address. 4. Changed and rearranged the allocation of RAM and ROM areas. Before it worked like this: - Allocate ROM area - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0, allocate at fixed address We still want to try allocating the RAM at zero, and if using DIRECT addressing we're still going to use the fixed addresses. So we don't know where the ROM should be until after we do the RAM. The new logic is: - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0 if REAL addressing allocate RAM and ROM together. The ROM address is aligned to a 1 MB boundary else (direct addressing) allocate RAM at fixed address - If ROM hasn't been allocated yet, allocate at fixed address 5. Calculate ROMBase and ROMBaseHost based on where the ROM was loaded. 6. There is a crash if the RAM is allocated too high. To try and catch this, check if it was allocated higher than the kernel data address. 7. Change subsequent code from using constant ROM_BASE to variable ROMBase. Changes to Other Programs ------------------------- emul_op.cpp, main.cpp, name_registery.cpp, rom_patches.cpp, rsrc_patches.cpp, emul_ppc.cpp, sheepshaver_glue.cpp, ppc-translate-cpp: Change from constant ROM_BASE to variable ROMBase. ppc_asm.S: It was setting register to a hard-coded literal address: 0x40b0d000. Changed to set it to ROMBase + 0x30d000. ppc_asm.tmpl: It defined a macro ASM_LO16 but it assumed that the macro would always be used with operands that included a register specification. This is not true. Moved the register specification from the macro to the macro invocations. main_beos.cpp, main_windows.cpp: Since the subprograms are all expecting a variable ROMBase, all the main_*.cpp pgrams have to define and export it. The ROM_BASE constant is moved here for consistency. The mains for beos and windows just allocate the ROM at the same fixed address as before, set ROMBaseHost and ROMBase to that address, and then use ROMBase for the subsequent code. cpu_emulation.h: removed ROM_BASE constant. This value is moved to the main_*.cpp modules, to be consistent with RAM_BASE. user_strings_unix.cpp, user_strings_unix.h: Added new error messages related to errors that occur when the RAM and ROM are allocated anywhere.
2009-08-18 18:26:11 +00:00
else if (pc == ROMBase + 0x4a10a0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000))
return SIGSEGV_RETURN_SKIP_INSTRUCTION;
// MacOS 8.6 serial drivers on startup (with DR Cache and OldWorld ROM)
else if ((pc - DR_CACHE_BASE) < DR_CACHE_SIZE && (cpu->gpr(16) == 0xf3012002 || cpu->gpr(16) == 0xf3012000))
return SIGSEGV_RETURN_SKIP_INSTRUCTION;
else if ((pc - DR_CACHE_BASE) < DR_CACHE_SIZE && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000))
return SIGSEGV_RETURN_SKIP_INSTRUCTION;
// Ignore writes to the zero page
else if ((uint32)(addr - SheepMem::ZeroPage()) < (uint32)SheepMem::PageSize())
return SIGSEGV_RETURN_SKIP_INSTRUCTION;
// Ignore all other faults, if requested
if (PrefsFindBool("ignoresegv"))
return SIGSEGV_RETURN_SKIP_INSTRUCTION;
}
#else
#error "FIXME: You don't have the capability to skip instruction within signal handlers"
#endif
fprintf(stderr, "SIGSEGV\n");
2007-12-30 09:18:40 +00:00
fprintf(stderr, " pc %p\n", sigsegv_get_fault_instruction_address(sip));
fprintf(stderr, " ea %p\n", sigsegv_get_fault_address(sip));
dump_registers();
dump_log();
2012-06-16 02:16:40 +00:00
dump_disassembly(pc, 8, 8);
enter_mon();
QuitEmulator();
return SIGSEGV_RETURN_FAILURE;
}
2012-06-16 02:16:40 +00:00
/*
* Initialize CPU emulation
*/
void init_emul_ppc(void)
{
// Get pointer to KernelData in host address space
kernel_data = (KernelData *)Mac2HostAddr(KERNEL_DATA_BASE);
// Initialize main CPU emulator
ppc_cpu = new sheepshaver_cpu();
[Michael Schmitt] Attached is a patch to SheepShaver to fix memory allocation problems when OS X 10.5 is the host. It also relaxes the 512 MB RAM limit on OS X hosts. Problem ------- Some users have been unable to run SheepShaver on OS X 10.5 (Leopard) hosts. The symptom is error "ERROR: Cannot map RAM: File already exists". SheepShaver allocates RAM at fixed addresses. If it is running in "Real" addressing mode, and can't allocate at address 0, then it was hard-coded to allocate the RAM area at 0x20000000. The ROM area as allocated at 0x40800000. The normal configuration is for SheepShaver to run under SDL, which is a Cocoa wrapper. By the time SheepShaver does its memory allocations, the Cocoa application has already started. The result is the SheepShaver memory address space already contains libraries, fonts, Input Managers, and IOKit areas. On Leopard hosts these areas can land on the same addresses SheepShaver needs, so SheepShaver's memory allocation fails. Solution -------- The approach is to change SheepShaver (on Unix & OS X hosts) to allocate the RAM area anywhere it can find the space, rather than at a fixed address. This could result in the RAM allocated higher than the ROM area, which causes a crash. To prevent this from occurring, the RAM and ROM areas are allocated contiguously. Previously the ROM starting address was a constant ROM_BASE, which was used throughout the source files. The ROM start address is now a variable ROMBase. ROMBase is allocated and set by main_*.cpp just like RAMBase. A side-effect of this change is that it lifts the 512 MB RAM limit for OS X hosts. The limit was because the fixed RAM and ROM addresses were such that the RAM could only be 512 MB before it overlapped the ROM area. Impact ------ The change to make ROMBase a variable is throughout all hosts & addressing modes. The RAM and ROM areas will only shift when run on Unix & OS X hosts, otherwise the same fixed allocation address is used as before. This change is limited to "Real" addressing mode. Unlike Basilisk II, SheepShaver *pre-calculates* the offset for "Direct" addressing mode; the offset is compiled into the program. If the RAM address were allowed to shift, it could result in the RAM area wrapping around address 0. Changes to main_unix.cpp ------------------------ 1. Real addressing mode no longer defines a RAM_BASE constant. 2. The base address of the Mac ROM (ROMBase) is defined and exported by this program. 3. Memory management helper vm_mac_acquire is renamed to vm_mac_acquire_fixed. Added a new memory management helper vm_mac_acquire, which allocates memory at any address. 4. Changed and rearranged the allocation of RAM and ROM areas. Before it worked like this: - Allocate ROM area - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0, allocate at fixed address We still want to try allocating the RAM at zero, and if using DIRECT addressing we're still going to use the fixed addresses. So we don't know where the ROM should be until after we do the RAM. The new logic is: - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0 if REAL addressing allocate RAM and ROM together. The ROM address is aligned to a 1 MB boundary else (direct addressing) allocate RAM at fixed address - If ROM hasn't been allocated yet, allocate at fixed address 5. Calculate ROMBase and ROMBaseHost based on where the ROM was loaded. 6. There is a crash if the RAM is allocated too high. To try and catch this, check if it was allocated higher than the kernel data address. 7. Change subsequent code from using constant ROM_BASE to variable ROMBase. Changes to Other Programs ------------------------- emul_op.cpp, main.cpp, name_registery.cpp, rom_patches.cpp, rsrc_patches.cpp, emul_ppc.cpp, sheepshaver_glue.cpp, ppc-translate-cpp: Change from constant ROM_BASE to variable ROMBase. ppc_asm.S: It was setting register to a hard-coded literal address: 0x40b0d000. Changed to set it to ROMBase + 0x30d000. ppc_asm.tmpl: It defined a macro ASM_LO16 but it assumed that the macro would always be used with operands that included a register specification. This is not true. Moved the register specification from the macro to the macro invocations. main_beos.cpp, main_windows.cpp: Since the subprograms are all expecting a variable ROMBase, all the main_*.cpp pgrams have to define and export it. The ROM_BASE constant is moved here for consistency. The mains for beos and windows just allocate the ROM at the same fixed address as before, set ROMBaseHost and ROMBase to that address, and then use ROMBase for the subsequent code. cpu_emulation.h: removed ROM_BASE constant. This value is moved to the main_*.cpp modules, to be consistent with RAM_BASE. user_strings_unix.cpp, user_strings_unix.h: Added new error messages related to errors that occur when the RAM and ROM are allocated anywhere.
2009-08-18 18:26:11 +00:00
ppc_cpu->set_register(powerpc_registers::GPR(3), any_register((uint32)ROMBase + 0x30d000));
ppc_cpu->set_register(powerpc_registers::GPR(4), any_register(KernelDataAddr + 0x1000));
WriteMacInt32(XLM_RUN_MODE, MODE_68K);
#if ENABLE_MON
// Install "regs" command in cxmon
mon_add_command("regs", dump_registers, "regs Dump PowerPC registers\n");
mon_add_command("log", dump_log, "log Dump PowerPC emulation log\n");
#endif
#if EMUL_TIME_STATS
emul_start_time = clock();
#endif
}
/*
* Deinitialize emulation
*/
void exit_emul_ppc(void)
{
#if EMUL_TIME_STATS
clock_t emul_end_time = clock();
printf("### Statistics for SheepShaver emulation parts\n");
const clock_t emul_time = emul_end_time - emul_start_time;
printf("Total emulation time : %.1f sec\n", double(emul_time) / double(CLOCKS_PER_SEC));
printf("Total interrupt count: %d (%2.1f Hz)\n", interrupt_count,
(double(interrupt_count) * CLOCKS_PER_SEC) / double(emul_time));
printf("Total ppc interrupt count: %d (%2.1f %%)\n", ppc_interrupt_count,
(double(ppc_interrupt_count) * 100.0) / double(interrupt_count));
#define PRINT_STATS(LABEL, VAR_PREFIX) do { \
printf("Total " LABEL " count : %d\n", VAR_PREFIX##_count); \
printf("Total " LABEL " time : %.1f sec (%.1f%%)\n", \
double(VAR_PREFIX##_time) / double(CLOCKS_PER_SEC), \
100.0 * double(VAR_PREFIX##_time) / double(emul_time)); \
} while (0)
PRINT_STATS("Execute68k[Trap] execution", exec68k);
PRINT_STATS("NativeOp execution", native_exec);
PRINT_STATS("MacOS routine execution", macos_exec);
#undef PRINT_STATS
printf("\n");
#endif
delete ppc_cpu;
ppc_cpu = NULL;
}
#if PPC_ENABLE_JIT && PPC_REENTRANT_JIT
// Initialize EmulOp trampolines
void init_emul_op_trampolines(basic_dyngen & dg)
{
typedef void (*func_t)(dyngen_cpu_base, uint32);
func_t func;
// EmulOp
emul_op_trampoline = dg.gen_start();
func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_emul_op).ptr();
dg.gen_invoke_CPU_T0(func);
dg.gen_exec_return();
dg.gen_end();
// NativeOp
native_op_trampoline = dg.gen_start();
func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_native_op).ptr();
dg.gen_invoke_CPU_T0(func);
dg.gen_exec_return();
dg.gen_end();
D(bug("EmulOp trampoline: %p\n", emul_op_trampoline));
D(bug("NativeOp trampoline: %p\n", native_op_trampoline));
}
#endif
/*
* Emulation loop
*/
void emul_ppc(uint32 entry)
{
#if 0
ppc_cpu->start_log();
#endif
// start emulation loop and enable code translation or caching
ppc_cpu->execute(entry);
}
/*
* Handle PowerPC interrupt
*/
void TriggerInterrupt(void)
{
idle_resume();
#if 0
WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
#else
// Trigger interrupt to main cpu only
if (ppc_cpu)
ppc_cpu->trigger_interrupt();
#endif
}
void HandleInterrupt(powerpc_registers *r)
{
#ifdef USE_SDL_VIDEO
// We must fill in the events queue in the same thread that did call SDL_SetVideoMode()
SDL_PumpEvents();
#endif
// Do nothing if interrupts are disabled
if (int32(ReadMacInt32(XLM_IRQ_NEST)) > 0)
return;
// Update interrupt count
#if EMUL_TIME_STATS
interrupt_count++;
#endif
// Interrupt action depends on current run mode
switch (ReadMacInt32(XLM_RUN_MODE)) {
case MODE_68K:
// 68k emulator active, trigger 68k interrupt level 1
WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
r->cr.set(r->cr.get() | tswap32(kernel_data->v[0x674 >> 2]));
break;
#if INTERRUPTS_IN_NATIVE_MODE
case MODE_NATIVE:
// 68k emulator inactive, in nanokernel?
if (r->gpr[1] != KernelDataAddr) {
2004-05-20 11:05:30 +00:00
// Prepare for 68k interrupt level 1
WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
WriteMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc,
ReadMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc)
| tswap32(kernel_data->v[0x674 >> 2]));
// Execute nanokernel interrupt routine (this will activate the 68k emulator)
DisableInterrupt();
if (ROMType == ROMTYPE_NEWWORLD)
[Michael Schmitt] Attached is a patch to SheepShaver to fix memory allocation problems when OS X 10.5 is the host. It also relaxes the 512 MB RAM limit on OS X hosts. Problem ------- Some users have been unable to run SheepShaver on OS X 10.5 (Leopard) hosts. The symptom is error "ERROR: Cannot map RAM: File already exists". SheepShaver allocates RAM at fixed addresses. If it is running in "Real" addressing mode, and can't allocate at address 0, then it was hard-coded to allocate the RAM area at 0x20000000. The ROM area as allocated at 0x40800000. The normal configuration is for SheepShaver to run under SDL, which is a Cocoa wrapper. By the time SheepShaver does its memory allocations, the Cocoa application has already started. The result is the SheepShaver memory address space already contains libraries, fonts, Input Managers, and IOKit areas. On Leopard hosts these areas can land on the same addresses SheepShaver needs, so SheepShaver's memory allocation fails. Solution -------- The approach is to change SheepShaver (on Unix & OS X hosts) to allocate the RAM area anywhere it can find the space, rather than at a fixed address. This could result in the RAM allocated higher than the ROM area, which causes a crash. To prevent this from occurring, the RAM and ROM areas are allocated contiguously. Previously the ROM starting address was a constant ROM_BASE, which was used throughout the source files. The ROM start address is now a variable ROMBase. ROMBase is allocated and set by main_*.cpp just like RAMBase. A side-effect of this change is that it lifts the 512 MB RAM limit for OS X hosts. The limit was because the fixed RAM and ROM addresses were such that the RAM could only be 512 MB before it overlapped the ROM area. Impact ------ The change to make ROMBase a variable is throughout all hosts & addressing modes. The RAM and ROM areas will only shift when run on Unix & OS X hosts, otherwise the same fixed allocation address is used as before. This change is limited to "Real" addressing mode. Unlike Basilisk II, SheepShaver *pre-calculates* the offset for "Direct" addressing mode; the offset is compiled into the program. If the RAM address were allowed to shift, it could result in the RAM area wrapping around address 0. Changes to main_unix.cpp ------------------------ 1. Real addressing mode no longer defines a RAM_BASE constant. 2. The base address of the Mac ROM (ROMBase) is defined and exported by this program. 3. Memory management helper vm_mac_acquire is renamed to vm_mac_acquire_fixed. Added a new memory management helper vm_mac_acquire, which allocates memory at any address. 4. Changed and rearranged the allocation of RAM and ROM areas. Before it worked like this: - Allocate ROM area - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0, allocate at fixed address We still want to try allocating the RAM at zero, and if using DIRECT addressing we're still going to use the fixed addresses. So we don't know where the ROM should be until after we do the RAM. The new logic is: - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0 if REAL addressing allocate RAM and ROM together. The ROM address is aligned to a 1 MB boundary else (direct addressing) allocate RAM at fixed address - If ROM hasn't been allocated yet, allocate at fixed address 5. Calculate ROMBase and ROMBaseHost based on where the ROM was loaded. 6. There is a crash if the RAM is allocated too high. To try and catch this, check if it was allocated higher than the kernel data address. 7. Change subsequent code from using constant ROM_BASE to variable ROMBase. Changes to Other Programs ------------------------- emul_op.cpp, main.cpp, name_registery.cpp, rom_patches.cpp, rsrc_patches.cpp, emul_ppc.cpp, sheepshaver_glue.cpp, ppc-translate-cpp: Change from constant ROM_BASE to variable ROMBase. ppc_asm.S: It was setting register to a hard-coded literal address: 0x40b0d000. Changed to set it to ROMBase + 0x30d000. ppc_asm.tmpl: It defined a macro ASM_LO16 but it assumed that the macro would always be used with operands that included a register specification. This is not true. Moved the register specification from the macro to the macro invocations. main_beos.cpp, main_windows.cpp: Since the subprograms are all expecting a variable ROMBase, all the main_*.cpp pgrams have to define and export it. The ROM_BASE constant is moved here for consistency. The mains for beos and windows just allocate the ROM at the same fixed address as before, set ROMBaseHost and ROMBase to that address, and then use ROMBase for the subsequent code. cpu_emulation.h: removed ROM_BASE constant. This value is moved to the main_*.cpp modules, to be consistent with RAM_BASE. user_strings_unix.cpp, user_strings_unix.h: Added new error messages related to errors that occur when the RAM and ROM are allocated anywhere.
2009-08-18 18:26:11 +00:00
ppc_cpu->interrupt(ROMBase + 0x312b1c);
else
[Michael Schmitt] Attached is a patch to SheepShaver to fix memory allocation problems when OS X 10.5 is the host. It also relaxes the 512 MB RAM limit on OS X hosts. Problem ------- Some users have been unable to run SheepShaver on OS X 10.5 (Leopard) hosts. The symptom is error "ERROR: Cannot map RAM: File already exists". SheepShaver allocates RAM at fixed addresses. If it is running in "Real" addressing mode, and can't allocate at address 0, then it was hard-coded to allocate the RAM area at 0x20000000. The ROM area as allocated at 0x40800000. The normal configuration is for SheepShaver to run under SDL, which is a Cocoa wrapper. By the time SheepShaver does its memory allocations, the Cocoa application has already started. The result is the SheepShaver memory address space already contains libraries, fonts, Input Managers, and IOKit areas. On Leopard hosts these areas can land on the same addresses SheepShaver needs, so SheepShaver's memory allocation fails. Solution -------- The approach is to change SheepShaver (on Unix & OS X hosts) to allocate the RAM area anywhere it can find the space, rather than at a fixed address. This could result in the RAM allocated higher than the ROM area, which causes a crash. To prevent this from occurring, the RAM and ROM areas are allocated contiguously. Previously the ROM starting address was a constant ROM_BASE, which was used throughout the source files. The ROM start address is now a variable ROMBase. ROMBase is allocated and set by main_*.cpp just like RAMBase. A side-effect of this change is that it lifts the 512 MB RAM limit for OS X hosts. The limit was because the fixed RAM and ROM addresses were such that the RAM could only be 512 MB before it overlapped the ROM area. Impact ------ The change to make ROMBase a variable is throughout all hosts & addressing modes. The RAM and ROM areas will only shift when run on Unix & OS X hosts, otherwise the same fixed allocation address is used as before. This change is limited to "Real" addressing mode. Unlike Basilisk II, SheepShaver *pre-calculates* the offset for "Direct" addressing mode; the offset is compiled into the program. If the RAM address were allowed to shift, it could result in the RAM area wrapping around address 0. Changes to main_unix.cpp ------------------------ 1. Real addressing mode no longer defines a RAM_BASE constant. 2. The base address of the Mac ROM (ROMBase) is defined and exported by this program. 3. Memory management helper vm_mac_acquire is renamed to vm_mac_acquire_fixed. Added a new memory management helper vm_mac_acquire, which allocates memory at any address. 4. Changed and rearranged the allocation of RAM and ROM areas. Before it worked like this: - Allocate ROM area - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0, allocate at fixed address We still want to try allocating the RAM at zero, and if using DIRECT addressing we're still going to use the fixed addresses. So we don't know where the ROM should be until after we do the RAM. The new logic is: - If can, attempt to allocate RAM at address zero - If RAM not allocated at 0 if REAL addressing allocate RAM and ROM together. The ROM address is aligned to a 1 MB boundary else (direct addressing) allocate RAM at fixed address - If ROM hasn't been allocated yet, allocate at fixed address 5. Calculate ROMBase and ROMBaseHost based on where the ROM was loaded. 6. There is a crash if the RAM is allocated too high. To try and catch this, check if it was allocated higher than the kernel data address. 7. Change subsequent code from using constant ROM_BASE to variable ROMBase. Changes to Other Programs ------------------------- emul_op.cpp, main.cpp, name_registery.cpp, rom_patches.cpp, rsrc_patches.cpp, emul_ppc.cpp, sheepshaver_glue.cpp, ppc-translate-cpp: Change from constant ROM_BASE to variable ROMBase. ppc_asm.S: It was setting register to a hard-coded literal address: 0x40b0d000. Changed to set it to ROMBase + 0x30d000. ppc_asm.tmpl: It defined a macro ASM_LO16 but it assumed that the macro would always be used with operands that included a register specification. This is not true. Moved the register specification from the macro to the macro invocations. main_beos.cpp, main_windows.cpp: Since the subprograms are all expecting a variable ROMBase, all the main_*.cpp pgrams have to define and export it. The ROM_BASE constant is moved here for consistency. The mains for beos and windows just allocate the ROM at the same fixed address as before, set ROMBaseHost and ROMBase to that address, and then use ROMBase for the subsequent code. cpu_emulation.h: removed ROM_BASE constant. This value is moved to the main_*.cpp modules, to be consistent with RAM_BASE. user_strings_unix.cpp, user_strings_unix.h: Added new error messages related to errors that occur when the RAM and ROM are allocated anywhere.
2009-08-18 18:26:11 +00:00
ppc_cpu->interrupt(ROMBase + 0x312a3c);
}
break;
#endif
#if INTERRUPTS_IN_EMUL_OP_MODE
case MODE_EMUL_OP:
// 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) {
#if EMUL_TIME_STATS
const clock_t interrupt_start = clock();
#endif
#if 1
// Execute full 68k interrupt routine
M68kRegisters r;
uint32 old_r25 = ReadMacInt32(XLM_68K_R25); // Save interrupt level
WriteMacInt32(XLM_68K_R25, 0x21); // Execute with interrupt level 1
static const uint8 proc_template[] = {
0x3f, 0x3c, 0x00, 0x00, // move.w #$0000,-(sp) (fake format word)
0x48, 0x7a, 0x00, 0x0a, // pea @1(pc) (return address)
0x40, 0xe7, // move sr,-(sp) (saved SR)
0x20, 0x78, 0x00, 0x064, // move.l $64,a0
0x4e, 0xd0, // jmp (a0)
M68K_RTS >> 8, M68K_RTS & 0xff // @1
};
BUILD_SHEEPSHAVER_PROCEDURE(proc);
Execute68k(proc, &r);
WriteMacInt32(XLM_68K_R25, old_r25); // Restore interrupt level
#else
// Only update cursor
if (HasMacStarted()) {
if (InterruptFlags & INTFLAG_VIA) {
ClearInterruptFlag(INTFLAG_VIA);
ADBInterrupt();
ExecuteNative(NATIVE_VIDEO_VBL);
}
}
#endif
#if EMUL_TIME_STATS
interrupt_time += (clock() - interrupt_start);
#endif
}
break;
#endif
}
}
// Execute NATIVE_OP routine
void sheepshaver_cpu::execute_native_op(uint32 selector)
{
#if EMUL_TIME_STATS
native_exec_count++;
const clock_t native_exec_start = clock();
#endif
switch (selector) {
case NATIVE_PATCH_NAME_REGISTRY:
DoPatchNameRegistry();
break;
case NATIVE_VIDEO_INSTALL_ACCEL:
VideoInstallAccel();
break;
case NATIVE_VIDEO_VBL:
VideoVBL();
break;
case NATIVE_VIDEO_DO_DRIVER_IO:
gpr(3) = (int32)(int16)VideoDoDriverIO(gpr(3), gpr(4), gpr(5), gpr(6), gpr(7));
break;
case NATIVE_ETHER_AO_GET_HWADDR:
AO_get_ethernet_address(gpr(3));
break;
case NATIVE_ETHER_AO_ADD_MULTI:
AO_enable_multicast(gpr(3));
break;
case NATIVE_ETHER_AO_DEL_MULTI:
AO_disable_multicast(gpr(3));
break;
case NATIVE_ETHER_AO_SEND_PACKET:
AO_transmit_packet(gpr(3));
break;
case NATIVE_ETHER_IRQ:
EtherIRQ();
break;
case NATIVE_ETHER_INIT:
gpr(3) = InitStreamModule((void *)gpr(3));
break;
case NATIVE_ETHER_TERM:
TerminateStreamModule();
break;
case NATIVE_ETHER_OPEN:
gpr(3) = ether_open((queue_t *)gpr(3), (void *)gpr(4), gpr(5), gpr(6), (void*)gpr(7));
break;
case NATIVE_ETHER_CLOSE:
gpr(3) = ether_close((queue_t *)gpr(3), gpr(4), (void *)gpr(5));
break;
case NATIVE_ETHER_WPUT:
gpr(3) = ether_wput((queue_t *)gpr(3), (mblk_t *)gpr(4));
break;
case NATIVE_ETHER_RSRV:
gpr(3) = ether_rsrv((queue_t *)gpr(3));
break;
case NATIVE_NQD_SYNC_HOOK:
gpr(3) = NQD_sync_hook(gpr(3));
2004-04-18 23:03:53 +00:00
break;
case NATIVE_NQD_UNKNOWN_HOOK:
gpr(3) = NQD_unknown_hook(gpr(3));
break;
case NATIVE_NQD_BITBLT_HOOK:
gpr(3) = NQD_bitblt_hook(gpr(3));
2004-04-18 23:03:53 +00:00
break;
case NATIVE_NQD_BITBLT:
NQD_bitblt(gpr(3));
2004-04-18 23:03:53 +00:00
break;
case NATIVE_NQD_FILLRECT_HOOK:
gpr(3) = NQD_fillrect_hook(gpr(3));
2004-04-18 23:03:53 +00:00
break;
case NATIVE_NQD_INVRECT:
NQD_invrect(gpr(3));
2004-04-18 23:03:53 +00:00
break;
case NATIVE_NQD_FILLRECT:
NQD_fillrect(gpr(3));
2004-04-18 23:03:53 +00:00
break;
case NATIVE_SERIAL_NOTHING:
case NATIVE_SERIAL_OPEN:
case NATIVE_SERIAL_PRIME_IN:
case NATIVE_SERIAL_PRIME_OUT:
case NATIVE_SERIAL_CONTROL:
case NATIVE_SERIAL_STATUS:
case NATIVE_SERIAL_CLOSE: {
typedef int16 (*SerialCallback)(uint32, uint32);
static const SerialCallback serial_callbacks[] = {
SerialNothing,
SerialOpen,
SerialPrimeIn,
SerialPrimeOut,
SerialControl,
SerialStatus,
SerialClose
};
gpr(3) = serial_callbacks[selector - NATIVE_SERIAL_NOTHING](gpr(3), gpr(4));
break;
}
case NATIVE_GET_RESOURCE:
get_resource(ReadMacInt32(XLM_GET_RESOURCE));
break;
case NATIVE_GET_1_RESOURCE:
get_resource(ReadMacInt32(XLM_GET_1_RESOURCE));
break;
case NATIVE_GET_IND_RESOURCE:
get_resource(ReadMacInt32(XLM_GET_IND_RESOURCE));
break;
case NATIVE_GET_1_IND_RESOURCE:
get_resource(ReadMacInt32(XLM_GET_1_IND_RESOURCE));
break;
case NATIVE_R_GET_RESOURCE:
get_resource(ReadMacInt32(XLM_R_GET_RESOURCE));
break;
case NATIVE_MAKE_EXECUTABLE:
MakeExecutable(0, gpr(4), gpr(5));
break;
case NATIVE_CHECK_LOAD_INVOC:
check_load_invoc(gpr(3), gpr(4), gpr(5));
break;
case NATIVE_NAMED_CHECK_LOAD_INVOC:
named_check_load_invoc(gpr(3), gpr(4), gpr(5));
break;
default:
printf("FATAL: NATIVE_OP called with bogus selector %d\n", selector);
QuitEmulator();
break;
}
#if EMUL_TIME_STATS
native_exec_time += (clock() - native_exec_start);
#endif
}
/*
* Execute 68k subroutine (must be ended with EXEC_RETURN)
* This must only be called by the emul_thread when in EMUL_OP mode
* r->a[7] is unused, the routine runs on the caller's stack
*/
void Execute68k(uint32 pc, M68kRegisters *r)
{
ppc_cpu->execute_68k(pc, r);
}
/*
* Execute 68k A-Trap from EMUL_OP routine
* r->a[7] is unused, the routine runs on the caller's stack
*/
void Execute68kTrap(uint16 trap, M68kRegisters *r)
{
SheepVar proc_var(4);
uint32 proc = proc_var.addr();
WriteMacInt16(proc, trap);
WriteMacInt16(proc + 2, M68K_RTS);
Execute68k(proc, r);
}
/*
* Call MacOS PPC code
*/
uint32 call_macos(uint32 tvect)
{
return ppc_cpu->execute_macos_code(tvect, 0, NULL);
}
uint32 call_macos1(uint32 tvect, uint32 arg1)
{
const uint32 args[] = { arg1 };
return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
}
uint32 call_macos2(uint32 tvect, uint32 arg1, uint32 arg2)
{
const uint32 args[] = { arg1, arg2 };
return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
}
uint32 call_macos3(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3)
{
const uint32 args[] = { arg1, arg2, arg3 };
return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
}
uint32 call_macos4(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4)
{
const uint32 args[] = { arg1, arg2, arg3, arg4 };
return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
}
uint32 call_macos5(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5)
{
const uint32 args[] = { arg1, arg2, arg3, arg4, arg5 };
return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
}
uint32 call_macos6(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6)
{
const uint32 args[] = { arg1, arg2, arg3, arg4, arg5, arg6 };
return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
}
uint32 call_macos7(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6, uint32 arg7)
{
const uint32 args[] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7 };
return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
}