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 (21 years, 1 month 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

# User Rev Content
1 gbeauche 1.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 gbeauche 1.3 #include "prefs.h"
25 gbeauche 1.1 #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 gbeauche 1.2 #include "spcflags.h"
32 gbeauche 1.1 #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 gbeauche 1.2 // Enable multicore (main/interrupts) cpu emulation?
60     #define MULTICORE_CPU 0
61    
62 gbeauche 1.1 // 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 gbeauche 1.4 static KernelData * const kernel_data = (KernelData *)KERNEL_DATA_BASE;
76 gbeauche 1.1
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 gbeauche 1.2 // Execute ppc routine
107     void execute_ppc(uint32 entry);
108    
109 gbeauche 1.1 // 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 gbeauche 1.4 void interrupt(uint32 entry);
117 gbeauche 1.2
118     // spcflags for interrupts handling
119     static uint32 spcflags;
120 gbeauche 1.1
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 gbeauche 1.2 uint32 sheepshaver_cpu::spcflags = 0;
132 gbeauche 1.1 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 gbeauche 1.2 /* 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 gbeauche 1.1 // 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 gbeauche 1.2 NativeOp(NATIVE_OP_field::extract(opcode));
191     if (FN_field::test(opcode))
192     pc() = lr();
193     else
194     pc() += 4;
195 gbeauche 1.1 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 gbeauche 1.2 EmulOp(&r68, gpr(24), EMUL_OP_field::extract(opcode) - 3);
207 gbeauche 1.1 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 gbeauche 1.2 // 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 gbeauche 1.4 #if !ASYNC_IRQ
227 gbeauche 1.2 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 gbeauche 1.4 #endif
242 gbeauche 1.2 }
243     };
244    
245 gbeauche 1.1 // Execution loop
246     void sheepshaver_cpu::execute(uint32 entry)
247     {
248     try {
249     pc() = entry;
250 gbeauche 1.2 powerpc_cpu::do_execute<execute_nothing, execute_spcflags_check>();
251 gbeauche 1.1 }
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 gbeauche 1.4 void sheepshaver_cpu::interrupt(uint32 entry)
263 gbeauche 1.1 {
264 gbeauche 1.4 #if !MULTICORE_CPU
265 gbeauche 1.2 // Save program counters and branch registers
266     uint32 saved_pc = pc();
267     uint32 saved_lr = lr();
268     uint32 saved_ctr= ctr();
269 gbeauche 1.4 uint32 saved_sp = gpr(1);
270 gbeauche 1.2 #endif
271    
272 gbeauche 1.4 // Initialize stack pointer to SheepShaver alternate stack base
273     gpr(1) = SheepStack1Base - 64;
274 gbeauche 1.1
275     // Build trampoline to return from interrupt
276 gbeauche 1.5 uint32 trampoline[] = { htonl(POWERPC_EMUL_OP | 1) };
277 gbeauche 1.1
278     // Prepare registers for nanokernel interrupt routine
279 gbeauche 1.5 kernel_data->v[0x004 >> 2] = htonl(gpr(1));
280     kernel_data->v[0x018 >> 2] = htonl(gpr(6));
281 gbeauche 1.1
282 gbeauche 1.5 gpr(6) = ntohl(kernel_data->v[0x65c >> 2]);
283 gbeauche 1.2 assert(gpr(6) != 0);
284 gbeauche 1.1 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 gbeauche 1.5 gpr(7) = ntohl(kernel_data->v[0x660 >> 2]);
294 gbeauche 1.1 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 gbeauche 1.2 #if !MULTICORE_CPU
311     // Restore program counters and branch registers
312     pc() = saved_pc;
313     lr() = saved_lr;
314     ctr()= saved_ctr;
315 gbeauche 1.4 gpr(1) = saved_sp;
316 gbeauche 1.2 #endif
317 gbeauche 1.1 }
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 gbeauche 1.6 // FIXME: make sure MacOS doesn't expect PPC registers to live on top
334 gbeauche 1.1 uint32 sp = gpr(1);
335 gbeauche 1.6 gpr(1) -= 56;
336 gbeauche 1.1 WriteMacInt32(gpr(1), sp);
337    
338     // Save PowerPC registers
339 gbeauche 1.6 uint32 saved_GPRs[19];
340     memcpy(&saved_GPRs[0], &gpr(13), sizeof(uint32)*(32-13));
341 gbeauche 1.1 #if SAVE_FP_EXEC_68K
342 gbeauche 1.6 double saved_FPRs[18];
343     memcpy(&saved_FPRs[0], &fpr(14), sizeof(double)*(32-14));
344 gbeauche 1.1 #endif
345    
346     // Setup registers for 68k emulator
347 gbeauche 1.2 cr().set(CR_SO_field<2>::mask()); // Supervisor mode
348 gbeauche 1.1 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 gbeauche 1.5 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 gbeauche 1.1 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 gbeauche 1.6 memcpy(&gpr(13), &saved_GPRs[0], sizeof(uint32)*(32-13));
391 gbeauche 1.1 #if SAVE_FP_EXEC_68K
392 gbeauche 1.6 memcpy(&fpr(14), &saved_FPRs[0], sizeof(double)*(32-14));
393 gbeauche 1.1 #endif
394    
395     // Cleanup stack
396 gbeauche 1.6 gpr(1) += 56;
397 gbeauche 1.1
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 gbeauche 1.5 uint32 trampoline[] = { htonl(POWERPC_EMUL_OP | 1) };
414 gbeauche 1.1 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 gbeauche 1.2 // Execute ppc routine
449     inline void sheepshaver_cpu::execute_ppc(uint32 entry)
450     {
451     // Save branch registers
452     uint32 saved_lr = lr();
453    
454 gbeauche 1.5 const uint32 trampoline[] = { htonl(POWERPC_EMUL_OP | 1) };
455 gbeauche 1.6 lr() = (uint32)trampoline;
456 gbeauche 1.2
457     execute(entry);
458    
459     // Restore branch registers
460     lr() = saved_lr;
461     }
462    
463 gbeauche 1.1 // Resource Manager thunk
464 gbeauche 1.5 extern "C" void check_load_invoc(uint32 type, int16 id, uint32 h);
465 gbeauche 1.2
466 gbeauche 1.1 inline void sheepshaver_cpu::get_resource(uint32 old_get_resource)
467     {
468 gbeauche 1.2 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 gbeauche 1.5 uint32 handle = gpr(3);
479 gbeauche 1.2 check_load_invoc(type, id, handle);
480 gbeauche 1.5 gpr(3) = handle;
481 gbeauche 1.2
482     // Cleanup stack
483     gpr(1) += 56;
484 gbeauche 1.1 }
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 gbeauche 1.2 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 gbeauche 1.1 // 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 gbeauche 1.3 static sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
526 gbeauche 1.1 {
527     #if ENABLE_VOSF
528 gbeauche 1.3 // 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 gbeauche 1.1 #endif
533 gbeauche 1.3
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 gbeauche 1.1 #endif
546 gbeauche 1.3
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 gbeauche 1.1 dump_registers();
552     current_cpu->dump_log();
553     enter_mon();
554     QuitEmulator();
555 gbeauche 1.3
556     return SIGSEGV_RETURN_FAILURE;
557 gbeauche 1.1 }
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 gbeauche 1.2 #if MULTICORE_CPU
567 gbeauche 1.1 // Initialize alternate CPU emulator to handle interrupts
568     interrupt_cpu = new sheepshaver_cpu();
569 gbeauche 1.2 #endif
570 gbeauche 1.1
571 gbeauche 1.3 // Install the handler for SIGSEGV
572     sigsegv_install_handler(sigsegv_handler);
573 gbeauche 1.4
574 gbeauche 1.1 #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 gbeauche 1.4 #if !ASYNC_IRQ
602 gbeauche 1.2 void TriggerInterrupt(void)
603     {
604     #if 0
605     WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
606     #else
607     SPCFLAGS_SET( SPCFLAG_INT );
608     #endif
609     }
610 gbeauche 1.4 #endif
611 gbeauche 1.2
612 gbeauche 1.4 void HandleInterrupt(void)
613 gbeauche 1.1 {
614     // Do nothing if interrupts are disabled
615 gbeauche 1.2 if (int32(ReadMacInt32(XLM_IRQ_NEST)) > 0)
616 gbeauche 1.1 return;
617    
618 gbeauche 1.2 // Do nothing if there is no interrupt pending
619     if (InterruptFlags == 0)
620 gbeauche 1.1 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 gbeauche 1.2 DisableInterrupt();
647     cpu_push(interrupt_cpu);
648 gbeauche 1.1 if (ROMType == ROMTYPE_NEWWORLD)
649 gbeauche 1.4 current_cpu->interrupt(ROM_BASE + 0x312b1c);
650 gbeauche 1.1 else
651 gbeauche 1.4 current_cpu->interrupt(ROM_BASE + 0x312a3c);
652 gbeauche 1.2 cpu_pop();
653 gbeauche 1.1 }
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 gbeauche 1.2 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 gbeauche 1.1 };
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 gbeauche 1.2 #define POWERPC_NATIVE_OP_INIT(LR, OP) \
697     tswap32(POWERPC_EMUL_OP | ((LR) << 11) | (((uint32)OP) << 6) | 2)
698 gbeauche 1.1
699     // FIXME: Make sure 32-bit relocations are used
700     const uint32 NativeOpTable[NATIVE_OP_MAX] = {
701 gbeauche 1.2 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 gbeauche 1.1 };
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 gbeauche 1.2 case NATIVE_DISABLE_INTERRUPT:
788     DisableInterrupt();
789     break;
790     case NATIVE_ENABLE_INTERRUPT:
791     EnableInterrupt();
792     break;
793 gbeauche 1.1 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 gbeauche 1.5 uint16 proc[2];
833     proc[0] = htons(trap);
834     proc[1] = htons(M68K_RTS);
835 gbeauche 1.1 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     }