43 |
|
#include <stdio.h> |
44 |
|
#include <stdlib.h> |
45 |
|
|
46 |
+ |
#ifdef USE_SDL_VIDEO |
47 |
+ |
#include <SDL_events.h> |
48 |
+ |
#endif |
49 |
+ |
|
50 |
|
#if ENABLE_MON |
51 |
|
#include "mon.h" |
52 |
|
#include "mon_disass.h" |
56 |
|
#include "debug.h" |
57 |
|
|
58 |
|
// Emulation time statistics |
59 |
< |
#define EMUL_TIME_STATS 1 |
59 |
> |
#ifndef EMUL_TIME_STATS |
60 |
> |
#define EMUL_TIME_STATS 0 |
61 |
> |
#endif |
62 |
|
|
63 |
|
#if EMUL_TIME_STATS |
64 |
|
static clock_t emul_start_time; |
65 |
< |
static uint32 interrupt_count = 0; |
65 |
> |
static uint32 interrupt_count = 0, ppc_interrupt_count = 0; |
66 |
|
static clock_t interrupt_time = 0; |
67 |
|
static uint32 exec68k_count = 0; |
68 |
|
static clock_t exec68k_time = 0; |
112 |
|
static KernelData * const kernel_data = (KernelData *)KERNEL_DATA_BASE; |
113 |
|
|
114 |
|
// SIGSEGV handler |
115 |
< |
static sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t); |
115 |
> |
sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t); |
116 |
|
|
117 |
|
#if PPC_ENABLE_JIT && PPC_REENTRANT_JIT |
118 |
|
// Special trampolines for EmulOp and NativeOp |
450 |
|
status = COMPILE_CODE_OK; |
451 |
|
break; |
452 |
|
#endif |
447 |
– |
case NATIVE_DISABLE_INTERRUPT: |
448 |
– |
dg.gen_invoke(DisableInterrupt); |
449 |
– |
status = COMPILE_CODE_OK; |
450 |
– |
break; |
451 |
– |
case NATIVE_ENABLE_INTERRUPT: |
452 |
– |
dg.gen_invoke(EnableInterrupt); |
453 |
– |
status = COMPILE_CODE_OK; |
454 |
– |
break; |
453 |
|
case NATIVE_BITBLT: |
454 |
|
dg.gen_load_T0_GPR(3); |
455 |
|
dg.gen_invoke_T0((void (*)(uint32))NQD_bitblt); |
594 |
|
void sheepshaver_cpu::interrupt(uint32 entry) |
595 |
|
{ |
596 |
|
#if EMUL_TIME_STATS |
597 |
< |
interrupt_count++; |
597 |
> |
ppc_interrupt_count++; |
598 |
|
const clock_t interrupt_start = clock(); |
599 |
|
#endif |
600 |
|
|
880 |
|
* Initialize CPU emulation |
881 |
|
*/ |
882 |
|
|
883 |
< |
static sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction) |
883 |
> |
sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction) |
884 |
|
{ |
885 |
|
#if ENABLE_VOSF |
886 |
|
// Handle screen fault |
900 |
|
const uint32 pc = cpu->pc(); |
901 |
|
|
902 |
|
// Fault in Mac ROM or RAM? |
903 |
< |
bool mac_fault = (pc >= ROM_BASE) && (pc < (ROM_BASE + ROM_AREA_SIZE)) || (pc >= RAMBase) && (pc < (RAMBase + RAMSize)); |
903 |
> |
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)); |
904 |
|
if (mac_fault) { |
905 |
|
|
906 |
|
// "VM settings" during MacOS 8 installation |
920 |
|
return SIGSEGV_RETURN_SKIP_INSTRUCTION; |
921 |
|
else if (pc == ROM_BASE + 0x4a10a0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000)) |
922 |
|
return SIGSEGV_RETURN_SKIP_INSTRUCTION; |
923 |
+ |
|
924 |
+ |
// MacOS 8.6 serial drivers on startup (with DR Cache and OldWorld ROM) |
925 |
+ |
else if ((pc - DR_CACHE_BASE) < DR_CACHE_SIZE && (cpu->gpr(16) == 0xf3012002 || cpu->gpr(16) == 0xf3012000)) |
926 |
+ |
return SIGSEGV_RETURN_SKIP_INSTRUCTION; |
927 |
+ |
else if ((pc - DR_CACHE_BASE) < DR_CACHE_SIZE && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000)) |
928 |
+ |
return SIGSEGV_RETURN_SKIP_INSTRUCTION; |
929 |
|
|
930 |
|
// Ignore writes to the zero page |
931 |
|
else if ((uint32)(addr - SheepMem::ZeroPage()) < (uint32)SheepMem::PageSize()) |
958 |
|
ppc_cpu->set_register(powerpc_registers::GPR(4), any_register(KernelDataAddr + 0x1000)); |
959 |
|
WriteMacInt32(XLM_RUN_MODE, MODE_68K); |
960 |
|
|
957 |
– |
// Install the handler for SIGSEGV |
958 |
– |
sigsegv_install_handler(sigsegv_handler); |
959 |
– |
|
961 |
|
#if ENABLE_MON |
962 |
|
// Install "regs" command in cxmon |
963 |
|
mon_add_command("regs", dump_registers, "regs Dump PowerPC registers\n"); |
983 |
|
printf("Total emulation time : %.1f sec\n", double(emul_time) / double(CLOCKS_PER_SEC)); |
984 |
|
printf("Total interrupt count: %d (%2.1f Hz)\n", interrupt_count, |
985 |
|
(double(interrupt_count) * CLOCKS_PER_SEC) / double(emul_time)); |
986 |
+ |
printf("Total ppc interrupt count: %d (%2.1f %%)\n", ppc_interrupt_count, |
987 |
+ |
(double(ppc_interrupt_count) * 100.0) / double(interrupt_count)); |
988 |
|
|
989 |
|
#define PRINT_STATS(LABEL, VAR_PREFIX) do { \ |
990 |
|
printf("Total " LABEL " count : %d\n", VAR_PREFIX##_count); \ |
1060 |
|
|
1061 |
|
void sheepshaver_cpu::handle_interrupt(void) |
1062 |
|
{ |
1063 |
< |
// Do nothing if interrupts are disabled |
1064 |
< |
if (*(int32 *)XLM_IRQ_NEST > 0) |
1065 |
< |
return; |
1063 |
> |
#ifdef USE_SDL_VIDEO |
1064 |
> |
// We must fill in the events queue in the same thread that did call SDL_SetVideoMode() |
1065 |
> |
SDL_PumpEvents(); |
1066 |
> |
#endif |
1067 |
|
|
1068 |
< |
// Do nothing if there is no interrupt pending |
1069 |
< |
if (InterruptFlags == 0) |
1068 |
> |
// Do nothing if interrupts are disabled |
1069 |
> |
if (int32(ReadMacInt32(XLM_IRQ_NEST)) > 0) |
1070 |
|
return; |
1071 |
|
|
1072 |
|
// Current interrupt nest level |
1073 |
|
static int interrupt_depth = 0; |
1074 |
|
++interrupt_depth; |
1075 |
+ |
#if EMUL_TIME_STATS |
1076 |
+ |
interrupt_count++; |
1077 |
+ |
#endif |
1078 |
|
|
1079 |
|
// Disable MacOS stack sniffer |
1080 |
|
WriteMacInt32(0x110, 0); |
1114 |
|
// 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0 |
1115 |
|
if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) { |
1116 |
|
interrupt_context ctx(this, "68k mode"); |
1117 |
+ |
#if EMUL_TIME_STATS |
1118 |
+ |
const clock_t interrupt_start = clock(); |
1119 |
+ |
#endif |
1120 |
|
#if 1 |
1121 |
|
// Execute full 68k interrupt routine |
1122 |
|
M68kRegisters r; |
1142 |
|
} |
1143 |
|
} |
1144 |
|
#endif |
1145 |
+ |
#if EMUL_TIME_STATS |
1146 |
+ |
interrupt_time += (clock() - interrupt_start); |
1147 |
+ |
#endif |
1148 |
|
} |
1149 |
|
break; |
1150 |
|
#endif |
1264 |
|
get_resource_callbacks[selector - NATIVE_GET_RESOURCE](); |
1265 |
|
break; |
1266 |
|
} |
1254 |
– |
case NATIVE_DISABLE_INTERRUPT: |
1255 |
– |
DisableInterrupt(); |
1256 |
– |
break; |
1257 |
– |
case NATIVE_ENABLE_INTERRUPT: |
1258 |
– |
EnableInterrupt(); |
1259 |
– |
break; |
1267 |
|
case NATIVE_MAKE_EXECUTABLE: |
1268 |
|
MakeExecutable(0, (void *)gpr(4), gpr(5)); |
1269 |
|
break; |