ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp
Revision: 1.40
Committed: 2004-05-20T11:47:27Z (20 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.39: +8 -1 lines
Log Message:
Don't allow "recursive" NanoKernel interrupts

File Contents

# Content
1 /*
2 * sheepshaver_glue.cpp - Glue Kheperix CPU to SheepShaver CPU engine interface
3 *
4 * SheepShaver (C) 1997-2004 Christian Bauer and Marc Hellwig
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "sysdeps.h"
22 #include "cpu_emulation.h"
23 #include "main.h"
24 #include "prefs.h"
25 #include "xlowmem.h"
26 #include "emul_op.h"
27 #include "rom_patches.h"
28 #include "macos_util.h"
29 #include "block-alloc.hpp"
30 #include "sigsegv.h"
31 #include "cpu/ppc/ppc-cpu.hpp"
32 #include "cpu/ppc/ppc-operations.hpp"
33 #include "cpu/ppc/ppc-instructions.hpp"
34 #include "thunks.h"
35
36 // Used for NativeOp trampolines
37 #include "video.h"
38 #include "name_registry.h"
39 #include "serial.h"
40 #include "ether.h"
41 #include "timer.h"
42
43 #include <stdio.h>
44 #include <stdlib.h>
45
46 #if ENABLE_MON
47 #include "mon.h"
48 #include "mon_disass.h"
49 #endif
50
51 #define DEBUG 0
52 #include "debug.h"
53
54 // Emulation time statistics
55 #define EMUL_TIME_STATS 1
56
57 #if EMUL_TIME_STATS
58 static clock_t emul_start_time;
59 static uint32 interrupt_count = 0;
60 static clock_t interrupt_time = 0;
61 static uint32 exec68k_count = 0;
62 static clock_t exec68k_time = 0;
63 static uint32 native_exec_count = 0;
64 static clock_t native_exec_time = 0;
65 static uint32 macos_exec_count = 0;
66 static clock_t macos_exec_time = 0;
67 #endif
68
69 static void enter_mon(void)
70 {
71 // Start up mon in real-mode
72 #if ENABLE_MON
73 char *arg[4] = {"mon", "-m", "-r", NULL};
74 mon(3, arg);
75 #endif
76 }
77
78 // From main_*.cpp
79 extern uintptr SignalStackBase();
80
81 // From rsrc_patches.cpp
82 extern "C" void check_load_invoc(uint32 type, int16 id, uint32 h);
83
84 // PowerPC EmulOp to exit from emulation looop
85 const uint32 POWERPC_EXEC_RETURN = POWERPC_EMUL_OP | 1;
86
87 // Enable multicore (main/interrupts) cpu emulation?
88 #define MULTICORE_CPU (ASYNC_IRQ ? 1 : 0)
89
90 // Enable interrupt routine safety checks?
91 #define SAFE_INTERRUPT_PPC 1
92
93 // Enable Execute68k() safety checks?
94 #define SAFE_EXEC_68K 1
95
96 // Save FP state in Execute68k()?
97 #define SAVE_FP_EXEC_68K 1
98
99 // Interrupts in EMUL_OP mode?
100 #define INTERRUPTS_IN_EMUL_OP_MODE 1
101
102 // Interrupts in native mode?
103 #define INTERRUPTS_IN_NATIVE_MODE 1
104
105 // Enable native EMUL_OPs to be run without a mode switch
106 #define ENABLE_NATIVE_EMUL_OP 1
107
108 // Pointer to Kernel Data
109 static KernelData * const kernel_data = (KernelData *)KERNEL_DATA_BASE;
110
111 // SIGSEGV handler
112 static sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t);
113
114 #if PPC_ENABLE_JIT && PPC_REENTRANT_JIT
115 // Special trampolines for EmulOp and NativeOp
116 static uint8 *emul_op_trampoline;
117 static uint8 *native_op_trampoline;
118 #endif
119
120 // JIT Compiler enabled?
121 static inline bool enable_jit_p()
122 {
123 return PrefsFindBool("jit");
124 }
125
126
127 /**
128 * PowerPC emulator glue with special 'sheep' opcodes
129 **/
130
131 enum {
132 PPC_I(SHEEP) = PPC_I(MAX),
133 PPC_I(SHEEP_MAX)
134 };
135
136 class sheepshaver_cpu
137 : public powerpc_cpu
138 {
139 void init_decoder();
140 void execute_sheep(uint32 opcode);
141
142 // Filter out EMUL_OP routines that only call native code
143 bool filter_execute_emul_op(uint32 emul_op);
144
145 // "Native" EMUL_OP routines
146 void execute_emul_op_microseconds();
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
168 sheepshaver_cpu();
169
170 // CR & XER accessors
171 uint32 get_cr() const { return cr().get(); }
172 void set_cr(uint32 v) { cr().set(v); }
173 uint32 get_xer() const { return xer().get(); }
174 void set_xer(uint32 v) { xer().set(v); }
175
176 // Execute NATIVE_OP routine
177 void execute_native_op(uint32 native_op);
178
179 // Execute EMUL_OP routine
180 void execute_emul_op(uint32 emul_op);
181
182 // Execute 68k routine
183 void execute_68k(uint32 entry, M68kRegisters *r);
184
185 // Execute ppc routine
186 void execute_ppc(uint32 entry);
187
188 // Execute MacOS/PPC code
189 uint32 execute_macos_code(uint32 tvect, int nargs, uint32 const *args);
190
191 // Compile one instruction
192 virtual int compile1(codegen_context_t & cg_context);
193
194 // Resource manager thunk
195 void get_resource(uint32 old_get_resource);
196
197 // Handle MacOS interrupt
198 void interrupt(uint32 entry);
199 void handle_interrupt();
200
201 // Make sure the SIGSEGV handler can access CPU registers
202 friend sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t);
203 };
204
205 // Memory allocator returning areas aligned on 16-byte boundaries
206 void *operator new(size_t size)
207 {
208 void *p;
209
210 #if defined(HAVE_POSIX_MEMALIGN)
211 if (posix_memalign(&p, 16, size) != 0)
212 throw std::bad_alloc();
213 #elif defined(HAVE_MEMALIGN)
214 p = memalign(16, size);
215 #elif defined(HAVE_VALLOC)
216 p = valloc(size); // page-aligned!
217 #else
218 /* XXX: handle padding ourselves */
219 p = malloc(size);
220 #endif
221
222 return p;
223 }
224
225 void operator delete(void *p)
226 {
227 #if defined(HAVE_MEMALIGN) || defined(HAVE_VALLOC)
228 #if defined(__GLIBC__)
229 // this is known to work only with GNU libc
230 free(p);
231 #endif
232 #else
233 free(p);
234 #endif
235 }
236
237 sheepshaver_cpu::sheepshaver_cpu()
238 : powerpc_cpu(enable_jit_p())
239 {
240 init_decoder();
241 }
242
243 void sheepshaver_cpu::init_decoder()
244 {
245 static const instr_info_t sheep_ii_table[] = {
246 { "sheep",
247 (execute_pmf)&sheepshaver_cpu::execute_sheep,
248 NULL,
249 PPC_I(SHEEP),
250 D_form, 6, 0, CFLOW_JUMP | CFLOW_TRAP
251 }
252 };
253
254 const int ii_count = sizeof(sheep_ii_table)/sizeof(sheep_ii_table[0]);
255 D(bug("SheepShaver extra decode table has %d entries\n", ii_count));
256
257 for (int i = 0; i < ii_count; i++) {
258 const instr_info_t * ii = &sheep_ii_table[i];
259 init_decoder_entry(ii);
260 }
261 }
262
263 /* NativeOp instruction format:
264 +------------+-------------------------+--+-----------+------------+
265 | 6 | |FN| OP | 2 |
266 +------------+-------------------------+--+-----------+------------+
267 0 5 |6 18 19 20 25 26 31
268 */
269
270 typedef bit_field< 19, 19 > FN_field;
271 typedef bit_field< 20, 25 > NATIVE_OP_field;
272 typedef bit_field< 26, 31 > EMUL_OP_field;
273
274 // "Native" EMUL_OP routines
275 #define GPR_A(REG) gpr(16 + (REG))
276 #define GPR_D(REG) gpr( 8 + (REG))
277
278 void sheepshaver_cpu::execute_emul_op_microseconds()
279 {
280 Microseconds(GPR_A(0), GPR_D(0));
281 }
282
283 void sheepshaver_cpu::execute_emul_op_idle_time_1()
284 {
285 // Sleep if no events pending
286 if (ReadMacInt32(0x14c) == 0)
287 Delay_usec(16667);
288 GPR_A(0) = ReadMacInt32(0x2b6);
289 }
290
291 void sheepshaver_cpu::execute_emul_op_idle_time_2()
292 {
293 // Sleep if no events pending
294 if (ReadMacInt32(0x14c) == 0)
295 Delay_usec(16667);
296 GPR_D(0) = (uint32)-2;
297 }
298
299 // Filter out EMUL_OP routines that only call native code
300 bool sheepshaver_cpu::filter_execute_emul_op(uint32 emul_op)
301 {
302 switch (emul_op) {
303 case OP_MICROSECONDS:
304 execute_emul_op_microseconds();
305 return true;
306 case OP_IDLE_TIME:
307 execute_emul_op_idle_time_1();
308 return true;
309 case OP_IDLE_TIME_2:
310 execute_emul_op_idle_time_2();
311 return true;
312 }
313 return false;
314 }
315
316 // Execute EMUL_OP routine
317 void sheepshaver_cpu::execute_emul_op(uint32 emul_op)
318 {
319 #if ENABLE_NATIVE_EMUL_OP
320 // First, filter out EMUL_OPs that can be executed without a mode switch
321 if (filter_execute_emul_op(emul_op))
322 return;
323 #endif
324
325 M68kRegisters r68;
326 WriteMacInt32(XLM_68K_R25, gpr(25));
327 WriteMacInt32(XLM_RUN_MODE, MODE_EMUL_OP);
328 for (int i = 0; i < 8; i++)
329 r68.d[i] = gpr(8 + i);
330 for (int i = 0; i < 7; i++)
331 r68.a[i] = gpr(16 + i);
332 r68.a[7] = gpr(1);
333 uint32 saved_cr = get_cr() & CR_field<2>::mask();
334 uint32 saved_xer = get_xer();
335 EmulOp(&r68, gpr(24), emul_op);
336 set_cr(saved_cr);
337 set_xer(saved_xer);
338 for (int i = 0; i < 8; i++)
339 gpr(8 + i) = r68.d[i];
340 for (int i = 0; i < 7; i++)
341 gpr(16 + i) = r68.a[i];
342 gpr(1) = r68.a[7];
343 WriteMacInt32(XLM_RUN_MODE, MODE_68K);
344 }
345
346 // Execute SheepShaver instruction
347 void sheepshaver_cpu::execute_sheep(uint32 opcode)
348 {
349 // D(bug("Extended opcode %08x at %08x (68k pc %08x)\n", opcode, pc(), gpr(24)));
350 assert((((opcode >> 26) & 0x3f) == 6) && OP_MAX <= 64 + 3);
351
352 switch (opcode & 0x3f) {
353 case 0: // EMUL_RETURN
354 QuitEmulator();
355 break;
356
357 case 1: // EXEC_RETURN
358 spcflags().set(SPCFLAG_CPU_EXEC_RETURN);
359 break;
360
361 case 2: // EXEC_NATIVE
362 execute_native_op(NATIVE_OP_field::extract(opcode));
363 if (FN_field::test(opcode))
364 pc() = lr();
365 else
366 pc() += 4;
367 break;
368
369 default: // EMUL_OP
370 execute_emul_op(EMUL_OP_field::extract(opcode) - 3);
371 pc() += 4;
372 break;
373 }
374 }
375
376 // Compile one instruction
377 int sheepshaver_cpu::compile1(codegen_context_t & cg_context)
378 {
379 #if PPC_ENABLE_JIT
380 const instr_info_t *ii = cg_context.instr_info;
381 if (ii->mnemo != PPC_I(SHEEP))
382 return COMPILE_FAILURE;
383
384 int status = COMPILE_FAILURE;
385 powerpc_dyngen & dg = cg_context.codegen;
386 uint32 opcode = cg_context.opcode;
387
388 switch (opcode & 0x3f) {
389 case 0: // EMUL_RETURN
390 dg.gen_invoke(QuitEmulator);
391 status = COMPILE_CODE_OK;
392 break;
393
394 case 1: // EXEC_RETURN
395 dg.gen_spcflags_set(SPCFLAG_CPU_EXEC_RETURN);
396 // Don't check for pending interrupts, we do know we have to
397 // get out of this block ASAP
398 dg.gen_exec_return();
399 status = COMPILE_EPILOGUE_OK;
400 break;
401
402 case 2: { // EXEC_NATIVE
403 uint32 selector = NATIVE_OP_field::extract(opcode);
404 switch (selector) {
405 #if !PPC_REENTRANT_JIT
406 // Filter out functions that may invoke Execute68k() or
407 // CallMacOS(), this would break reentrancy as they could
408 // invalidate the translation cache and even overwrite
409 // continuation code when we are done with them.
410 case NATIVE_PATCH_NAME_REGISTRY:
411 dg.gen_invoke(DoPatchNameRegistry);
412 status = COMPILE_CODE_OK;
413 break;
414 case NATIVE_VIDEO_INSTALL_ACCEL:
415 dg.gen_invoke(VideoInstallAccel);
416 status = COMPILE_CODE_OK;
417 break;
418 case NATIVE_VIDEO_VBL:
419 dg.gen_invoke(VideoVBL);
420 status = COMPILE_CODE_OK;
421 break;
422 case NATIVE_GET_RESOURCE:
423 case NATIVE_GET_1_RESOURCE:
424 case NATIVE_GET_IND_RESOURCE:
425 case NATIVE_GET_1_IND_RESOURCE:
426 case NATIVE_R_GET_RESOURCE: {
427 static const uint32 get_resource_ptr[] = {
428 XLM_GET_RESOURCE,
429 XLM_GET_1_RESOURCE,
430 XLM_GET_IND_RESOURCE,
431 XLM_GET_1_IND_RESOURCE,
432 XLM_R_GET_RESOURCE
433 };
434 uint32 old_get_resource = ReadMacInt32(get_resource_ptr[selector - NATIVE_GET_RESOURCE]);
435 typedef void (*func_t)(dyngen_cpu_base, uint32);
436 func_t func = (func_t)nv_mem_fun(&sheepshaver_cpu::get_resource).ptr();
437 dg.gen_invoke_CPU_im(func, old_get_resource);
438 status = COMPILE_CODE_OK;
439 break;
440 }
441 case NATIVE_CHECK_LOAD_INVOC:
442 dg.gen_load_T0_GPR(3);
443 dg.gen_load_T1_GPR(4);
444 dg.gen_se_16_32_T1();
445 dg.gen_load_T2_GPR(5);
446 dg.gen_invoke_T0_T1_T2((void (*)(uint32, uint32, uint32))check_load_invoc);
447 status = COMPILE_CODE_OK;
448 break;
449 #endif
450 case NATIVE_DISABLE_INTERRUPT:
451 dg.gen_invoke(DisableInterrupt);
452 status = COMPILE_CODE_OK;
453 break;
454 case NATIVE_ENABLE_INTERRUPT:
455 dg.gen_invoke(EnableInterrupt);
456 status = COMPILE_CODE_OK;
457 break;
458 case NATIVE_BITBLT:
459 dg.gen_load_T0_GPR(3);
460 dg.gen_invoke_T0((void (*)(uint32))NQD_bitblt);
461 status = COMPILE_CODE_OK;
462 break;
463 case NATIVE_INVRECT:
464 dg.gen_load_T0_GPR(3);
465 dg.gen_invoke_T0((void (*)(uint32))NQD_invrect);
466 status = COMPILE_CODE_OK;
467 break;
468 case NATIVE_FILLRECT:
469 dg.gen_load_T0_GPR(3);
470 dg.gen_invoke_T0((void (*)(uint32))NQD_fillrect);
471 status = COMPILE_CODE_OK;
472 break;
473 }
474 // Could we fully translate this NativeOp?
475 if (FN_field::test(opcode)) {
476 if (status != COMPILE_FAILURE) {
477 dg.gen_load_A0_LR();
478 dg.gen_set_PC_A0();
479 }
480 cg_context.done_compile = true;
481 break;
482 }
483 else if (status != COMPILE_FAILURE) {
484 cg_context.done_compile = false;
485 break;
486 }
487 #if PPC_REENTRANT_JIT
488 // Try to execute NativeOp trampoline
489 dg.gen_set_PC_im(cg_context.pc + 4);
490 dg.gen_mov_32_T0_im(selector);
491 dg.gen_jmp(native_op_trampoline);
492 cg_context.done_compile = true;
493 status = COMPILE_EPILOGUE_OK;
494 break;
495 #endif
496 // Invoke NativeOp handler
497 typedef void (*func_t)(dyngen_cpu_base, uint32);
498 func_t func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_native_op).ptr();
499 dg.gen_invoke_CPU_im(func, selector);
500 cg_context.done_compile = false;
501 status = COMPILE_CODE_OK;
502 break;
503 }
504
505 default: { // EMUL_OP
506 uint32 emul_op = EMUL_OP_field::extract(opcode) - 3;
507 #if ENABLE_NATIVE_EMUL_OP
508 typedef void (*emul_op_func_t)(dyngen_cpu_base);
509 emul_op_func_t emul_op_func = 0;
510 switch (emul_op) {
511 case OP_MICROSECONDS:
512 emul_op_func = (emul_op_func_t)nv_mem_fun(&sheepshaver_cpu::execute_emul_op_microseconds).ptr();
513 break;
514 case OP_IDLE_TIME:
515 emul_op_func = (emul_op_func_t)nv_mem_fun(&sheepshaver_cpu::execute_emul_op_idle_time_1).ptr();
516 break;
517 case OP_IDLE_TIME_2:
518 emul_op_func = (emul_op_func_t)nv_mem_fun(&sheepshaver_cpu::execute_emul_op_idle_time_2).ptr();
519 break;
520 }
521 if (emul_op_func) {
522 dg.gen_invoke_CPU(emul_op_func);
523 cg_context.done_compile = false;
524 status = COMPILE_CODE_OK;
525 break;
526 }
527 #endif
528 #if PPC_REENTRANT_JIT
529 // Try to execute EmulOp trampoline
530 dg.gen_set_PC_im(cg_context.pc + 4);
531 dg.gen_mov_32_T0_im(emul_op);
532 dg.gen_jmp(emul_op_trampoline);
533 cg_context.done_compile = true;
534 status = COMPILE_EPILOGUE_OK;
535 break;
536 #endif
537 // Invoke EmulOp handler
538 typedef void (*func_t)(dyngen_cpu_base, uint32);
539 func_t func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_emul_op).ptr();
540 dg.gen_invoke_CPU_im(func, emul_op);
541 cg_context.done_compile = false;
542 status = COMPILE_CODE_OK;
543 break;
544 }
545 }
546 return status;
547 #endif
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 {
594 #if EMUL_TIME_STATS
595 interrupt_count++;
596 const clock_t interrupt_start = clock();
597 #endif
598
599 #if SAFE_INTERRUPT_PPC
600 static int depth = 0;
601 if (depth != 0)
602 printf("FATAL: sheepshaver_cpu::interrupt() called more than once: %d\n", depth);
603 depth++;
604 #endif
605
606 #if !MULTICORE_CPU
607 // Save program counters and branch registers
608 uint32 saved_pc = pc();
609 uint32 saved_lr = lr();
610 uint32 saved_ctr= ctr();
611 uint32 saved_sp = gpr(1);
612 #endif
613
614 // Initialize stack pointer to SheepShaver alternate stack base
615 gpr(1) = SignalStackBase() - 64;
616
617 // Build trampoline to return from interrupt
618 SheepVar32 trampoline = POWERPC_EXEC_RETURN;
619
620 // Prepare registers for nanokernel interrupt routine
621 kernel_data->v[0x004 >> 2] = htonl(gpr(1));
622 kernel_data->v[0x018 >> 2] = htonl(gpr(6));
623
624 gpr(6) = ntohl(kernel_data->v[0x65c >> 2]);
625 assert(gpr(6) != 0);
626 WriteMacInt32(gpr(6) + 0x13c, gpr(7));
627 WriteMacInt32(gpr(6) + 0x144, gpr(8));
628 WriteMacInt32(gpr(6) + 0x14c, gpr(9));
629 WriteMacInt32(gpr(6) + 0x154, gpr(10));
630 WriteMacInt32(gpr(6) + 0x15c, gpr(11));
631 WriteMacInt32(gpr(6) + 0x164, gpr(12));
632 WriteMacInt32(gpr(6) + 0x16c, gpr(13));
633
634 gpr(1) = KernelDataAddr;
635 gpr(7) = ntohl(kernel_data->v[0x660 >> 2]);
636 gpr(8) = 0;
637 gpr(10) = trampoline.addr();
638 gpr(12) = trampoline.addr();
639 gpr(13) = get_cr();
640
641 // rlwimi. r7,r7,8,0,0
642 uint32 result = op_ppc_rlwimi::apply(gpr(7), 8, 0x80000000, gpr(7));
643 record_cr0(result);
644 gpr(7) = result;
645
646 gpr(11) = 0xf072; // MSR (SRR1)
647 cr().set((gpr(11) & 0x0fff0000) | (get_cr() & ~0x0fff0000));
648
649 // Enter nanokernel
650 execute(entry);
651
652 #if !MULTICORE_CPU
653 // Restore program counters and branch registers
654 pc() = saved_pc;
655 lr() = saved_lr;
656 ctr()= saved_ctr;
657 gpr(1) = saved_sp;
658 #endif
659
660 #if EMUL_TIME_STATS
661 interrupt_time += (clock() - interrupt_start);
662 #endif
663
664 #if SAFE_INTERRUPT_PPC
665 depth--;
666 #endif
667 }
668
669 // Execute 68k routine
670 void sheepshaver_cpu::execute_68k(uint32 entry, M68kRegisters *r)
671 {
672 #if EMUL_TIME_STATS
673 exec68k_count++;
674 const clock_t exec68k_start = clock();
675 #endif
676
677 #if SAFE_EXEC_68K
678 if (ReadMacInt32(XLM_RUN_MODE) != MODE_EMUL_OP)
679 printf("FATAL: Execute68k() not called from EMUL_OP mode\n");
680 #endif
681
682 // Save program counters and branch registers
683 uint32 saved_pc = pc();
684 uint32 saved_lr = lr();
685 uint32 saved_ctr= ctr();
686 uint32 saved_cr = get_cr();
687
688 // Create MacOS stack frame
689 // FIXME: make sure MacOS doesn't expect PPC registers to live on top
690 uint32 sp = gpr(1);
691 gpr(1) -= 56;
692 WriteMacInt32(gpr(1), sp);
693
694 // Save PowerPC registers
695 uint32 saved_GPRs[19];
696 memcpy(&saved_GPRs[0], &gpr(13), sizeof(uint32)*(32-13));
697 #if SAVE_FP_EXEC_68K
698 double saved_FPRs[18];
699 memcpy(&saved_FPRs[0], &fpr(14), sizeof(double)*(32-14));
700 #endif
701
702 // Setup registers for 68k emulator
703 cr().set(CR_SO_field<2>::mask()); // Supervisor mode
704 for (int i = 0; i < 8; i++) // d[0]..d[7]
705 gpr(8 + i) = r->d[i];
706 for (int i = 0; i < 7; i++) // a[0]..a[6]
707 gpr(16 + i) = r->a[i];
708 gpr(23) = 0;
709 gpr(24) = entry;
710 gpr(25) = ReadMacInt32(XLM_68K_R25); // MSB of SR
711 gpr(26) = 0;
712 gpr(28) = 0; // VBR
713 gpr(29) = ntohl(kernel_data->ed.v[0x74 >> 2]); // Pointer to opcode table
714 gpr(30) = ntohl(kernel_data->ed.v[0x78 >> 2]); // Address of emulator
715 gpr(31) = KernelDataAddr + 0x1000;
716
717 // Push return address (points to EXEC_RETURN opcode) on stack
718 gpr(1) -= 4;
719 WriteMacInt32(gpr(1), XLM_EXEC_RETURN_OPCODE);
720
721 // Rentering 68k emulator
722 WriteMacInt32(XLM_RUN_MODE, MODE_68K);
723
724 // Set r0 to 0 for 68k emulator
725 gpr(0) = 0;
726
727 // Execute 68k opcode
728 uint32 opcode = ReadMacInt16(gpr(24));
729 gpr(27) = (int32)(int16)ReadMacInt16(gpr(24) += 2);
730 gpr(29) += opcode * 8;
731 execute(gpr(29));
732
733 // Save r25 (contains current 68k interrupt level)
734 WriteMacInt32(XLM_68K_R25, gpr(25));
735
736 // Reentering EMUL_OP mode
737 WriteMacInt32(XLM_RUN_MODE, MODE_EMUL_OP);
738
739 // Save 68k registers
740 for (int i = 0; i < 8; i++) // d[0]..d[7]
741 r->d[i] = gpr(8 + i);
742 for (int i = 0; i < 7; i++) // a[0]..a[6]
743 r->a[i] = gpr(16 + i);
744
745 // Restore PowerPC registers
746 memcpy(&gpr(13), &saved_GPRs[0], sizeof(uint32)*(32-13));
747 #if SAVE_FP_EXEC_68K
748 memcpy(&fpr(14), &saved_FPRs[0], sizeof(double)*(32-14));
749 #endif
750
751 // Cleanup stack
752 gpr(1) += 56;
753
754 // Restore program counters and branch registers
755 pc() = saved_pc;
756 lr() = saved_lr;
757 ctr()= saved_ctr;
758 set_cr(saved_cr);
759
760 #if EMUL_TIME_STATS
761 exec68k_time += (clock() - exec68k_start);
762 #endif
763 }
764
765 // Call MacOS PPC code
766 uint32 sheepshaver_cpu::execute_macos_code(uint32 tvect, int nargs, uint32 const *args)
767 {
768 #if EMUL_TIME_STATS
769 macos_exec_count++;
770 const clock_t macos_exec_start = clock();
771 #endif
772
773 // Save program counters and branch registers
774 uint32 saved_pc = pc();
775 uint32 saved_lr = lr();
776 uint32 saved_ctr= ctr();
777
778 // Build trampoline with EXEC_RETURN
779 SheepVar32 trampoline = POWERPC_EXEC_RETURN;
780 lr() = trampoline.addr();
781
782 gpr(1) -= 64; // Create stack frame
783 uint32 proc = ReadMacInt32(tvect); // Get routine address
784 uint32 toc = ReadMacInt32(tvect + 4); // Get TOC pointer
785
786 // Save PowerPC registers
787 uint32 regs[8];
788 regs[0] = gpr(2);
789 for (int i = 0; i < nargs; i++)
790 regs[i + 1] = gpr(i + 3);
791
792 // Prepare and call MacOS routine
793 gpr(2) = toc;
794 for (int i = 0; i < nargs; i++)
795 gpr(i + 3) = args[i];
796 execute(proc);
797 uint32 retval = gpr(3);
798
799 // Restore PowerPC registers
800 for (int i = 0; i <= nargs; i++)
801 gpr(i + 2) = regs[i];
802
803 // Cleanup stack
804 gpr(1) += 64;
805
806 // Restore program counters and branch registers
807 pc() = saved_pc;
808 lr() = saved_lr;
809 ctr()= saved_ctr;
810
811 #if EMUL_TIME_STATS
812 macos_exec_time += (clock() - macos_exec_start);
813 #endif
814
815 return retval;
816 }
817
818 // Execute ppc routine
819 inline void sheepshaver_cpu::execute_ppc(uint32 entry)
820 {
821 // Save branch registers
822 uint32 saved_lr = lr();
823
824 SheepVar32 trampoline = POWERPC_EXEC_RETURN;
825 WriteMacInt32(trampoline.addr(), POWERPC_EXEC_RETURN);
826 lr() = trampoline.addr();
827
828 execute(entry);
829
830 // Restore branch registers
831 lr() = saved_lr;
832 }
833
834 // Resource Manager thunk
835 inline void sheepshaver_cpu::get_resource(uint32 old_get_resource)
836 {
837 uint32 type = gpr(3);
838 int16 id = gpr(4);
839
840 // Create stack frame
841 gpr(1) -= 56;
842
843 // Call old routine
844 execute_ppc(old_get_resource);
845
846 // Call CheckLoad()
847 uint32 handle = gpr(3);
848 check_load_invoc(type, id, handle);
849 gpr(3) = handle;
850
851 // Cleanup stack
852 gpr(1) += 56;
853 }
854
855
856 /**
857 * SheepShaver CPU engine interface
858 **/
859
860 static sheepshaver_cpu *main_cpu = NULL; // CPU emulator to handle usual control flow
861 static sheepshaver_cpu *interrupt_cpu = NULL; // CPU emulator to handle interrupts
862 static sheepshaver_cpu *current_cpu = NULL; // Current CPU emulator context
863
864 void FlushCodeCache(uintptr start, uintptr end)
865 {
866 D(bug("FlushCodeCache(%08x, %08x)\n", start, end));
867 main_cpu->invalidate_cache_range(start, end);
868 #if MULTICORE_CPU
869 interrupt_cpu->invalidate_cache_range(start, end);
870 #endif
871 }
872
873 static inline void cpu_push(sheepshaver_cpu *new_cpu)
874 {
875 #if MULTICORE_CPU
876 current_cpu = new_cpu;
877 #endif
878 }
879
880 static inline void cpu_pop()
881 {
882 #if MULTICORE_CPU
883 current_cpu = main_cpu;
884 #endif
885 }
886
887 // Dump PPC registers
888 static void dump_registers(void)
889 {
890 current_cpu->dump_registers();
891 }
892
893 // Dump log
894 static void dump_log(void)
895 {
896 current_cpu->dump_log();
897 }
898
899 /*
900 * Initialize CPU emulation
901 */
902
903 static sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
904 {
905 #if ENABLE_VOSF
906 // Handle screen fault
907 extern bool Screen_fault_handler(sigsegv_address_t, sigsegv_address_t);
908 if (Screen_fault_handler(fault_address, fault_instruction))
909 return SIGSEGV_RETURN_SUCCESS;
910 #endif
911
912 const uintptr addr = (uintptr)fault_address;
913 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
914 // Ignore writes to ROM
915 if ((addr - ROM_BASE) < ROM_SIZE)
916 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
917
918 // Get program counter of target CPU
919 sheepshaver_cpu * const cpu = current_cpu;
920 const uint32 pc = cpu->pc();
921
922 // Fault in Mac ROM or RAM?
923 bool mac_fault = (pc >= ROM_BASE) && (pc < (ROM_BASE + ROM_AREA_SIZE)) || (pc >= RAMBase) && (pc < (RAMBase + RAMSize));
924 if (mac_fault) {
925
926 // "VM settings" during MacOS 8 installation
927 if (pc == ROM_BASE + 0x488160 && cpu->gpr(20) == 0xf8000000)
928 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
929
930 // MacOS 8.5 installation
931 else if (pc == ROM_BASE + 0x488140 && cpu->gpr(16) == 0xf8000000)
932 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
933
934 // MacOS 8 serial drivers on startup
935 else if (pc == ROM_BASE + 0x48e080 && (cpu->gpr(8) == 0xf3012002 || cpu->gpr(8) == 0xf3012000))
936 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
937
938 // MacOS 8.1 serial drivers on startup
939 else if (pc == ROM_BASE + 0x48c5e0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000))
940 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
941 else if (pc == ROM_BASE + 0x4a10a0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000))
942 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
943
944 // Ignore writes to the zero page
945 else if ((uint32)(addr - SheepMem::ZeroPage()) < (uint32)SheepMem::PageSize())
946 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
947
948 // Ignore all other faults, if requested
949 if (PrefsFindBool("ignoresegv"))
950 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
951 }
952 #else
953 #error "FIXME: You don't have the capability to skip instruction within signal handlers"
954 #endif
955
956 printf("SIGSEGV\n");
957 printf(" pc %p\n", fault_instruction);
958 printf(" ea %p\n", fault_address);
959 printf(" cpu %s\n", current_cpu == main_cpu ? "main" : "interrupts");
960 dump_registers();
961 current_cpu->dump_log();
962 enter_mon();
963 QuitEmulator();
964
965 return SIGSEGV_RETURN_FAILURE;
966 }
967
968 void init_emul_ppc(void)
969 {
970 // Initialize main CPU emulator
971 main_cpu = new sheepshaver_cpu();
972 main_cpu->set_register(powerpc_registers::GPR(3), any_register((uint32)ROM_BASE + 0x30d000));
973 main_cpu->set_register(powerpc_registers::GPR(4), any_register(KernelDataAddr + 0x1000));
974 WriteMacInt32(XLM_RUN_MODE, MODE_68K);
975
976 #if MULTICORE_CPU
977 // Initialize alternate CPU emulator to handle interrupts
978 interrupt_cpu = new sheepshaver_cpu();
979 #endif
980
981 // Install the handler for SIGSEGV
982 sigsegv_install_handler(sigsegv_handler);
983
984 #if ENABLE_MON
985 // Install "regs" command in cxmon
986 mon_add_command("regs", dump_registers, "regs Dump PowerPC registers\n");
987 mon_add_command("log", dump_log, "log Dump PowerPC emulation log\n");
988 #endif
989
990 #if EMUL_TIME_STATS
991 emul_start_time = clock();
992 #endif
993 }
994
995 /*
996 * Deinitialize emulation
997 */
998
999 void exit_emul_ppc(void)
1000 {
1001 #if EMUL_TIME_STATS
1002 clock_t emul_end_time = clock();
1003
1004 printf("### Statistics for SheepShaver emulation parts\n");
1005 const clock_t emul_time = emul_end_time - emul_start_time;
1006 printf("Total emulation time : %.1f sec\n", double(emul_time) / double(CLOCKS_PER_SEC));
1007 printf("Total interrupt count: %d (%2.1f Hz)\n", interrupt_count,
1008 (double(interrupt_count) * CLOCKS_PER_SEC) / double(emul_time));
1009
1010 #define PRINT_STATS(LABEL, VAR_PREFIX) do { \
1011 printf("Total " LABEL " count : %d\n", VAR_PREFIX##_count); \
1012 printf("Total " LABEL " time : %.1f sec (%.1f%%)\n", \
1013 double(VAR_PREFIX##_time) / double(CLOCKS_PER_SEC), \
1014 100.0 * double(VAR_PREFIX##_time) / double(emul_time)); \
1015 } while (0)
1016
1017 PRINT_STATS("Execute68k[Trap] execution", exec68k);
1018 PRINT_STATS("NativeOp execution", native_exec);
1019 PRINT_STATS("MacOS routine execution", macos_exec);
1020
1021 #undef PRINT_STATS
1022 printf("\n");
1023 #endif
1024
1025 delete main_cpu;
1026 #if MULTICORE_CPU
1027 delete interrupt_cpu;
1028 #endif
1029 }
1030
1031 #if PPC_ENABLE_JIT && PPC_REENTRANT_JIT
1032 // Initialize EmulOp trampolines
1033 void init_emul_op_trampolines(basic_dyngen & dg)
1034 {
1035 typedef void (*func_t)(dyngen_cpu_base, uint32);
1036 func_t func;
1037
1038 // EmulOp
1039 emul_op_trampoline = dg.gen_start();
1040 func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_emul_op).ptr();
1041 dg.gen_invoke_CPU_T0(func);
1042 dg.gen_exec_return();
1043 dg.gen_end();
1044
1045 // NativeOp
1046 native_op_trampoline = dg.gen_start();
1047 func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_native_op).ptr();
1048 dg.gen_invoke_CPU_T0(func);
1049 dg.gen_exec_return();
1050 dg.gen_end();
1051
1052 D(bug("EmulOp trampoline: %p\n", emul_op_trampoline));
1053 D(bug("NativeOp trampoline: %p\n", native_op_trampoline));
1054 }
1055 #endif
1056
1057 /*
1058 * Emulation loop
1059 */
1060
1061 void emul_ppc(uint32 entry)
1062 {
1063 current_cpu = main_cpu;
1064 #if 0
1065 current_cpu->start_log();
1066 #endif
1067 // start emulation loop and enable code translation or caching
1068 current_cpu->execute(entry);
1069 }
1070
1071 /*
1072 * Handle PowerPC interrupt
1073 */
1074
1075 #if ASYNC_IRQ
1076 void HandleInterrupt(void)
1077 {
1078 main_cpu->handle_interrupt();
1079 }
1080 #else
1081 void TriggerInterrupt(void)
1082 {
1083 #if 0
1084 WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
1085 #else
1086 // Trigger interrupt to main cpu only
1087 if (main_cpu)
1088 main_cpu->trigger_interrupt();
1089 #endif
1090 }
1091 #endif
1092
1093 void sheepshaver_cpu::handle_interrupt(void)
1094 {
1095 // Do nothing if interrupts are disabled
1096 if (*(int32 *)XLM_IRQ_NEST > 0)
1097 return;
1098
1099 // Do nothing if there is no interrupt pending
1100 if (InterruptFlags == 0)
1101 return;
1102
1103 // Current interrupt nest level
1104 static int interrupt_depth = 0;
1105 ++interrupt_depth;
1106
1107 // Disable MacOS stack sniffer
1108 WriteMacInt32(0x110, 0);
1109
1110 // Interrupt action depends on current run mode
1111 switch (ReadMacInt32(XLM_RUN_MODE)) {
1112 case MODE_68K:
1113 // 68k emulator active, trigger 68k interrupt level 1
1114 assert(current_cpu == main_cpu);
1115 WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
1116 set_cr(get_cr() | tswap32(kernel_data->v[0x674 >> 2]));
1117 break;
1118
1119 #if INTERRUPTS_IN_NATIVE_MODE
1120 case MODE_NATIVE:
1121 // 68k emulator inactive, in nanokernel?
1122 assert(current_cpu == main_cpu);
1123 if (gpr(1) != KernelDataAddr && interrupt_depth == 1) {
1124 interrupt_context ctx(this, "PowerPC mode");
1125
1126 // Prepare for 68k interrupt level 1
1127 WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
1128 WriteMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc,
1129 ReadMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc)
1130 | tswap32(kernel_data->v[0x674 >> 2]));
1131
1132 // Execute nanokernel interrupt routine (this will activate the 68k emulator)
1133 DisableInterrupt();
1134 cpu_push(interrupt_cpu);
1135 if (ROMType == ROMTYPE_NEWWORLD)
1136 current_cpu->interrupt(ROM_BASE + 0x312b1c);
1137 else
1138 current_cpu->interrupt(ROM_BASE + 0x312a3c);
1139 cpu_pop();
1140 }
1141 break;
1142 #endif
1143
1144 #if INTERRUPTS_IN_EMUL_OP_MODE
1145 case MODE_EMUL_OP:
1146 // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
1147 if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) {
1148 interrupt_context ctx(this, "68k mode");
1149 #if 1
1150 // Execute full 68k interrupt routine
1151 M68kRegisters r;
1152 uint32 old_r25 = ReadMacInt32(XLM_68K_R25); // Save interrupt level
1153 WriteMacInt32(XLM_68K_R25, 0x21); // Execute with interrupt level 1
1154 static const uint8 proc[] = {
1155 0x3f, 0x3c, 0x00, 0x00, // move.w #$0000,-(sp) (fake format word)
1156 0x48, 0x7a, 0x00, 0x0a, // pea @1(pc) (return address)
1157 0x40, 0xe7, // move sr,-(sp) (saved SR)
1158 0x20, 0x78, 0x00, 0x064, // move.l $64,a0
1159 0x4e, 0xd0, // jmp (a0)
1160 M68K_RTS >> 8, M68K_RTS & 0xff // @1
1161 };
1162 Execute68k((uint32)proc, &r);
1163 WriteMacInt32(XLM_68K_R25, old_r25); // Restore interrupt level
1164 #else
1165 // Only update cursor
1166 if (HasMacStarted()) {
1167 if (InterruptFlags & INTFLAG_VIA) {
1168 ClearInterruptFlag(INTFLAG_VIA);
1169 ADBInterrupt();
1170 ExecuteNative(NATIVE_VIDEO_VBL);
1171 }
1172 }
1173 #endif
1174 }
1175 break;
1176 #endif
1177 }
1178
1179 // We are done with this interrupt
1180 --interrupt_depth;
1181 }
1182
1183 static void get_resource(void);
1184 static void get_1_resource(void);
1185 static void get_ind_resource(void);
1186 static void get_1_ind_resource(void);
1187 static void r_get_resource(void);
1188
1189 // Execute NATIVE_OP routine
1190 void sheepshaver_cpu::execute_native_op(uint32 selector)
1191 {
1192 #if EMUL_TIME_STATS
1193 native_exec_count++;
1194 const clock_t native_exec_start = clock();
1195 #endif
1196
1197 switch (selector) {
1198 case NATIVE_PATCH_NAME_REGISTRY:
1199 DoPatchNameRegistry();
1200 break;
1201 case NATIVE_VIDEO_INSTALL_ACCEL:
1202 VideoInstallAccel();
1203 break;
1204 case NATIVE_VIDEO_VBL:
1205 VideoVBL();
1206 break;
1207 case NATIVE_VIDEO_DO_DRIVER_IO:
1208 gpr(3) = (int32)(int16)VideoDoDriverIO((void *)gpr(3), (void *)gpr(4),
1209 (void *)gpr(5), gpr(6), gpr(7));
1210 break;
1211 #ifdef WORDS_BIGENDIAN
1212 case NATIVE_ETHER_IRQ:
1213 EtherIRQ();
1214 break;
1215 case NATIVE_ETHER_INIT:
1216 gpr(3) = InitStreamModule((void *)gpr(3));
1217 break;
1218 case NATIVE_ETHER_TERM:
1219 TerminateStreamModule();
1220 break;
1221 case NATIVE_ETHER_OPEN:
1222 gpr(3) = ether_open((queue_t *)gpr(3), (void *)gpr(4), gpr(5), gpr(6), (void*)gpr(7));
1223 break;
1224 case NATIVE_ETHER_CLOSE:
1225 gpr(3) = ether_close((queue_t *)gpr(3), gpr(4), (void *)gpr(5));
1226 break;
1227 case NATIVE_ETHER_WPUT:
1228 gpr(3) = ether_wput((queue_t *)gpr(3), (mblk_t *)gpr(4));
1229 break;
1230 case NATIVE_ETHER_RSRV:
1231 gpr(3) = ether_rsrv((queue_t *)gpr(3));
1232 break;
1233 #else
1234 case NATIVE_ETHER_INIT:
1235 // FIXME: needs more complicated thunks
1236 gpr(3) = false;
1237 break;
1238 #endif
1239 case NATIVE_SYNC_HOOK:
1240 gpr(3) = NQD_sync_hook(gpr(3));
1241 break;
1242 case NATIVE_BITBLT_HOOK:
1243 gpr(3) = NQD_bitblt_hook(gpr(3));
1244 break;
1245 case NATIVE_BITBLT:
1246 NQD_bitblt(gpr(3));
1247 break;
1248 case NATIVE_FILLRECT_HOOK:
1249 gpr(3) = NQD_fillrect_hook(gpr(3));
1250 break;
1251 case NATIVE_INVRECT:
1252 NQD_invrect(gpr(3));
1253 break;
1254 case NATIVE_FILLRECT:
1255 NQD_fillrect(gpr(3));
1256 break;
1257 case NATIVE_SERIAL_NOTHING:
1258 case NATIVE_SERIAL_OPEN:
1259 case NATIVE_SERIAL_PRIME_IN:
1260 case NATIVE_SERIAL_PRIME_OUT:
1261 case NATIVE_SERIAL_CONTROL:
1262 case NATIVE_SERIAL_STATUS:
1263 case NATIVE_SERIAL_CLOSE: {
1264 typedef int16 (*SerialCallback)(uint32, uint32);
1265 static const SerialCallback serial_callbacks[] = {
1266 SerialNothing,
1267 SerialOpen,
1268 SerialPrimeIn,
1269 SerialPrimeOut,
1270 SerialControl,
1271 SerialStatus,
1272 SerialClose
1273 };
1274 gpr(3) = serial_callbacks[selector - NATIVE_SERIAL_NOTHING](gpr(3), gpr(4));
1275 break;
1276 }
1277 case NATIVE_GET_RESOURCE:
1278 case NATIVE_GET_1_RESOURCE:
1279 case NATIVE_GET_IND_RESOURCE:
1280 case NATIVE_GET_1_IND_RESOURCE:
1281 case NATIVE_R_GET_RESOURCE: {
1282 typedef void (*GetResourceCallback)(void);
1283 static const GetResourceCallback get_resource_callbacks[] = {
1284 ::get_resource,
1285 ::get_1_resource,
1286 ::get_ind_resource,
1287 ::get_1_ind_resource,
1288 ::r_get_resource
1289 };
1290 get_resource_callbacks[selector - NATIVE_GET_RESOURCE]();
1291 break;
1292 }
1293 case NATIVE_DISABLE_INTERRUPT:
1294 DisableInterrupt();
1295 break;
1296 case NATIVE_ENABLE_INTERRUPT:
1297 EnableInterrupt();
1298 break;
1299 case NATIVE_MAKE_EXECUTABLE:
1300 MakeExecutable(0, (void *)gpr(4), gpr(5));
1301 break;
1302 case NATIVE_CHECK_LOAD_INVOC:
1303 check_load_invoc(gpr(3), gpr(4), gpr(5));
1304 break;
1305 default:
1306 printf("FATAL: NATIVE_OP called with bogus selector %d\n", selector);
1307 QuitEmulator();
1308 break;
1309 }
1310
1311 #if EMUL_TIME_STATS
1312 native_exec_time += (clock() - native_exec_start);
1313 #endif
1314 }
1315
1316 /*
1317 * Execute 68k subroutine (must be ended with EXEC_RETURN)
1318 * This must only be called by the emul_thread when in EMUL_OP mode
1319 * r->a[7] is unused, the routine runs on the caller's stack
1320 */
1321
1322 void Execute68k(uint32 pc, M68kRegisters *r)
1323 {
1324 current_cpu->execute_68k(pc, r);
1325 }
1326
1327 /*
1328 * Execute 68k A-Trap from EMUL_OP routine
1329 * r->a[7] is unused, the routine runs on the caller's stack
1330 */
1331
1332 void Execute68kTrap(uint16 trap, M68kRegisters *r)
1333 {
1334 SheepVar proc_var(4);
1335 uint32 proc = proc_var.addr();
1336 WriteMacInt16(proc, trap);
1337 WriteMacInt16(proc + 2, M68K_RTS);
1338 Execute68k(proc, r);
1339 }
1340
1341 /*
1342 * Call MacOS PPC code
1343 */
1344
1345 uint32 call_macos(uint32 tvect)
1346 {
1347 return current_cpu->execute_macos_code(tvect, 0, NULL);
1348 }
1349
1350 uint32 call_macos1(uint32 tvect, uint32 arg1)
1351 {
1352 const uint32 args[] = { arg1 };
1353 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1354 }
1355
1356 uint32 call_macos2(uint32 tvect, uint32 arg1, uint32 arg2)
1357 {
1358 const uint32 args[] = { arg1, arg2 };
1359 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1360 }
1361
1362 uint32 call_macos3(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3)
1363 {
1364 const uint32 args[] = { arg1, arg2, arg3 };
1365 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1366 }
1367
1368 uint32 call_macos4(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4)
1369 {
1370 const uint32 args[] = { arg1, arg2, arg3, arg4 };
1371 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1372 }
1373
1374 uint32 call_macos5(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5)
1375 {
1376 const uint32 args[] = { arg1, arg2, arg3, arg4, arg5 };
1377 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1378 }
1379
1380 uint32 call_macos6(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6)
1381 {
1382 const uint32 args[] = { arg1, arg2, arg3, arg4, arg5, arg6 };
1383 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1384 }
1385
1386 uint32 call_macos7(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6, uint32 arg7)
1387 {
1388 const uint32 args[] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7 };
1389 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1390 }
1391
1392 /*
1393 * Resource Manager thunks
1394 */
1395
1396 void get_resource(void)
1397 {
1398 current_cpu->get_resource(ReadMacInt32(XLM_GET_RESOURCE));
1399 }
1400
1401 void get_1_resource(void)
1402 {
1403 current_cpu->get_resource(ReadMacInt32(XLM_GET_1_RESOURCE));
1404 }
1405
1406 void get_ind_resource(void)
1407 {
1408 current_cpu->get_resource(ReadMacInt32(XLM_GET_IND_RESOURCE));
1409 }
1410
1411 void get_1_ind_resource(void)
1412 {
1413 current_cpu->get_resource(ReadMacInt32(XLM_GET_1_IND_RESOURCE));
1414 }
1415
1416 void r_get_resource(void)
1417 {
1418 current_cpu->get_resource(ReadMacInt32(XLM_R_GET_RESOURCE));
1419 }