--- SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp 2003/09/07 14:25:01 1.1 +++ SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp 2005/06/30 09:09:59 1.63 @@ -1,7 +1,7 @@ /* * sheepshaver_glue.cpp - Glue Kheperix CPU to SheepShaver CPU engine interface * - * SheepShaver (C) 1997-2002 Christian Bauer and Marc Hellwig + * 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 @@ -21,6 +21,7 @@ #include "sysdeps.h" #include "cpu_emulation.h" #include "main.h" +#include "prefs.h" #include "xlowmem.h" #include "emul_op.h" #include "rom_patches.h" @@ -29,22 +30,51 @@ #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 +#include +#ifdef HAVE_MALLOC_H +#include +#endif + +#ifdef USE_SDL_VIDEO +#include +#endif #if ENABLE_MON #include "mon.h" #include "mon_disass.h" #endif -#define DEBUG 1 +#define DEBUG 0 #include "debug.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 @@ -54,6 +84,15 @@ static void enter_mon(void) #endif } +// From main_*.cpp +extern uintptr SignalStackBase(); + +// From rsrc_patches.cpp +extern "C" void check_load_invoc(uint32 type, int16 id, 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 @@ -66,26 +105,33 @@ static void enter_mon(void) // Interrupts in native mode? #define INTERRUPTS_IN_NATIVE_MODE 1 -// 68k Emulator Data -struct EmulatorData { - uint32 v[0x400]; -}; +// Pointer to Kernel Data +static KernelData * kernel_data; -// Kernel Data -struct KernelData { - uint32 v[0x400]; - EmulatorData ed; -}; +// SIGSEGV handler +sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t); -// Pointer to Kernel Data -static KernelData * const kernel_data = (KernelData *)0x68ffe000; +#if PPC_ENABLE_JIT && PPC_REENTRANT_JIT +// Special trampolines for EmulOp and NativeOp +static uint8 *emul_op_trampoline; +static uint8 *native_op_trampoline; +#endif + +// JIT Compiler enabled? +static inline bool enable_jit_p() +{ + return PrefsFindBool("jit"); +} /** * PowerPC emulator glue with special 'sheep' opcodes **/ -struct sheepshaver_exec_return { }; +enum { + PPC_I(SHEEP) = PPC_I(MAX), + PPC_I(SHEEP_MAX) +}; class sheepshaver_cpu : public powerpc_cpu @@ -95,59 +141,100 @@ class sheepshaver_cpu public: - sheepshaver_cpu() - : powerpc_cpu() - { init_decoder(); } - - // Stack pointer accessors - uint32 get_sp() const { return gpr(1); } - void set_sp(uint32 v) { gpr(1) = v; } + // Constructor + sheepshaver_cpu(); - // Condition Register accessors + // 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); - // Execution loop - void execute(uint32 pc); + // 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, uint32 sp); + void interrupt(uint32 entry); + + // Make sure the SIGSEGV handler can access CPU registers + friend sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t); - // Lazy memory allocator (one item at a time) - void *operator new(size_t size) - { return allocator_helper< sheepshaver_cpu, lazy_allocator >::allocate(); } - void operator delete(void *p) - { allocator_helper< sheepshaver_cpu, lazy_allocator >::deallocate(p); } - // FIXME: really make surre array allocation fail at link time? - void *operator new[](size_t); - void operator delete[](void *p); + // Memory allocator returning areas aligned on 16-byte boundaries + void *operator new(size_t size); + void operator delete(void *p); }; -lazy_allocator< sheepshaver_cpu > allocator_helper< sheepshaver_cpu, lazy_allocator >::allocator; +// Memory allocator returning sheepshaver_cpu objects aligned on 16-byte boundaries +// FORMAT: [ alignment ] magic identifier, offset to malloc'ed data, sheepshaver_cpu data +void *sheepshaver_cpu::operator new(size_t size) +{ + const int ALIGN = 16; + + // Allocate enough space for sheepshaver_cpu data + signature + align pad + uint8 *ptr = (uint8 *)malloc(size + ALIGN * 2); + if (ptr == NULL) + throw std::bad_alloc(); + + // Align memory + int ofs = 0; + while ((((uintptr)ptr) % ALIGN) != 0) + ofs++, ptr++; + + // Insert signature and offset + struct aligned_block_t { + uint32 pad[(ALIGN - 8) / 4]; + uint32 signature; + uint32 offset; + uint8 data[sizeof(sheepshaver_cpu)]; + }; + aligned_block_t *blk = (aligned_block_t *)ptr; + blk->signature = FOURCC('S','C','P','U'); + blk->offset = ofs + (&blk->data[0] - (uint8 *)blk); + assert((((uintptr)&blk->data) % ALIGN) == 0); + return &blk->data[0]; +} -void sheepshaver_cpu::init_decoder() +void sheepshaver_cpu::operator delete(void *p) { -#ifndef PPC_NO_STATIC_II_INDEX_TABLE - static bool initialized = false; - if (initialized) - return; - initialized = true; -#endif + uint32 *blk = (uint32 *)p; + assert(blk[-2] == FOURCC('S','C','P','U')); + void *ptr = (void *)(((uintptr)p) - blk[-1]); + free(ptr); +} +sheepshaver_cpu::sheepshaver_cpu() + : powerpc_cpu(enable_jit_p()) +{ + init_decoder(); +} + +void sheepshaver_cpu::init_decoder() +{ static const instr_info_t sheep_ii_table[] = { { "sheep", - (execute_fn)&sheepshaver_cpu::execute_sheep, + (execute_pmf)&sheepshaver_cpu::execute_sheep, NULL, - D_form, 6, 0, CFLOW_TRAP + PPC_I(SHEEP), + D_form, 6, 0, CFLOW_JUMP | CFLOW_TRAP } }; @@ -160,8 +247,40 @@ void sheepshaver_cpu::init_decoder() } } -// Forward declaration for native opcode handler -static void NativeOp(int selector); +/* 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) @@ -173,68 +292,204 @@ void sheepshaver_cpu::execute_sheep(uint case 0: // EMUL_RETURN QuitEmulator(); break; - + case 1: // EXEC_RETURN - throw sheepshaver_exec_return(); + spcflags().set(SPCFLAG_CPU_EXEC_RETURN); break; case 2: // EXEC_NATIVE - NativeOp((opcode >> 6) & 0x1f); - pc() = lr(); + execute_native_op(NATIVE_OP_field::extract(opcode)); + if (FN_field::test(opcode)) + pc() = lr(); + else + pc() += 4; break; - default: { // 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); - EmulOp(&r68, gpr(24), (opcode & 0x3f) - 3); - 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); + default: // EMUL_OP + execute_emul_op(EMUL_OP_field::extract(opcode) - 3); pc() += 4; break; } - } } -// Execution loop -void sheepshaver_cpu::execute(uint32 entry) -{ - try { - pc() = entry; - powerpc_cpu::execute(); +// 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; + } + 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; +#endif + case NATIVE_BITBLT: + dg.gen_load_T0_GPR(3); + dg.gen_invoke_T0((void (*)(uint32))NQD_bitblt); + status = COMPILE_CODE_OK; + break; + case NATIVE_INVRECT: + dg.gen_load_T0_GPR(3); + dg.gen_invoke_T0((void (*)(uint32))NQD_invrect); + status = COMPILE_CODE_OK; + break; + case NATIVE_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_A0_LR(); + dg.gen_set_PC_A0(); + 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_A0_LR(); + dg.gen_set_PC_A0(); + } + dg.gen_mov_32_T0_im(selector); + dg.gen_jmp(native_op_trampoline); + cg_context.done_compile = true; + status = COMPILE_EPILOGUE_OK; + break; +#endif + // 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; } - catch (sheepshaver_exec_return const &) { - // Nothing, simply return + + 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; +#endif + // 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; } - catch (...) { - printf("ERROR: execute() received an unknown exception!\n"); - QuitEmulator(); } + return status; } +#endif // Handle MacOS interrupt -void sheepshaver_cpu::interrupt(uint32 entry, uint32 sp) +void sheepshaver_cpu::interrupt(uint32 entry) { - // Create stack frame - gpr(1) = sp - 64; +#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 - uint32 trampoline[] = { POWERPC_EMUL_OP | 1 }; + SheepVar32 trampoline = POWERPC_EXEC_RETURN; // Prepare registers for nanokernel interrupt routine - kernel_data->v[0x004 >> 2] = gpr(1); - kernel_data->v[0x018 >> 2] = gpr(6); + kernel_data->v[0x004 >> 2] = htonl(gpr(1)); + kernel_data->v[0x018 >> 2] = htonl(gpr(6)); - gpr(6) = kernel_data->v[0x65c >> 2]; + 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)); @@ -244,11 +499,11 @@ void sheepshaver_cpu::interrupt(uint32 e WriteMacInt32(gpr(6) + 0x16c, gpr(13)); gpr(1) = KernelDataAddr; - gpr(7) = kernel_data->v[0x660 >> 2]; + gpr(7) = ntohl(kernel_data->v[0x660 >> 2]); gpr(8) = 0; - gpr(10) = (uint32)trampoline; - gpr(12) = (uint32)trampoline; - gpr(13) = cr().get(); + 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)); @@ -256,18 +511,30 @@ void sheepshaver_cpu::interrupt(uint32 e gpr(7) = result; gpr(11) = 0xf072; // MSR (SRR1) - cr().set((gpr(11) & 0x0fff0000) | (cr().get() & ~0x0fff0000)); + cr().set((gpr(11) & 0x0fff0000) | (get_cr() & ~0x0fff0000)); // Enter nanokernel execute(entry); - // Cleanup stack - gpr(1) += 64; + // 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"); @@ -277,21 +544,24 @@ void sheepshaver_cpu::execute_68k(uint32 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 + 19*4 + 18*8; + gpr(1) -= 56; WriteMacInt32(gpr(1), sp); // Save PowerPC registers - memcpy(Mac2HostAddr(gpr(1)+56), &gpr(13), sizeof(uint32)*(32-13)); + uint32 saved_GPRs[19]; + memcpy(&saved_GPRs[0], &gpr(13), sizeof(uint32)*(32-13)); #if SAVE_FP_EXEC_68K - memcpy(Mac2HostAddr(gpr(1)+56+19*4), &fpr(14), sizeof(double)*(32-14)); + double saved_FPRs[18]; + memcpy(&saved_FPRs[0], &fpr(14), sizeof(double)*(32-14)); #endif // Setup registers for 68k emulator - cr().set(0); - cr().set(2, 1); // Supervisor mode + 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] @@ -301,8 +571,8 @@ void sheepshaver_cpu::execute_68k(uint32 gpr(25) = ReadMacInt32(XLM_68K_R25); // MSB of SR gpr(26) = 0; gpr(28) = 0; // VBR - gpr(29) = kernel_data->ed.v[0x74 >> 2]; // Pointer to opcode table - gpr(30) = kernel_data->ed.v[0x78 >> 2]; // Address of emulator + 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 @@ -334,31 +604,41 @@ void sheepshaver_cpu::execute_68k(uint32 r->a[i] = gpr(16 + i); // Restore PowerPC registers - memcpy(&gpr(13), Mac2HostAddr(gpr(1)+56), sizeof(uint32)*(32-13)); + memcpy(&gpr(13), &saved_GPRs[0], sizeof(uint32)*(32-13)); #if SAVE_FP_EXEC_68K - memcpy(&fpr(14), Mac2HostAddr(gpr(1)+56+19*4), sizeof(double)*(32-14)); + memcpy(&fpr(14), &saved_FPRs[0], sizeof(double)*(32-14)); #endif // Cleanup stack - gpr(1) += 56 + 19*4 + 18*8; + 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 - uint32 trampoline[] = { POWERPC_EMUL_OP | 1 }; - lr() = (uint32)trampoline; + SheepVar32 trampoline = POWERPC_EXEC_RETURN; + lr() = trampoline.addr(); gpr(1) -= 64; // Create stack frame uint32 proc = ReadMacInt32(tvect); // Get routine address @@ -389,14 +669,48 @@ uint32 sheepshaver_cpu::execute_macos_co 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) { - printf("ERROR: get_resource() unimplemented\n"); - QuitEmulator(); + 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; } @@ -404,141 +718,241 @@ inline void sheepshaver_cpu::get_resourc * SheepShaver CPU engine interface **/ -static sheepshaver_cpu *main_cpu = NULL; // CPU emulator to handle usual control flow -static sheepshaver_cpu *interrupt_cpu = NULL; // CPU emulator to handle interrupts -static sheepshaver_cpu *current_cpu = NULL; // Current CPU emulator context +// 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) { - current_cpu->dump_registers(); + ppc_cpu->dump_registers(); } // Dump log static void dump_log(void) { - current_cpu->dump_log(); + ppc_cpu->dump_log(); } /* * Initialize CPU emulation */ -static struct sigaction sigsegv_action; - -#if defined(__powerpc__) -#include -#endif - -static void sigsegv_handler(int sig, siginfo_t *sip, void *scp) +sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction) { - const uintptr addr = (uintptr)sip->si_addr; #if ENABLE_VOSF - // Handle screen fault. - extern bool Screen_fault_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction); - if (Screen_fault_handler((sigsegv_address_t)addr, SIGSEGV_INVALID_PC)) - return; + // Handle screen fault + extern bool Screen_fault_handler(sigsegv_address_t, sigsegv_address_t); + if (Screen_fault_handler(fault_address, fault_instruction)) + return SIGSEGV_RETURN_SUCCESS; #endif -#if defined(__powerpc__) - if (addr >= ROM_BASE && addr < ROM_BASE + ROM_SIZE) { - printf("IGNORE write access to ROM at %08x\n", addr); - (((ucontext_t *)scp)->uc_mcontext.regs)->nip += 4; - return; - } - if (addr >= 0xf3012000 && addr < 0xf3014000 && 0) { - printf("IGNORE write access to ROM at %08x\n", addr); - (((ucontext_t *)scp)->uc_mcontext.regs)->nip += 4; - return; + + const uintptr addr = (uintptr)fault_address; +#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? + bool mac_fault = (pc >= ROM_BASE) && (pc < (ROM_BASE + 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 + if (pc == ROM_BASE + 0x488160 && cpu->gpr(20) == 0xf8000000) + return SIGSEGV_RETURN_SKIP_INSTRUCTION; + + // MacOS 8.5 installation + else if (pc == ROM_BASE + 0x488140 && cpu->gpr(16) == 0xf8000000) + return SIGSEGV_RETURN_SKIP_INSTRUCTION; + + // MacOS 8 serial drivers on startup + else if (pc == ROM_BASE + 0x48e080 && (cpu->gpr(8) == 0xf3012002 || cpu->gpr(8) == 0xf3012000)) + return SIGSEGV_RETURN_SKIP_INSTRUCTION; + + // MacOS 8.1 serial drivers on startup + else if (pc == ROM_BASE + 0x48c5e0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000)) + return SIGSEGV_RETURN_SKIP_INSTRUCTION; + else if (pc == ROM_BASE + 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; } -#endif - printf("Caught SIGSEGV at address %p\n", sip->si_addr); - printf("Native PC: %08x\n", (((ucontext_t *)scp)->uc_mcontext.regs)->nip); - printf("Current CPU: %s\n", current_cpu == main_cpu ? "main" : "interrupts"); -#if 1 - dump_registers(); #else - printf("Main CPU context\n"); - main_cpu->dump_registers(); - printf("Interrupts CPU context\n"); - interrupt_cpu->dump_registers(); +#error "FIXME: You don't have the capability to skip instruction within signal handlers" #endif - current_cpu->dump_log(); - WriteMacInt32(XLM_IRQ_NEST, 1); + + fprintf(stderr, "SIGSEGV\n"); + fprintf(stderr, " pc %p\n", fault_instruction); + fprintf(stderr, " ea %p\n", fault_address); + dump_registers(); + ppc_cpu->dump_log(); enter_mon(); QuitEmulator(); + + return SIGSEGV_RETURN_FAILURE; } void init_emul_ppc(void) { + // Get pointer to KernelData in host address space + kernel_data = (KernelData *)Mac2HostAddr(KERNEL_DATA_BASE); + // Initialize main CPU emulator - main_cpu = new sheepshaver_cpu(); - main_cpu->set_register(powerpc_registers::GPR(3), any_register((uint32)ROM_BASE + 0x30d000)); + ppc_cpu = new sheepshaver_cpu(); + ppc_cpu->set_register(powerpc_registers::GPR(3), any_register((uint32)ROM_BASE + 0x30d000)); + ppc_cpu->set_register(powerpc_registers::GPR(4), any_register(KernelDataAddr + 0x1000)); WriteMacInt32(XLM_RUN_MODE, MODE_68K); - // Initialize alternate CPU emulator to handle interrupts - interrupt_cpu = new sheepshaver_cpu(); - - // Install SIGSEGV handler - sigemptyset(&sigsegv_action.sa_mask); - sigsegv_action.sa_sigaction = sigsegv_handler; - sigsegv_action.sa_flags = SA_SIGINFO; - sigsegv_action.sa_restorer = NULL; - sigaction(SIGSEGV, &sigsegv_action, NULL); - #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; } +#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) { - current_cpu = main_cpu; - current_cpu->start_log(); - current_cpu->execute(entry); +#if 0 + ppc_cpu->start_log(); +#endif + // start emulation loop and enable code translation or caching + ppc_cpu->execute(entry); } /* * Handle PowerPC interrupt */ -// Atomic operations -extern int atomic_add(int *var, int v); -extern int atomic_and(int *var, int v); -extern int atomic_or(int *var, int v); +void TriggerInterrupt(void) +{ +#if 0 + WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1); +#else + // Trigger interrupt to main cpu only + if (ppc_cpu) + ppc_cpu->trigger_interrupt(); +#endif +} -void HandleInterrupt(void) +void HandleInterrupt(powerpc_registers *r) { - // Do nothing if interrupts are disabled - if (ReadMacInt32(XLM_IRQ_NEST) > 0 || InterruptFlags == 0) - return; +#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 CPU objects are not initialized yet - if (current_cpu == NULL) + // Do nothing if interrupts are disabled + if (int32(ReadMacInt32(XLM_IRQ_NEST)) > 0) return; - // Disable MacOS stack sniffer - WriteMacInt32(0x110, 0); + // 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 - assert(current_cpu == main_cpu); WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1); - main_cpu->set_cr(main_cpu->get_cr() | tswap32(kernel_data->v[0x674 >> 2])); + 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? - assert(current_cpu == main_cpu); - if (main_cpu->gpr(1) != KernelDataAddr) { + if (r->gpr[1] != KernelDataAddr) { + // Prepare for 68k interrupt level 1 WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1); WriteMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc, @@ -546,13 +960,11 @@ void HandleInterrupt(void) | tswap32(kernel_data->v[0x674 >> 2])); // Execute nanokernel interrupt routine (this will activate the 68k emulator) - atomic_add((int32 *)XLM_IRQ_NEST, htonl(1)); - current_cpu = interrupt_cpu; + DisableInterrupt(); if (ROMType == ROMTYPE_NEWWORLD) - current_cpu->interrupt(ROM_BASE + 0x312b1c, main_cpu->get_sp()); + ppc_cpu->interrupt(ROM_BASE + 0x312b1c); else - current_cpu->interrupt(ROM_BASE + 0x312a3c, main_cpu->get_sp()); - current_cpu = main_cpu; + ppc_cpu->interrupt(ROM_BASE + 0x312a3c); } break; #endif @@ -561,20 +973,24 @@ void HandleInterrupt(void) 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 uint16 proc[] = { - 0x3f3c, 0x0000, // move.w #$0000,-(sp) (fake format word) - 0x487a, 0x000a, // pea @1(pc) (return address) - 0x40e7, // move sr,-(sp) (saved SR) - 0x2078, 0x0064, // move.l $64,a0 - 0x4ed0, // jmp (a0) - M68K_RTS // @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 }; - Execute68k((uint32)proc, &r); + BUILD_SHEEPSHAVER_PROCEDURE(proc); + Execute68k(proc, &r); WriteMacInt32(XLM_68K_R25, old_r25); // Restore interrupt level #else // Only update cursor @@ -582,60 +998,33 @@ void HandleInterrupt(void) if (InterruptFlags & INTFLAG_VIA) { ClearInterruptFlag(INTFLAG_VIA); ADBInterrupt(); - ExecutePPC(VideoVBL); + ExecuteNative(NATIVE_VIDEO_VBL); } } #endif +#if EMUL_TIME_STATS + interrupt_time += (clock() - interrupt_start); +#endif } break; #endif } } -/* - * Execute NATIVE_OP opcode (called by PowerPC emulator) - */ - -#define POWERPC_NATIVE_OP(selector) \ - { tswap32(POWERPC_EMUL_OP | 2 | (((uint32)selector) << 6)) } - -// FIXME: Make sure 32-bit relocations are used -const uint32 NativeOpTable[NATIVE_OP_MAX] = { - POWERPC_NATIVE_OP(NATIVE_PATCH_NAME_REGISTRY), - POWERPC_NATIVE_OP(NATIVE_VIDEO_INSTALL_ACCEL), - POWERPC_NATIVE_OP(NATIVE_VIDEO_VBL), - POWERPC_NATIVE_OP(NATIVE_VIDEO_DO_DRIVER_IO), - POWERPC_NATIVE_OP(NATIVE_ETHER_IRQ), - POWERPC_NATIVE_OP(NATIVE_ETHER_INIT), - POWERPC_NATIVE_OP(NATIVE_ETHER_TERM), - POWERPC_NATIVE_OP(NATIVE_ETHER_OPEN), - POWERPC_NATIVE_OP(NATIVE_ETHER_CLOSE), - POWERPC_NATIVE_OP(NATIVE_ETHER_WPUT), - POWERPC_NATIVE_OP(NATIVE_ETHER_RSRV), - POWERPC_NATIVE_OP(NATIVE_SERIAL_NOTHING), - POWERPC_NATIVE_OP(NATIVE_SERIAL_OPEN), - POWERPC_NATIVE_OP(NATIVE_SERIAL_PRIME_IN), - POWERPC_NATIVE_OP(NATIVE_SERIAL_PRIME_OUT), - POWERPC_NATIVE_OP(NATIVE_SERIAL_CONTROL), - POWERPC_NATIVE_OP(NATIVE_SERIAL_STATUS), - POWERPC_NATIVE_OP(NATIVE_SERIAL_CLOSE), - POWERPC_NATIVE_OP(NATIVE_GET_RESOURCE), - POWERPC_NATIVE_OP(NATIVE_GET_1_RESOURCE), - POWERPC_NATIVE_OP(NATIVE_GET_IND_RESOURCE), - POWERPC_NATIVE_OP(NATIVE_GET_1_IND_RESOURCE), - POWERPC_NATIVE_OP(NATIVE_R_GET_RESOURCE), -}; - static void get_resource(void); static void get_1_resource(void); static void get_ind_resource(void); static void get_1_ind_resource(void); static void r_get_resource(void); -#define GPR(REG) current_cpu->gpr(REG) - -static void NativeOp(int selector) +// 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(); @@ -647,23 +1036,46 @@ static void NativeOp(int selector) VideoVBL(); break; case NATIVE_VIDEO_DO_DRIVER_IO: - GPR(3) = (int32)(int16)VideoDoDriverIO((void *)GPR(3), (void *)GPR(4), - (void *)GPR(5), GPR(6), GPR(7)); + gpr(3) = (int32)(int16)VideoDoDriverIO(gpr(3), gpr(4), gpr(5), gpr(6), gpr(7)); break; - case NATIVE_GET_RESOURCE: - get_resource(); + case NATIVE_ETHER_IRQ: + EtherIRQ(); break; - case NATIVE_GET_1_RESOURCE: - get_1_resource(); + case NATIVE_ETHER_INIT: + gpr(3) = InitStreamModule((void *)gpr(3)); break; - case NATIVE_GET_IND_RESOURCE: - get_ind_resource(); + case NATIVE_ETHER_TERM: + TerminateStreamModule(); break; - case NATIVE_GET_1_IND_RESOURCE: - get_1_ind_resource(); + 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_SYNC_HOOK: + gpr(3) = NQD_sync_hook(gpr(3)); break; - case NATIVE_R_GET_RESOURCE: - r_get_resource(); + case NATIVE_BITBLT_HOOK: + gpr(3) = NQD_bitblt_hook(gpr(3)); + break; + case NATIVE_BITBLT: + NQD_bitblt(gpr(3)); + break; + case NATIVE_FILLRECT_HOOK: + gpr(3) = NQD_fillrect_hook(gpr(3)); + break; + case NATIVE_INVRECT: + NQD_invrect(gpr(3)); + break; + case NATIVE_FILLRECT: + NQD_fillrect(gpr(3)); break; case NATIVE_SERIAL_NOTHING: case NATIVE_SERIAL_OPEN: @@ -682,28 +1094,40 @@ static void NativeOp(int selector) SerialStatus, SerialClose }; - GPR(3) = serial_callbacks[selector - NATIVE_SERIAL_NOTHING](GPR(3), GPR(4)); + gpr(3) = serial_callbacks[selector - NATIVE_SERIAL_NOTHING](gpr(3), gpr(4)); 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: { + typedef void (*GetResourceCallback)(void); + static const GetResourceCallback get_resource_callbacks[] = { + ::get_resource, + ::get_1_resource, + ::get_ind_resource, + ::get_1_ind_resource, + ::r_get_resource + }; + get_resource_callbacks[selector - NATIVE_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; default: printf("FATAL: NATIVE_OP called with bogus selector %d\n", selector); QuitEmulator(); break; } -} - -/* - * Execute native subroutine (LR must contain return address) - */ -void ExecuteNative(int selector) -{ - uint32 tvect[2]; - tvect[0] = tswap32(POWERPC_NATIVE_OP_FUNC(selector)); - tvect[1] = 0; // Fake TVECT - RoutineDescriptor desc = BUILD_PPC_ROUTINE_DESCRIPTOR(0, tvect); - M68kRegisters r; - Execute68k((uint32)&desc, &r); +#if EMUL_TIME_STATS + native_exec_time += (clock() - native_exec_start); +#endif } /* @@ -714,7 +1138,7 @@ void ExecuteNative(int selector) void Execute68k(uint32 pc, M68kRegisters *r) { - current_cpu->execute_68k(pc, r); + ppc_cpu->execute_68k(pc, r); } /* @@ -724,8 +1148,11 @@ void Execute68k(uint32 pc, M68kRegisters void Execute68kTrap(uint16 trap, M68kRegisters *r) { - uint16 proc[2] = {trap, M68K_RTS}; - Execute68k((uint32)proc, r); + SheepVar proc_var(4); + uint32 proc = proc_var.addr(); + WriteMacInt16(proc, trap); + WriteMacInt16(proc + 2, M68K_RTS); + Execute68k(proc, r); } /* @@ -734,103 +1161,76 @@ void Execute68kTrap(uint16 trap, M68kReg uint32 call_macos(uint32 tvect) { - return current_cpu->execute_macos_code(tvect, 0, NULL); + return ppc_cpu->execute_macos_code(tvect, 0, NULL); } uint32 call_macos1(uint32 tvect, uint32 arg1) { const uint32 args[] = { arg1 }; - return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args); + 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 current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args); + 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 current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args); + 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 current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args); + 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 current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args); + 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 current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args); + 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 current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args); -} - -/* - * Atomic operations - */ - -int atomic_add(int *var, int v) -{ - int ret = *var; - *var += v; - return ret; -} - -int atomic_and(int *var, int v) -{ - int ret = *var; - *var &= v; - return ret; -} - -int atomic_or(int *var, int v) -{ - int ret = *var; - *var |= v; - return ret; + return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args); } /* * Resource Manager thunks */ -extern "C" void check_load_invoc(uint32 type, int16 id, uint16 **h); - void get_resource(void) { - current_cpu->get_resource(ReadMacInt32(XLM_GET_RESOURCE)); + ppc_cpu->get_resource(ReadMacInt32(XLM_GET_RESOURCE)); } void get_1_resource(void) { - current_cpu->get_resource(ReadMacInt32(XLM_GET_1_RESOURCE)); + ppc_cpu->get_resource(ReadMacInt32(XLM_GET_1_RESOURCE)); } void get_ind_resource(void) { - current_cpu->get_resource(ReadMacInt32(XLM_GET_IND_RESOURCE)); + ppc_cpu->get_resource(ReadMacInt32(XLM_GET_IND_RESOURCE)); } void get_1_ind_resource(void) { - current_cpu->get_resource(ReadMacInt32(XLM_GET_1_IND_RESOURCE)); + ppc_cpu->get_resource(ReadMacInt32(XLM_GET_1_IND_RESOURCE)); } void r_get_resource(void) { - current_cpu->get_resource(ReadMacInt32(XLM_R_GET_RESOURCE)); + ppc_cpu->get_resource(ReadMacInt32(XLM_R_GET_RESOURCE)); }