--- SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp 2004/05/23 05:28:12 1.42 +++ SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp 2004/11/22 22:04:38 1.53 @@ -42,6 +42,13 @@ #include #include +#ifdef HAVE_MALLOC_H +#include +#endif + +#ifdef USE_SDL_VIDEO +#include +#endif #if ENABLE_MON #include "mon.h" @@ -52,11 +59,13 @@ #include "debug.h" // Emulation time statistics -#define EMUL_TIME_STATS 1 +#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; +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; @@ -99,14 +108,11 @@ const uint32 POWERPC_EXEC_RETURN = POWER // Interrupts in native mode? #define INTERRUPTS_IN_NATIVE_MODE 1 -// Enable native EMUL_OPs to be run without a mode switch -#define ENABLE_NATIVE_EMUL_OP 1 - // Pointer to Kernel Data -static KernelData * const kernel_data = (KernelData *)KERNEL_DATA_BASE; +static KernelData * kernel_data; // SIGSEGV handler -static sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t); +sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t); #if PPC_ENABLE_JIT && PPC_REENTRANT_JIT // Special trampolines for EmulOp and NativeOp @@ -136,14 +142,6 @@ class sheepshaver_cpu void init_decoder(); void execute_sheep(uint32 opcode); - // Filter out EMUL_OP routines that only call native code - bool filter_execute_emul_op(uint32 emul_op); - - // "Native" EMUL_OP routines - void execute_emul_op_microseconds(); - void execute_emul_op_idle_time_1(); - void execute_emul_op_idle_time_2(); - // CPU context to preserve on interrupt class interrupt_context { uint32 gpr[32]; @@ -185,9 +183,10 @@ public: // 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); @@ -268,57 +267,9 @@ typedef bit_field< 19, 19 > FN_field; typedef bit_field< 20, 25 > NATIVE_OP_field; typedef bit_field< 26, 31 > EMUL_OP_field; -// "Native" EMUL_OP routines -#define GPR_A(REG) gpr(16 + (REG)) -#define GPR_D(REG) gpr( 8 + (REG)) - -void sheepshaver_cpu::execute_emul_op_microseconds() -{ - Microseconds(GPR_A(0), GPR_D(0)); -} - -void sheepshaver_cpu::execute_emul_op_idle_time_1() -{ - // Sleep if no events pending - if (ReadMacInt32(0x14c) == 0) - Delay_usec(16667); - GPR_A(0) = ReadMacInt32(0x2b6); -} - -void sheepshaver_cpu::execute_emul_op_idle_time_2() -{ - // Sleep if no events pending - if (ReadMacInt32(0x14c) == 0) - Delay_usec(16667); - GPR_D(0) = (uint32)-2; -} - -// Filter out EMUL_OP routines that only call native code -bool sheepshaver_cpu::filter_execute_emul_op(uint32 emul_op) -{ - switch (emul_op) { - case OP_MICROSECONDS: - execute_emul_op_microseconds(); - return true; - case OP_IDLE_TIME: - execute_emul_op_idle_time_1(); - return true; - case OP_IDLE_TIME_2: - execute_emul_op_idle_time_2(); - return true; - } - return false; -} - // Execute EMUL_OP routine void sheepshaver_cpu::execute_emul_op(uint32 emul_op) { -#if ENABLE_NATIVE_EMUL_OP - // First, filter out EMUL_OPs that can be executed without a mode switch - if (filter_execute_emul_op(emul_op)) - return; -#endif - M68kRegisters r68; WriteMacInt32(XLM_68K_R25, gpr(25)); WriteMacInt32(XLM_RUN_MODE, MODE_EMUL_OP); @@ -371,9 +322,9 @@ void sheepshaver_cpu::execute_sheep(uint } // Compile one instruction +#if PPC_ENABLE_JIT int sheepshaver_cpu::compile1(codegen_context_t & cg_context) { -#if PPC_ENABLE_JIT const instr_info_t *ii = cg_context.instr_info; if (ii->mnemo != PPC_I(SHEEP)) return COMPILE_FAILURE; @@ -444,14 +395,6 @@ int sheepshaver_cpu::compile1(codegen_co status = COMPILE_CODE_OK; break; #endif - case NATIVE_DISABLE_INTERRUPT: - dg.gen_invoke(DisableInterrupt); - status = COMPILE_CODE_OK; - break; - case NATIVE_ENABLE_INTERRUPT: - dg.gen_invoke(EnableInterrupt); - status = COMPILE_CODE_OK; - break; case NATIVE_BITBLT: dg.gen_load_T0_GPR(3); dg.gen_invoke_T0((void (*)(uint32))NQD_bitblt); @@ -508,27 +451,6 @@ int sheepshaver_cpu::compile1(codegen_co default: { // EMUL_OP uint32 emul_op = EMUL_OP_field::extract(opcode) - 3; -#if ENABLE_NATIVE_EMUL_OP - typedef void (*emul_op_func_t)(dyngen_cpu_base); - emul_op_func_t emul_op_func = 0; - switch (emul_op) { - case OP_MICROSECONDS: - emul_op_func = (emul_op_func_t)nv_mem_fun(&sheepshaver_cpu::execute_emul_op_microseconds).ptr(); - break; - case OP_IDLE_TIME: - emul_op_func = (emul_op_func_t)nv_mem_fun(&sheepshaver_cpu::execute_emul_op_idle_time_1).ptr(); - break; - case OP_IDLE_TIME_2: - emul_op_func = (emul_op_func_t)nv_mem_fun(&sheepshaver_cpu::execute_emul_op_idle_time_2).ptr(); - break; - } - if (emul_op_func) { - dg.gen_invoke_CPU(emul_op_func); - cg_context.done_compile = false; - status = COMPILE_CODE_OK; - break; - } -#endif #if PPC_REENTRANT_JIT // Try to execute EmulOp trampoline dg.gen_set_PC_im(cg_context.pc + 4); @@ -548,9 +470,8 @@ int sheepshaver_cpu::compile1(codegen_co } } return status; -#endif - return COMPILE_FAILURE; } +#endif // CPU context to preserve on interrupt sheepshaver_cpu::interrupt_context::interrupt_context(sheepshaver_cpu *_cpu, const char *_where) @@ -596,7 +517,7 @@ sheepshaver_cpu::interrupt_context::~int void sheepshaver_cpu::interrupt(uint32 entry) { #if EMUL_TIME_STATS - interrupt_count++; + ppc_interrupt_count++; const clock_t interrupt_start = clock(); #endif @@ -882,7 +803,7 @@ static void dump_log(void) * Initialize CPU emulation */ -static sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction) +sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction) { #if ENABLE_VOSF // Handle screen fault @@ -894,7 +815,7 @@ static sigsegv_return_t sigsegv_handler( const uintptr addr = (uintptr)fault_address; #if HAVE_SIGSEGV_SKIP_INSTRUCTION // Ignore writes to ROM - if ((addr - ROM_BASE) < ROM_SIZE) + if ((addr - (uintptr)ROMBaseHost) < ROM_SIZE) return SIGSEGV_RETURN_SKIP_INSTRUCTION; // Get program counter of target CPU @@ -902,7 +823,7 @@ static sigsegv_return_t sigsegv_handler( 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)); + 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 @@ -922,6 +843,12 @@ static sigsegv_return_t sigsegv_handler( 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()) @@ -948,15 +875,15 @@ static sigsegv_return_t sigsegv_handler( 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(); 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); - // Install the handler for SIGSEGV - sigsegv_install_handler(sigsegv_handler); - #if ENABLE_MON // Install "regs" command in cxmon mon_add_command("regs", dump_registers, "regs Dump PowerPC registers\n"); @@ -982,6 +909,8 @@ void exit_emul_ppc(void) 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); \ @@ -1057,17 +986,21 @@ void TriggerInterrupt(void) void sheepshaver_cpu::handle_interrupt(void) { - // Do nothing if interrupts are disabled - if (*(int32 *)XLM_IRQ_NEST > 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 there is no interrupt pending - if (InterruptFlags == 0) + // Do nothing if interrupts are disabled + if (int32(ReadMacInt32(XLM_IRQ_NEST)) > 0) return; // Current interrupt nest level static int interrupt_depth = 0; ++interrupt_depth; +#if EMUL_TIME_STATS + interrupt_count++; +#endif // Disable MacOS stack sniffer WriteMacInt32(0x110, 0); @@ -1107,12 +1040,15 @@ void sheepshaver_cpu::handle_interrupt(v // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0 if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) { interrupt_context ctx(this, "68k mode"); +#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[] = { + 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) @@ -1120,7 +1056,8 @@ void sheepshaver_cpu::handle_interrupt(v 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 @@ -1132,6 +1069,9 @@ void sheepshaver_cpu::handle_interrupt(v } } #endif +#if EMUL_TIME_STATS + interrupt_time += (clock() - interrupt_start); +#endif } break; #endif @@ -1166,8 +1106,7 @@ void sheepshaver_cpu::execute_native_op( 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; #ifdef WORDS_BIGENDIAN case NATIVE_ETHER_IRQ: @@ -1251,14 +1190,8 @@ void sheepshaver_cpu::execute_native_op( get_resource_callbacks[selector - NATIVE_GET_RESOURCE](); break; } - case NATIVE_DISABLE_INTERRUPT: - DisableInterrupt(); - break; - case NATIVE_ENABLE_INTERRUPT: - EnableInterrupt(); - break; case NATIVE_MAKE_EXECUTABLE: - MakeExecutable(0, (void *)gpr(4), gpr(5)); + MakeExecutable(0, gpr(4), gpr(5)); break; case NATIVE_CHECK_LOAD_INVOC: check_load_invoc(gpr(3), gpr(4), gpr(5));