52 |
|
#include "debug.h" |
53 |
|
|
54 |
|
// Emulation time statistics |
55 |
< |
#define EMUL_TIME_STATS 1 |
55 |
> |
#ifndef EMUL_TIME_STATS |
56 |
> |
#define EMUL_TIME_STATS 0 |
57 |
> |
#endif |
58 |
|
|
59 |
|
#if EMUL_TIME_STATS |
60 |
|
static clock_t emul_start_time; |
61 |
< |
static uint32 interrupt_count = 0; |
61 |
> |
static uint32 interrupt_count = 0, ppc_interrupt_count = 0; |
62 |
|
static clock_t interrupt_time = 0; |
63 |
|
static uint32 exec68k_count = 0; |
64 |
|
static clock_t exec68k_time = 0; |
471 |
|
break; |
472 |
|
} |
473 |
|
// Could we fully translate this NativeOp? |
474 |
< |
if (FN_field::test(opcode)) { |
475 |
< |
if (status != COMPILE_FAILURE) { |
474 |
> |
if (status == COMPILE_CODE_OK) { |
475 |
> |
if (!FN_field::test(opcode)) |
476 |
> |
cg_context.done_compile = false; |
477 |
> |
else { |
478 |
|
dg.gen_load_A0_LR(); |
479 |
|
dg.gen_set_PC_A0(); |
480 |
+ |
cg_context.done_compile = true; |
481 |
|
} |
477 |
– |
cg_context.done_compile = true; |
478 |
– |
break; |
479 |
– |
} |
480 |
– |
else if (status != COMPILE_FAILURE) { |
481 |
– |
cg_context.done_compile = false; |
482 |
|
break; |
483 |
|
} |
484 |
|
#if PPC_REENTRANT_JIT |
485 |
|
// Try to execute NativeOp trampoline |
486 |
< |
dg.gen_set_PC_im(cg_context.pc + 4); |
486 |
> |
if (!FN_field::test(opcode)) |
487 |
> |
dg.gen_set_PC_im(cg_context.pc + 4); |
488 |
> |
else { |
489 |
> |
dg.gen_load_A0_LR(); |
490 |
> |
dg.gen_set_PC_A0(); |
491 |
> |
} |
492 |
|
dg.gen_mov_32_T0_im(selector); |
493 |
|
dg.gen_jmp(native_op_trampoline); |
494 |
|
cg_context.done_compile = true; |
496 |
|
break; |
497 |
|
#endif |
498 |
|
// Invoke NativeOp handler |
499 |
< |
typedef void (*func_t)(dyngen_cpu_base, uint32); |
500 |
< |
func_t func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_native_op).ptr(); |
501 |
< |
dg.gen_invoke_CPU_im(func, selector); |
502 |
< |
cg_context.done_compile = false; |
503 |
< |
status = COMPILE_CODE_OK; |
499 |
> |
if (!FN_field::test(opcode)) { |
500 |
> |
typedef void (*func_t)(dyngen_cpu_base, uint32); |
501 |
> |
func_t func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_native_op).ptr(); |
502 |
> |
dg.gen_invoke_CPU_im(func, selector); |
503 |
> |
cg_context.done_compile = false; |
504 |
> |
status = COMPILE_CODE_OK; |
505 |
> |
} |
506 |
> |
// Otherwise, let it generate a call to execute_sheep() which |
507 |
> |
// will cause necessary updates to the program counter |
508 |
|
break; |
509 |
|
} |
510 |
|
|
598 |
|
void sheepshaver_cpu::interrupt(uint32 entry) |
599 |
|
{ |
600 |
|
#if EMUL_TIME_STATS |
601 |
< |
interrupt_count++; |
601 |
> |
ppc_interrupt_count++; |
602 |
|
const clock_t interrupt_start = clock(); |
603 |
|
#endif |
604 |
|
|
904 |
|
const uint32 pc = cpu->pc(); |
905 |
|
|
906 |
|
// Fault in Mac ROM or RAM? |
907 |
< |
bool mac_fault = (pc >= ROM_BASE) && (pc < (ROM_BASE + ROM_AREA_SIZE)) || (pc >= RAMBase) && (pc < (RAMBase + RAMSize)); |
907 |
> |
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)); |
908 |
|
if (mac_fault) { |
909 |
|
|
910 |
|
// "VM settings" during MacOS 8 installation |
924 |
|
return SIGSEGV_RETURN_SKIP_INSTRUCTION; |
925 |
|
else if (pc == ROM_BASE + 0x4a10a0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000)) |
926 |
|
return SIGSEGV_RETURN_SKIP_INSTRUCTION; |
927 |
+ |
|
928 |
+ |
// MacOS 8.6 serial drivers on startup (with DR Cache and OldWorld ROM) |
929 |
+ |
else if ((pc - DR_CACHE_BASE) < DR_CACHE_SIZE && (cpu->gpr(16) == 0xf3012002 || cpu->gpr(16) == 0xf3012000)) |
930 |
+ |
return SIGSEGV_RETURN_SKIP_INSTRUCTION; |
931 |
+ |
else if ((pc - DR_CACHE_BASE) < DR_CACHE_SIZE && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000)) |
932 |
+ |
return SIGSEGV_RETURN_SKIP_INSTRUCTION; |
933 |
|
|
934 |
|
// Ignore writes to the zero page |
935 |
|
else if ((uint32)(addr - SheepMem::ZeroPage()) < (uint32)SheepMem::PageSize()) |
990 |
|
printf("Total emulation time : %.1f sec\n", double(emul_time) / double(CLOCKS_PER_SEC)); |
991 |
|
printf("Total interrupt count: %d (%2.1f Hz)\n", interrupt_count, |
992 |
|
(double(interrupt_count) * CLOCKS_PER_SEC) / double(emul_time)); |
993 |
+ |
printf("Total ppc interrupt count: %d (%2.1f %%)\n", ppc_interrupt_count, |
994 |
+ |
(double(ppc_interrupt_count) * 100.0) / double(interrupt_count)); |
995 |
|
|
996 |
|
#define PRINT_STATS(LABEL, VAR_PREFIX) do { \ |
997 |
|
printf("Total " LABEL " count : %d\n", VAR_PREFIX##_count); \ |
1071 |
|
if (*(int32 *)XLM_IRQ_NEST > 0) |
1072 |
|
return; |
1073 |
|
|
1057 |
– |
// Do nothing if there is no interrupt pending |
1058 |
– |
if (InterruptFlags == 0) |
1059 |
– |
return; |
1060 |
– |
|
1074 |
|
// Current interrupt nest level |
1075 |
|
static int interrupt_depth = 0; |
1076 |
|
++interrupt_depth; |
1077 |
+ |
#if EMUL_TIME_STATS |
1078 |
+ |
interrupt_count++; |
1079 |
+ |
#endif |
1080 |
|
|
1081 |
|
// Disable MacOS stack sniffer |
1082 |
|
WriteMacInt32(0x110, 0); |
1116 |
|
// 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0 |
1117 |
|
if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) { |
1118 |
|
interrupt_context ctx(this, "68k mode"); |
1119 |
+ |
#if EMUL_TIME_STATS |
1120 |
+ |
const clock_t interrupt_start = clock(); |
1121 |
+ |
#endif |
1122 |
|
#if 1 |
1123 |
|
// Execute full 68k interrupt routine |
1124 |
|
M68kRegisters r; |
1144 |
|
} |
1145 |
|
} |
1146 |
|
#endif |
1147 |
+ |
#if EMUL_TIME_STATS |
1148 |
+ |
interrupt_time += (clock() - interrupt_start); |
1149 |
+ |
#endif |
1150 |
|
} |
1151 |
|
break; |
1152 |
|
#endif |