ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp
Revision: 1.38
Committed: 2004-05-19T21:23:16Z (20 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.37: +126 -57 lines
Log Message:
Make NativeOp() handler a sheepshaver_cpu handler, thus getting rid of ugly
GPR macro definition.

Make the JIT engine somewhat reentrant. This brings a massive performance
boost for applications that cause many Execute68k(). e.g. audio in PlayerPRO.

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