ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp
Revision: 1.57
Committed: 2005-01-30T21:48:21Z (19 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.56: +1 -1 lines
Log Message:
Happy New Year 2005!

File Contents

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