ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp
Revision: 1.11
Committed: 2003-10-26T14:16:39Z (20 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.10: +6 -1 lines
Log Message:
Fix ASYNC_IRQ build but locks may still happen. Note that with a predecode
cache, checking for pending interrupts may not be the bottle neck nowadays.

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