ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp
Revision: 1.6
Committed: 2003-10-11T09:33:27Z (20 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.5: +10 -12 lines
Log Message:
- Minor optimization to execute_ppc() as we apparently don't need to move
  target PC into CTR.
- Fix breakage introduced during little endian fixing. We now assume that
  MacOS doesn't rely on any PPC register that may have been saved on top
  of it stack. i.e. register state is saved onto native stack.

File Contents

# Content
1 /*
2 * sheepshaver_glue.cpp - Glue Kheperix CPU to SheepShaver CPU engine interface
3 *
4 * SheepShaver (C) 1997-2002 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 "spcflags.h"
32 #include "cpu/ppc/ppc-cpu.hpp"
33 #include "cpu/ppc/ppc-operations.hpp"
34
35 // Used for NativeOp trampolines
36 #include "video.h"
37 #include "name_registry.h"
38 #include "serial.h"
39
40 #include <stdio.h>
41
42 #if ENABLE_MON
43 #include "mon.h"
44 #include "mon_disass.h"
45 #endif
46
47 #define DEBUG 1
48 #include "debug.h"
49
50 static void enter_mon(void)
51 {
52 // Start up mon in real-mode
53 #if ENABLE_MON
54 char *arg[4] = {"mon", "-m", "-r", NULL};
55 mon(3, arg);
56 #endif
57 }
58
59 // Enable multicore (main/interrupts) cpu emulation?
60 #define MULTICORE_CPU 0
61
62 // Enable Execute68k() safety checks?
63 #define SAFE_EXEC_68K 1
64
65 // Save FP state in Execute68k()?
66 #define SAVE_FP_EXEC_68K 1
67
68 // Interrupts in EMUL_OP mode?
69 #define INTERRUPTS_IN_EMUL_OP_MODE 1
70
71 // Interrupts in native mode?
72 #define INTERRUPTS_IN_NATIVE_MODE 1
73
74 // Pointer to Kernel Data
75 static KernelData * const kernel_data = (KernelData *)KERNEL_DATA_BASE;
76
77
78 /**
79 * PowerPC emulator glue with special 'sheep' opcodes
80 **/
81
82 struct sheepshaver_exec_return { };
83
84 class sheepshaver_cpu
85 : public powerpc_cpu
86 {
87 void init_decoder();
88 void execute_sheep(uint32 opcode);
89
90 public:
91
92 sheepshaver_cpu()
93 : powerpc_cpu()
94 { init_decoder(); }
95
96 // Condition Register accessors
97 uint32 get_cr() const { return cr().get(); }
98 void set_cr(uint32 v) { cr().set(v); }
99
100 // Execution loop
101 void execute(uint32 pc);
102
103 // Execute 68k routine
104 void execute_68k(uint32 entry, M68kRegisters *r);
105
106 // Execute ppc routine
107 void execute_ppc(uint32 entry);
108
109 // Execute MacOS/PPC code
110 uint32 execute_macos_code(uint32 tvect, int nargs, uint32 const *args);
111
112 // Resource manager thunk
113 void get_resource(uint32 old_get_resource);
114
115 // Handle MacOS interrupt
116 void interrupt(uint32 entry);
117
118 // spcflags for interrupts handling
119 static uint32 spcflags;
120
121 // Lazy memory allocator (one item at a time)
122 void *operator new(size_t size)
123 { return allocator_helper< sheepshaver_cpu, lazy_allocator >::allocate(); }
124 void operator delete(void *p)
125 { allocator_helper< sheepshaver_cpu, lazy_allocator >::deallocate(p); }
126 // FIXME: really make surre array allocation fail at link time?
127 void *operator new[](size_t);
128 void operator delete[](void *p);
129 };
130
131 uint32 sheepshaver_cpu::spcflags = 0;
132 lazy_allocator< sheepshaver_cpu > allocator_helper< sheepshaver_cpu, lazy_allocator >::allocator;
133
134 void sheepshaver_cpu::init_decoder()
135 {
136 #ifndef PPC_NO_STATIC_II_INDEX_TABLE
137 static bool initialized = false;
138 if (initialized)
139 return;
140 initialized = true;
141 #endif
142
143 static const instr_info_t sheep_ii_table[] = {
144 { "sheep",
145 (execute_fn)&sheepshaver_cpu::execute_sheep,
146 NULL,
147 D_form, 6, 0, CFLOW_TRAP
148 }
149 };
150
151 const int ii_count = sizeof(sheep_ii_table)/sizeof(sheep_ii_table[0]);
152 D(bug("SheepShaver extra decode table has %d entries\n", ii_count));
153
154 for (int i = 0; i < ii_count; i++) {
155 const instr_info_t * ii = &sheep_ii_table[i];
156 init_decoder_entry(ii);
157 }
158 }
159
160 // Forward declaration for native opcode handler
161 static void NativeOp(int selector);
162
163 /* NativeOp instruction format:
164 +------------+--------------------------+--+----------+------------+
165 | 6 | |FN| OP | 2 |
166 +------------+--------------------------+--+----------+------------+
167 0 5 |6 19 20 21 25 26 31
168 */
169
170 typedef bit_field< 20, 20 > FN_field;
171 typedef bit_field< 21, 25 > NATIVE_OP_field;
172 typedef bit_field< 26, 31 > EMUL_OP_field;
173
174 // Execute SheepShaver instruction
175 void sheepshaver_cpu::execute_sheep(uint32 opcode)
176 {
177 // D(bug("Extended opcode %08x at %08x (68k pc %08x)\n", opcode, pc(), gpr(24)));
178 assert((((opcode >> 26) & 0x3f) == 6) && OP_MAX <= 64 + 3);
179
180 switch (opcode & 0x3f) {
181 case 0: // EMUL_RETURN
182 QuitEmulator();
183 break;
184
185 case 1: // EXEC_RETURN
186 throw sheepshaver_exec_return();
187 break;
188
189 case 2: // EXEC_NATIVE
190 NativeOp(NATIVE_OP_field::extract(opcode));
191 if (FN_field::test(opcode))
192 pc() = lr();
193 else
194 pc() += 4;
195 break;
196
197 default: { // EMUL_OP
198 M68kRegisters r68;
199 WriteMacInt32(XLM_68K_R25, gpr(25));
200 WriteMacInt32(XLM_RUN_MODE, MODE_EMUL_OP);
201 for (int i = 0; i < 8; i++)
202 r68.d[i] = gpr(8 + i);
203 for (int i = 0; i < 7; i++)
204 r68.a[i] = gpr(16 + i);
205 r68.a[7] = gpr(1);
206 EmulOp(&r68, gpr(24), EMUL_OP_field::extract(opcode) - 3);
207 for (int i = 0; i < 8; i++)
208 gpr(8 + i) = r68.d[i];
209 for (int i = 0; i < 7; i++)
210 gpr(16 + i) = r68.a[i];
211 gpr(1) = r68.a[7];
212 WriteMacInt32(XLM_RUN_MODE, MODE_68K);
213 pc() += 4;
214 break;
215 }
216 }
217 }
218
219 // Checks for pending interrupts
220 struct execute_nothing {
221 static inline void execute(powerpc_cpu *) { }
222 };
223
224 struct execute_spcflags_check {
225 static inline void execute(powerpc_cpu *cpu) {
226 #if !ASYNC_IRQ
227 if (SPCFLAGS_TEST(SPCFLAG_ALL_BUT_EXEC_RETURN)) {
228 if (SPCFLAGS_TEST( SPCFLAG_ENTER_MON )) {
229 SPCFLAGS_CLEAR( SPCFLAG_ENTER_MON );
230 enter_mon();
231 }
232 if (SPCFLAGS_TEST( SPCFLAG_DOINT )) {
233 SPCFLAGS_CLEAR( SPCFLAG_DOINT );
234 HandleInterrupt();
235 }
236 if (SPCFLAGS_TEST( SPCFLAG_INT )) {
237 SPCFLAGS_CLEAR( SPCFLAG_INT );
238 SPCFLAGS_SET( SPCFLAG_DOINT );
239 }
240 }
241 #endif
242 }
243 };
244
245 // Execution loop
246 void sheepshaver_cpu::execute(uint32 entry)
247 {
248 try {
249 pc() = entry;
250 powerpc_cpu::do_execute<execute_nothing, execute_spcflags_check>();
251 }
252 catch (sheepshaver_exec_return const &) {
253 // Nothing, simply return
254 }
255 catch (...) {
256 printf("ERROR: execute() received an unknown exception!\n");
257 QuitEmulator();
258 }
259 }
260
261 // Handle MacOS interrupt
262 void sheepshaver_cpu::interrupt(uint32 entry)
263 {
264 #if !MULTICORE_CPU
265 // Save program counters and branch registers
266 uint32 saved_pc = pc();
267 uint32 saved_lr = lr();
268 uint32 saved_ctr= ctr();
269 uint32 saved_sp = gpr(1);
270 #endif
271
272 // Initialize stack pointer to SheepShaver alternate stack base
273 gpr(1) = SheepStack1Base - 64;
274
275 // Build trampoline to return from interrupt
276 uint32 trampoline[] = { htonl(POWERPC_EMUL_OP | 1) };
277
278 // Prepare registers for nanokernel interrupt routine
279 kernel_data->v[0x004 >> 2] = htonl(gpr(1));
280 kernel_data->v[0x018 >> 2] = htonl(gpr(6));
281
282 gpr(6) = ntohl(kernel_data->v[0x65c >> 2]);
283 assert(gpr(6) != 0);
284 WriteMacInt32(gpr(6) + 0x13c, gpr(7));
285 WriteMacInt32(gpr(6) + 0x144, gpr(8));
286 WriteMacInt32(gpr(6) + 0x14c, gpr(9));
287 WriteMacInt32(gpr(6) + 0x154, gpr(10));
288 WriteMacInt32(gpr(6) + 0x15c, gpr(11));
289 WriteMacInt32(gpr(6) + 0x164, gpr(12));
290 WriteMacInt32(gpr(6) + 0x16c, gpr(13));
291
292 gpr(1) = KernelDataAddr;
293 gpr(7) = ntohl(kernel_data->v[0x660 >> 2]);
294 gpr(8) = 0;
295 gpr(10) = (uint32)trampoline;
296 gpr(12) = (uint32)trampoline;
297 gpr(13) = cr().get();
298
299 // rlwimi. r7,r7,8,0,0
300 uint32 result = op_ppc_rlwimi::apply(gpr(7), 8, 0x80000000, gpr(7));
301 record_cr0(result);
302 gpr(7) = result;
303
304 gpr(11) = 0xf072; // MSR (SRR1)
305 cr().set((gpr(11) & 0x0fff0000) | (cr().get() & ~0x0fff0000));
306
307 // Enter nanokernel
308 execute(entry);
309
310 #if !MULTICORE_CPU
311 // Restore program counters and branch registers
312 pc() = saved_pc;
313 lr() = saved_lr;
314 ctr()= saved_ctr;
315 gpr(1) = saved_sp;
316 #endif
317 }
318
319 // Execute 68k routine
320 void sheepshaver_cpu::execute_68k(uint32 entry, M68kRegisters *r)
321 {
322 #if SAFE_EXEC_68K
323 if (ReadMacInt32(XLM_RUN_MODE) != MODE_EMUL_OP)
324 printf("FATAL: Execute68k() not called from EMUL_OP mode\n");
325 #endif
326
327 // Save program counters and branch registers
328 uint32 saved_pc = pc();
329 uint32 saved_lr = lr();
330 uint32 saved_ctr= ctr();
331
332 // Create MacOS stack frame
333 // FIXME: make sure MacOS doesn't expect PPC registers to live on top
334 uint32 sp = gpr(1);
335 gpr(1) -= 56;
336 WriteMacInt32(gpr(1), sp);
337
338 // Save PowerPC registers
339 uint32 saved_GPRs[19];
340 memcpy(&saved_GPRs[0], &gpr(13), sizeof(uint32)*(32-13));
341 #if SAVE_FP_EXEC_68K
342 double saved_FPRs[18];
343 memcpy(&saved_FPRs[0], &fpr(14), sizeof(double)*(32-14));
344 #endif
345
346 // Setup registers for 68k emulator
347 cr().set(CR_SO_field<2>::mask()); // Supervisor mode
348 for (int i = 0; i < 8; i++) // d[0]..d[7]
349 gpr(8 + i) = r->d[i];
350 for (int i = 0; i < 7; i++) // a[0]..a[6]
351 gpr(16 + i) = r->a[i];
352 gpr(23) = 0;
353 gpr(24) = entry;
354 gpr(25) = ReadMacInt32(XLM_68K_R25); // MSB of SR
355 gpr(26) = 0;
356 gpr(28) = 0; // VBR
357 gpr(29) = ntohl(kernel_data->ed.v[0x74 >> 2]); // Pointer to opcode table
358 gpr(30) = ntohl(kernel_data->ed.v[0x78 >> 2]); // Address of emulator
359 gpr(31) = KernelDataAddr + 0x1000;
360
361 // Push return address (points to EXEC_RETURN opcode) on stack
362 gpr(1) -= 4;
363 WriteMacInt32(gpr(1), XLM_EXEC_RETURN_OPCODE);
364
365 // Rentering 68k emulator
366 WriteMacInt32(XLM_RUN_MODE, MODE_68K);
367
368 // Set r0 to 0 for 68k emulator
369 gpr(0) = 0;
370
371 // Execute 68k opcode
372 uint32 opcode = ReadMacInt16(gpr(24));
373 gpr(27) = (int32)(int16)ReadMacInt16(gpr(24) += 2);
374 gpr(29) += opcode * 8;
375 execute(gpr(29));
376
377 // Save r25 (contains current 68k interrupt level)
378 WriteMacInt32(XLM_68K_R25, gpr(25));
379
380 // Reentering EMUL_OP mode
381 WriteMacInt32(XLM_RUN_MODE, MODE_EMUL_OP);
382
383 // Save 68k registers
384 for (int i = 0; i < 8; i++) // d[0]..d[7]
385 r->d[i] = gpr(8 + i);
386 for (int i = 0; i < 7; i++) // a[0]..a[6]
387 r->a[i] = gpr(16 + i);
388
389 // Restore PowerPC registers
390 memcpy(&gpr(13), &saved_GPRs[0], sizeof(uint32)*(32-13));
391 #if SAVE_FP_EXEC_68K
392 memcpy(&fpr(14), &saved_FPRs[0], sizeof(double)*(32-14));
393 #endif
394
395 // Cleanup stack
396 gpr(1) += 56;
397
398 // Restore program counters and branch registers
399 pc() = saved_pc;
400 lr() = saved_lr;
401 ctr()= saved_ctr;
402 }
403
404 // Call MacOS PPC code
405 uint32 sheepshaver_cpu::execute_macos_code(uint32 tvect, int nargs, uint32 const *args)
406 {
407 // Save program counters and branch registers
408 uint32 saved_pc = pc();
409 uint32 saved_lr = lr();
410 uint32 saved_ctr= ctr();
411
412 // Build trampoline with EXEC_RETURN
413 uint32 trampoline[] = { htonl(POWERPC_EMUL_OP | 1) };
414 lr() = (uint32)trampoline;
415
416 gpr(1) -= 64; // Create stack frame
417 uint32 proc = ReadMacInt32(tvect); // Get routine address
418 uint32 toc = ReadMacInt32(tvect + 4); // Get TOC pointer
419
420 // Save PowerPC registers
421 uint32 regs[8];
422 regs[0] = gpr(2);
423 for (int i = 0; i < nargs; i++)
424 regs[i + 1] = gpr(i + 3);
425
426 // Prepare and call MacOS routine
427 gpr(2) = toc;
428 for (int i = 0; i < nargs; i++)
429 gpr(i + 3) = args[i];
430 execute(proc);
431 uint32 retval = gpr(3);
432
433 // Restore PowerPC registers
434 for (int i = 0; i <= nargs; i++)
435 gpr(i + 2) = regs[i];
436
437 // Cleanup stack
438 gpr(1) += 64;
439
440 // Restore program counters and branch registers
441 pc() = saved_pc;
442 lr() = saved_lr;
443 ctr()= saved_ctr;
444
445 return retval;
446 }
447
448 // Execute ppc routine
449 inline void sheepshaver_cpu::execute_ppc(uint32 entry)
450 {
451 // Save branch registers
452 uint32 saved_lr = lr();
453
454 const uint32 trampoline[] = { htonl(POWERPC_EMUL_OP | 1) };
455 lr() = (uint32)trampoline;
456
457 execute(entry);
458
459 // Restore branch registers
460 lr() = saved_lr;
461 }
462
463 // Resource Manager thunk
464 extern "C" void check_load_invoc(uint32 type, int16 id, uint32 h);
465
466 inline void sheepshaver_cpu::get_resource(uint32 old_get_resource)
467 {
468 uint32 type = gpr(3);
469 int16 id = gpr(4);
470
471 // Create stack frame
472 gpr(1) -= 56;
473
474 // Call old routine
475 execute_ppc(old_get_resource);
476
477 // Call CheckLoad()
478 uint32 handle = gpr(3);
479 check_load_invoc(type, id, handle);
480 gpr(3) = handle;
481
482 // Cleanup stack
483 gpr(1) += 56;
484 }
485
486
487 /**
488 * SheepShaver CPU engine interface
489 **/
490
491 static sheepshaver_cpu *main_cpu = NULL; // CPU emulator to handle usual control flow
492 static sheepshaver_cpu *interrupt_cpu = NULL; // CPU emulator to handle interrupts
493 static sheepshaver_cpu *current_cpu = NULL; // Current CPU emulator context
494
495 static inline void cpu_push(sheepshaver_cpu *new_cpu)
496 {
497 #if MULTICORE_CPU
498 current_cpu = new_cpu;
499 #endif
500 }
501
502 static inline void cpu_pop()
503 {
504 #if MULTICORE_CPU
505 current_cpu = main_cpu;
506 #endif
507 }
508
509 // Dump PPC registers
510 static void dump_registers(void)
511 {
512 current_cpu->dump_registers();
513 }
514
515 // Dump log
516 static void dump_log(void)
517 {
518 current_cpu->dump_log();
519 }
520
521 /*
522 * Initialize CPU emulation
523 */
524
525 static sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
526 {
527 #if ENABLE_VOSF
528 // Handle screen fault
529 extern bool Screen_fault_handler(sigsegv_address_t, sigsegv_address_t);
530 if (Screen_fault_handler(fault_address, fault_instruction))
531 return SIGSEGV_RETURN_SUCCESS;
532 #endif
533
534 const uintptr addr = (uintptr)fault_address;
535 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
536 // Ignore writes to ROM
537 if ((addr - ROM_BASE) < ROM_SIZE)
538 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
539
540 // Ignore all other faults, if requested
541 if (PrefsFindBool("ignoresegv"))
542 return SIGSEGV_RETURN_FAILURE;
543 #else
544 #error "FIXME: You don't have the capability to skip instruction within signal handlers"
545 #endif
546
547 printf("SIGSEGV\n");
548 printf(" pc %p\n", fault_instruction);
549 printf(" ea %p\n", fault_address);
550 printf(" cpu %s\n", current_cpu == main_cpu ? "main" : "interrupts");
551 dump_registers();
552 current_cpu->dump_log();
553 enter_mon();
554 QuitEmulator();
555
556 return SIGSEGV_RETURN_FAILURE;
557 }
558
559 void init_emul_ppc(void)
560 {
561 // Initialize main CPU emulator
562 main_cpu = new sheepshaver_cpu();
563 main_cpu->set_register(powerpc_registers::GPR(3), any_register((uint32)ROM_BASE + 0x30d000));
564 WriteMacInt32(XLM_RUN_MODE, MODE_68K);
565
566 #if MULTICORE_CPU
567 // Initialize alternate CPU emulator to handle interrupts
568 interrupt_cpu = new sheepshaver_cpu();
569 #endif
570
571 // Install the handler for SIGSEGV
572 sigsegv_install_handler(sigsegv_handler);
573
574 #if ENABLE_MON
575 // Install "regs" command in cxmon
576 mon_add_command("regs", dump_registers, "regs Dump PowerPC registers\n");
577 mon_add_command("log", dump_log, "log Dump PowerPC emulation log\n");
578 #endif
579 }
580
581 /*
582 * Emulation loop
583 */
584
585 void emul_ppc(uint32 entry)
586 {
587 current_cpu = main_cpu;
588 current_cpu->start_log();
589 current_cpu->execute(entry);
590 }
591
592 /*
593 * Handle PowerPC interrupt
594 */
595
596 // Atomic operations
597 extern int atomic_add(int *var, int v);
598 extern int atomic_and(int *var, int v);
599 extern int atomic_or(int *var, int v);
600
601 #if !ASYNC_IRQ
602 void TriggerInterrupt(void)
603 {
604 #if 0
605 WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
606 #else
607 SPCFLAGS_SET( SPCFLAG_INT );
608 #endif
609 }
610 #endif
611
612 void HandleInterrupt(void)
613 {
614 // Do nothing if interrupts are disabled
615 if (int32(ReadMacInt32(XLM_IRQ_NEST)) > 0)
616 return;
617
618 // Do nothing if there is no interrupt pending
619 if (InterruptFlags == 0)
620 return;
621
622 // Disable MacOS stack sniffer
623 WriteMacInt32(0x110, 0);
624
625 // Interrupt action depends on current run mode
626 switch (ReadMacInt32(XLM_RUN_MODE)) {
627 case MODE_68K:
628 // 68k emulator active, trigger 68k interrupt level 1
629 assert(current_cpu == main_cpu);
630 WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
631 main_cpu->set_cr(main_cpu->get_cr() | tswap32(kernel_data->v[0x674 >> 2]));
632 break;
633
634 #if INTERRUPTS_IN_NATIVE_MODE
635 case MODE_NATIVE:
636 // 68k emulator inactive, in nanokernel?
637 assert(current_cpu == main_cpu);
638 if (main_cpu->gpr(1) != KernelDataAddr) {
639 // Prepare for 68k interrupt level 1
640 WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
641 WriteMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc,
642 ReadMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc)
643 | tswap32(kernel_data->v[0x674 >> 2]));
644
645 // Execute nanokernel interrupt routine (this will activate the 68k emulator)
646 DisableInterrupt();
647 cpu_push(interrupt_cpu);
648 if (ROMType == ROMTYPE_NEWWORLD)
649 current_cpu->interrupt(ROM_BASE + 0x312b1c);
650 else
651 current_cpu->interrupt(ROM_BASE + 0x312a3c);
652 cpu_pop();
653 }
654 break;
655 #endif
656
657 #if INTERRUPTS_IN_EMUL_OP_MODE
658 case MODE_EMUL_OP:
659 // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
660 if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) {
661 #if 1
662 // Execute full 68k interrupt routine
663 M68kRegisters r;
664 uint32 old_r25 = ReadMacInt32(XLM_68K_R25); // Save interrupt level
665 WriteMacInt32(XLM_68K_R25, 0x21); // Execute with interrupt level 1
666 static const uint8 proc[] = {
667 0x3f, 0x3c, 0x00, 0x00, // move.w #$0000,-(sp) (fake format word)
668 0x48, 0x7a, 0x00, 0x0a, // pea @1(pc) (return address)
669 0x40, 0xe7, // move sr,-(sp) (saved SR)
670 0x20, 0x78, 0x00, 0x064, // move.l $64,a0
671 0x4e, 0xd0, // jmp (a0)
672 M68K_RTS >> 8, M68K_RTS & 0xff // @1
673 };
674 Execute68k((uint32)proc, &r);
675 WriteMacInt32(XLM_68K_R25, old_r25); // Restore interrupt level
676 #else
677 // Only update cursor
678 if (HasMacStarted()) {
679 if (InterruptFlags & INTFLAG_VIA) {
680 ClearInterruptFlag(INTFLAG_VIA);
681 ADBInterrupt();
682 ExecutePPC(VideoVBL);
683 }
684 }
685 #endif
686 }
687 break;
688 #endif
689 }
690 }
691
692 /*
693 * Execute NATIVE_OP opcode (called by PowerPC emulator)
694 */
695
696 #define POWERPC_NATIVE_OP_INIT(LR, OP) \
697 tswap32(POWERPC_EMUL_OP | ((LR) << 11) | (((uint32)OP) << 6) | 2)
698
699 // FIXME: Make sure 32-bit relocations are used
700 const uint32 NativeOpTable[NATIVE_OP_MAX] = {
701 POWERPC_NATIVE_OP_INIT(1, NATIVE_PATCH_NAME_REGISTRY),
702 POWERPC_NATIVE_OP_INIT(1, NATIVE_VIDEO_INSTALL_ACCEL),
703 POWERPC_NATIVE_OP_INIT(1, NATIVE_VIDEO_VBL),
704 POWERPC_NATIVE_OP_INIT(1, NATIVE_VIDEO_DO_DRIVER_IO),
705 POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_IRQ),
706 POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_INIT),
707 POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_TERM),
708 POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_OPEN),
709 POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_CLOSE),
710 POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_WPUT),
711 POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_RSRV),
712 POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_NOTHING),
713 POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_OPEN),
714 POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_PRIME_IN),
715 POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_PRIME_OUT),
716 POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_CONTROL),
717 POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_STATUS),
718 POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_CLOSE),
719 POWERPC_NATIVE_OP_INIT(1, NATIVE_GET_RESOURCE),
720 POWERPC_NATIVE_OP_INIT(1, NATIVE_GET_1_RESOURCE),
721 POWERPC_NATIVE_OP_INIT(1, NATIVE_GET_IND_RESOURCE),
722 POWERPC_NATIVE_OP_INIT(1, NATIVE_GET_1_IND_RESOURCE),
723 POWERPC_NATIVE_OP_INIT(1, NATIVE_R_GET_RESOURCE),
724 POWERPC_NATIVE_OP_INIT(0, NATIVE_DISABLE_INTERRUPT),
725 POWERPC_NATIVE_OP_INIT(0, NATIVE_ENABLE_INTERRUPT),
726 };
727
728 static void get_resource(void);
729 static void get_1_resource(void);
730 static void get_ind_resource(void);
731 static void get_1_ind_resource(void);
732 static void r_get_resource(void);
733
734 #define GPR(REG) current_cpu->gpr(REG)
735
736 static void NativeOp(int selector)
737 {
738 switch (selector) {
739 case NATIVE_PATCH_NAME_REGISTRY:
740 DoPatchNameRegistry();
741 break;
742 case NATIVE_VIDEO_INSTALL_ACCEL:
743 VideoInstallAccel();
744 break;
745 case NATIVE_VIDEO_VBL:
746 VideoVBL();
747 break;
748 case NATIVE_VIDEO_DO_DRIVER_IO:
749 GPR(3) = (int32)(int16)VideoDoDriverIO((void *)GPR(3), (void *)GPR(4),
750 (void *)GPR(5), GPR(6), GPR(7));
751 break;
752 case NATIVE_GET_RESOURCE:
753 get_resource();
754 break;
755 case NATIVE_GET_1_RESOURCE:
756 get_1_resource();
757 break;
758 case NATIVE_GET_IND_RESOURCE:
759 get_ind_resource();
760 break;
761 case NATIVE_GET_1_IND_RESOURCE:
762 get_1_ind_resource();
763 break;
764 case NATIVE_R_GET_RESOURCE:
765 r_get_resource();
766 break;
767 case NATIVE_SERIAL_NOTHING:
768 case NATIVE_SERIAL_OPEN:
769 case NATIVE_SERIAL_PRIME_IN:
770 case NATIVE_SERIAL_PRIME_OUT:
771 case NATIVE_SERIAL_CONTROL:
772 case NATIVE_SERIAL_STATUS:
773 case NATIVE_SERIAL_CLOSE: {
774 typedef int16 (*SerialCallback)(uint32, uint32);
775 static const SerialCallback serial_callbacks[] = {
776 SerialNothing,
777 SerialOpen,
778 SerialPrimeIn,
779 SerialPrimeOut,
780 SerialControl,
781 SerialStatus,
782 SerialClose
783 };
784 GPR(3) = serial_callbacks[selector - NATIVE_SERIAL_NOTHING](GPR(3), GPR(4));
785 break;
786 }
787 case NATIVE_DISABLE_INTERRUPT:
788 DisableInterrupt();
789 break;
790 case NATIVE_ENABLE_INTERRUPT:
791 EnableInterrupt();
792 break;
793 default:
794 printf("FATAL: NATIVE_OP called with bogus selector %d\n", selector);
795 QuitEmulator();
796 break;
797 }
798 }
799
800 /*
801 * Execute native subroutine (LR must contain return address)
802 */
803
804 void ExecuteNative(int selector)
805 {
806 uint32 tvect[2];
807 tvect[0] = tswap32(POWERPC_NATIVE_OP_FUNC(selector));
808 tvect[1] = 0; // Fake TVECT
809 RoutineDescriptor desc = BUILD_PPC_ROUTINE_DESCRIPTOR(0, tvect);
810 M68kRegisters r;
811 Execute68k((uint32)&desc, &r);
812 }
813
814 /*
815 * Execute 68k subroutine (must be ended with EXEC_RETURN)
816 * This must only be called by the emul_thread when in EMUL_OP mode
817 * r->a[7] is unused, the routine runs on the caller's stack
818 */
819
820 void Execute68k(uint32 pc, M68kRegisters *r)
821 {
822 current_cpu->execute_68k(pc, r);
823 }
824
825 /*
826 * Execute 68k A-Trap from EMUL_OP routine
827 * r->a[7] is unused, the routine runs on the caller's stack
828 */
829
830 void Execute68kTrap(uint16 trap, M68kRegisters *r)
831 {
832 uint16 proc[2];
833 proc[0] = htons(trap);
834 proc[1] = htons(M68K_RTS);
835 Execute68k((uint32)proc, r);
836 }
837
838 /*
839 * Call MacOS PPC code
840 */
841
842 uint32 call_macos(uint32 tvect)
843 {
844 return current_cpu->execute_macos_code(tvect, 0, NULL);
845 }
846
847 uint32 call_macos1(uint32 tvect, uint32 arg1)
848 {
849 const uint32 args[] = { arg1 };
850 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
851 }
852
853 uint32 call_macos2(uint32 tvect, uint32 arg1, uint32 arg2)
854 {
855 const uint32 args[] = { arg1, arg2 };
856 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
857 }
858
859 uint32 call_macos3(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3)
860 {
861 const uint32 args[] = { arg1, arg2, arg3 };
862 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
863 }
864
865 uint32 call_macos4(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4)
866 {
867 const uint32 args[] = { arg1, arg2, arg3, arg4 };
868 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
869 }
870
871 uint32 call_macos5(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5)
872 {
873 const uint32 args[] = { arg1, arg2, arg3, arg4, arg5 };
874 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
875 }
876
877 uint32 call_macos6(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6)
878 {
879 const uint32 args[] = { arg1, arg2, arg3, arg4, arg5, arg6 };
880 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
881 }
882
883 uint32 call_macos7(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6, uint32 arg7)
884 {
885 const uint32 args[] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7 };
886 return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
887 }
888
889 /*
890 * Atomic operations
891 */
892
893 int atomic_add(int *var, int v)
894 {
895 int ret = *var;
896 *var += v;
897 return ret;
898 }
899
900 int atomic_and(int *var, int v)
901 {
902 int ret = *var;
903 *var &= v;
904 return ret;
905 }
906
907 int atomic_or(int *var, int v)
908 {
909 int ret = *var;
910 *var |= v;
911 return ret;
912 }
913
914 /*
915 * Resource Manager thunks
916 */
917
918 void get_resource(void)
919 {
920 current_cpu->get_resource(ReadMacInt32(XLM_GET_RESOURCE));
921 }
922
923 void get_1_resource(void)
924 {
925 current_cpu->get_resource(ReadMacInt32(XLM_GET_1_RESOURCE));
926 }
927
928 void get_ind_resource(void)
929 {
930 current_cpu->get_resource(ReadMacInt32(XLM_GET_IND_RESOURCE));
931 }
932
933 void get_1_ind_resource(void)
934 {
935 current_cpu->get_resource(ReadMacInt32(XLM_GET_1_IND_RESOURCE));
936 }
937
938 void r_get_resource(void)
939 {
940 current_cpu->get_resource(ReadMacInt32(XLM_R_GET_RESOURCE));
941 }