147 |
|
void execute_emul_op_idle_time_1(); |
148 |
|
void execute_emul_op_idle_time_2(); |
149 |
|
|
150 |
+ |
// CPU context to preserve on interrupt |
151 |
+ |
class interrupt_context { |
152 |
+ |
uint32 gpr[32]; |
153 |
+ |
uint32 pc; |
154 |
+ |
uint32 lr; |
155 |
+ |
uint32 ctr; |
156 |
+ |
uint32 cr; |
157 |
+ |
uint32 xer; |
158 |
+ |
sheepshaver_cpu *cpu; |
159 |
+ |
const char *where; |
160 |
+ |
public: |
161 |
+ |
interrupt_context(sheepshaver_cpu *_cpu, const char *_where); |
162 |
+ |
~interrupt_context(); |
163 |
+ |
}; |
164 |
+ |
|
165 |
|
public: |
166 |
|
|
167 |
|
// Constructor |
548 |
|
return COMPILE_FAILURE; |
549 |
|
} |
550 |
|
|
551 |
+ |
// CPU context to preserve on interrupt |
552 |
+ |
sheepshaver_cpu::interrupt_context::interrupt_context(sheepshaver_cpu *_cpu, const char *_where) |
553 |
+ |
{ |
554 |
+ |
#if SAFE_INTERRUPT_PPC >= 2 |
555 |
+ |
cpu = _cpu; |
556 |
+ |
where = _where; |
557 |
+ |
|
558 |
+ |
// Save interrupt context |
559 |
+ |
memcpy(&gpr[0], &cpu->gpr(0), sizeof(gpr)); |
560 |
+ |
pc = cpu->pc(); |
561 |
+ |
lr = cpu->lr(); |
562 |
+ |
ctr = cpu->ctr(); |
563 |
+ |
cr = cpu->get_cr(); |
564 |
+ |
xer = cpu->get_xer(); |
565 |
+ |
#endif |
566 |
+ |
} |
567 |
+ |
|
568 |
+ |
sheepshaver_cpu::interrupt_context::~interrupt_context() |
569 |
+ |
{ |
570 |
+ |
#if SAFE_INTERRUPT_PPC >= 2 |
571 |
+ |
// Check whether CPU context was preserved by interrupt |
572 |
+ |
if (memcmp(&gpr[0], &cpu->gpr(0), sizeof(gpr)) != 0) { |
573 |
+ |
printf("FATAL: %s: interrupt clobbers registers\n", where); |
574 |
+ |
for (int i = 0; i < 32; i++) |
575 |
+ |
if (gpr[i] != cpu->gpr(i)) |
576 |
+ |
printf(" r%d: %08x -> %08x\n", i, gpr[i], cpu->gpr(i)); |
577 |
+ |
} |
578 |
+ |
if (pc != cpu->pc()) |
579 |
+ |
printf("FATAL: %s: interrupt clobbers PC\n", where); |
580 |
+ |
if (lr != cpu->lr()) |
581 |
+ |
printf("FATAL: %s: interrupt clobbers LR\n", where); |
582 |
+ |
if (ctr != cpu->ctr()) |
583 |
+ |
printf("FATAL: %s: interrupt clobbers CTR\n", where); |
584 |
+ |
if (cr != cpu->get_cr()) |
585 |
+ |
printf("FATAL: %s: interrupt clobbers CR\n", where); |
586 |
+ |
if (xer != cpu->get_xer()) |
587 |
+ |
printf("FATAL: %s: interrupt clobbers XER\n", where); |
588 |
+ |
#endif |
589 |
+ |
} |
590 |
+ |
|
591 |
|
// Handle MacOS interrupt |
592 |
|
void sheepshaver_cpu::interrupt(uint32 entry) |
593 |
|
{ |
602 |
|
printf("FATAL: sheepshaver_cpu::interrupt() called more than once: %d\n", depth); |
603 |
|
depth++; |
604 |
|
#endif |
550 |
– |
#if SAFE_INTERRUPT_PPC >= 2 |
551 |
– |
uint32 saved_regs[32]; |
552 |
– |
memcpy(&saved_regs[0], &gpr(0), sizeof(saved_regs)); |
553 |
– |
#endif |
605 |
|
|
606 |
|
#if !MULTICORE_CPU |
607 |
|
// Save program counters and branch registers |
661 |
|
interrupt_time += (clock() - interrupt_start); |
662 |
|
#endif |
663 |
|
|
613 |
– |
#if SAFE_INTERRUPT_PPC >= 2 |
614 |
– |
if (memcmp(&saved_regs[0], &gpr(0), sizeof(saved_regs)) != 0) |
615 |
– |
printf("FATAL: dirty PowerPC registers\n"); |
616 |
– |
#endif |
664 |
|
#if SAFE_INTERRUPT_PPC |
665 |
|
depth--; |
666 |
|
#endif |
1117 |
|
// 68k emulator inactive, in nanokernel? |
1118 |
|
assert(current_cpu == main_cpu); |
1119 |
|
if (gpr(1) != KernelDataAddr) { |
1120 |
+ |
interrupt_context ctx(this, "PowerPC mode"); |
1121 |
+ |
|
1122 |
|
// Prepare for 68k interrupt level 1 |
1123 |
|
WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1); |
1124 |
|
WriteMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc, |
1141 |
|
case MODE_EMUL_OP: |
1142 |
|
// 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0 |
1143 |
|
if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) { |
1144 |
+ |
interrupt_context ctx(this, "68k mode"); |
1145 |
|
#if 1 |
1146 |
|
// Execute full 68k interrupt routine |
1147 |
|
M68kRegisters r; |