ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp
Revision: 1.46
Committed: 2004-06-22T17:10:08Z (20 years, 5 months ago) by gbeauche
Branch: MAIN
Changes since 1.45: +1 -15 lines
Log Message:
Don't handle XLM_IRQ_NEST atomically in emulated mode. That's useless since
this variable is modified only within a single thread and interrupts are
not handled asynchronously.

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