ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp
Revision: 1.10
Committed: 2003-10-26T13:59:03Z (21 years, 1 month ago) by gbeauche
Branch: MAIN
Changes since 1.9: +23 -39 lines
Log Message:
Rewrite interrupts handling code so that the emulator can work with a
predecode cache. This implies to run in interpreted mode only while
processing EmulOps or other native (nested) runs.

Note that the FLIGHT_RECORDER with a predecode cache gets slower than
without caching at all.

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.4 #if !ASYNC_IRQ
590 gbeauche 1.2 void TriggerInterrupt(void)
591     {
592     #if 0
593     WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
594     #else
595 gbeauche 1.10 // Trigger interrupt to main cpu only
596     if (main_cpu)
597     main_cpu->trigger_interrupt();
598 gbeauche 1.2 #endif
599     }
600 gbeauche 1.4 #endif
601 gbeauche 1.2
602 gbeauche 1.10 void sheepshaver_cpu::handle_interrupt(void)
603 gbeauche 1.1 {
604     // Do nothing if interrupts are disabled
605 gbeauche 1.2 if (int32(ReadMacInt32(XLM_IRQ_NEST)) > 0)
606 gbeauche 1.1 return;
607    
608 gbeauche 1.2 // Do nothing if there is no interrupt pending
609     if (InterruptFlags == 0)
610 gbeauche 1.1 return;
611    
612     // Disable MacOS stack sniffer
613     WriteMacInt32(0x110, 0);
614    
615     // Interrupt action depends on current run mode
616     switch (ReadMacInt32(XLM_RUN_MODE)) {
617     case MODE_68K:
618     // 68k emulator active, trigger 68k interrupt level 1
619     assert(current_cpu == main_cpu);
620     WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
621 gbeauche 1.10 set_cr(get_cr() | tswap32(kernel_data->v[0x674 >> 2]));
622 gbeauche 1.1 break;
623    
624     #if INTERRUPTS_IN_NATIVE_MODE
625     case MODE_NATIVE:
626     // 68k emulator inactive, in nanokernel?
627     assert(current_cpu == main_cpu);
628 gbeauche 1.10 if (gpr(1) != KernelDataAddr) {
629 gbeauche 1.1 // Prepare for 68k interrupt level 1
630     WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
631     WriteMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc,
632     ReadMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc)
633     | tswap32(kernel_data->v[0x674 >> 2]));
634    
635     // Execute nanokernel interrupt routine (this will activate the 68k emulator)
636 gbeauche 1.2 DisableInterrupt();
637     cpu_push(interrupt_cpu);
638 gbeauche 1.1 if (ROMType == ROMTYPE_NEWWORLD)
639 gbeauche 1.4 current_cpu->interrupt(ROM_BASE + 0x312b1c);
640 gbeauche 1.1 else
641 gbeauche 1.4 current_cpu->interrupt(ROM_BASE + 0x312a3c);
642 gbeauche 1.2 cpu_pop();
643 gbeauche 1.1 }
644     break;
645     #endif
646    
647     #if INTERRUPTS_IN_EMUL_OP_MODE
648     case MODE_EMUL_OP:
649     // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
650     if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) {
651     #if 1
652     // Execute full 68k interrupt routine
653     M68kRegisters r;
654     uint32 old_r25 = ReadMacInt32(XLM_68K_R25); // Save interrupt level
655     WriteMacInt32(XLM_68K_R25, 0x21); // Execute with interrupt level 1
656 gbeauche 1.2 static const uint8 proc[] = {
657     0x3f, 0x3c, 0x00, 0x00, // move.w #$0000,-(sp) (fake format word)
658     0x48, 0x7a, 0x00, 0x0a, // pea @1(pc) (return address)
659     0x40, 0xe7, // move sr,-(sp) (saved SR)
660     0x20, 0x78, 0x00, 0x064, // move.l $64,a0
661     0x4e, 0xd0, // jmp (a0)
662     M68K_RTS >> 8, M68K_RTS & 0xff // @1
663 gbeauche 1.1 };
664     Execute68k((uint32)proc, &r);
665     WriteMacInt32(XLM_68K_R25, old_r25); // Restore interrupt level
666     #else
667     // Only update cursor
668     if (HasMacStarted()) {
669     if (InterruptFlags & INTFLAG_VIA) {
670     ClearInterruptFlag(INTFLAG_VIA);
671     ADBInterrupt();
672     ExecutePPC(VideoVBL);
673     }
674     }
675     #endif
676     }
677     break;
678     #endif
679     }
680     }
681    
682     /*
683     * Execute NATIVE_OP opcode (called by PowerPC emulator)
684     */
685    
686 gbeauche 1.2 #define POWERPC_NATIVE_OP_INIT(LR, OP) \
687     tswap32(POWERPC_EMUL_OP | ((LR) << 11) | (((uint32)OP) << 6) | 2)
688 gbeauche 1.1
689     // FIXME: Make sure 32-bit relocations are used
690     const uint32 NativeOpTable[NATIVE_OP_MAX] = {
691 gbeauche 1.2 POWERPC_NATIVE_OP_INIT(1, NATIVE_PATCH_NAME_REGISTRY),
692     POWERPC_NATIVE_OP_INIT(1, NATIVE_VIDEO_INSTALL_ACCEL),
693     POWERPC_NATIVE_OP_INIT(1, NATIVE_VIDEO_VBL),
694     POWERPC_NATIVE_OP_INIT(1, NATIVE_VIDEO_DO_DRIVER_IO),
695     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_IRQ),
696     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_INIT),
697     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_TERM),
698     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_OPEN),
699     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_CLOSE),
700     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_WPUT),
701     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_RSRV),
702     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_NOTHING),
703     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_OPEN),
704     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_PRIME_IN),
705     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_PRIME_OUT),
706     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_CONTROL),
707     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_STATUS),
708     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_CLOSE),
709     POWERPC_NATIVE_OP_INIT(1, NATIVE_GET_RESOURCE),
710     POWERPC_NATIVE_OP_INIT(1, NATIVE_GET_1_RESOURCE),
711     POWERPC_NATIVE_OP_INIT(1, NATIVE_GET_IND_RESOURCE),
712     POWERPC_NATIVE_OP_INIT(1, NATIVE_GET_1_IND_RESOURCE),
713     POWERPC_NATIVE_OP_INIT(1, NATIVE_R_GET_RESOURCE),
714     POWERPC_NATIVE_OP_INIT(0, NATIVE_DISABLE_INTERRUPT),
715     POWERPC_NATIVE_OP_INIT(0, NATIVE_ENABLE_INTERRUPT),
716 gbeauche 1.7 POWERPC_NATIVE_OP_INIT(1, NATIVE_MAKE_EXECUTABLE),
717 gbeauche 1.1 };
718    
719     static void get_resource(void);
720     static void get_1_resource(void);
721     static void get_ind_resource(void);
722     static void get_1_ind_resource(void);
723     static void r_get_resource(void);
724    
725     #define GPR(REG) current_cpu->gpr(REG)
726    
727     static void NativeOp(int selector)
728     {
729     switch (selector) {
730     case NATIVE_PATCH_NAME_REGISTRY:
731     DoPatchNameRegistry();
732     break;
733     case NATIVE_VIDEO_INSTALL_ACCEL:
734     VideoInstallAccel();
735     break;
736     case NATIVE_VIDEO_VBL:
737     VideoVBL();
738     break;
739     case NATIVE_VIDEO_DO_DRIVER_IO:
740     GPR(3) = (int32)(int16)VideoDoDriverIO((void *)GPR(3), (void *)GPR(4),
741     (void *)GPR(5), GPR(6), GPR(7));
742     break;
743     case NATIVE_GET_RESOURCE:
744     get_resource();
745     break;
746     case NATIVE_GET_1_RESOURCE:
747     get_1_resource();
748     break;
749     case NATIVE_GET_IND_RESOURCE:
750     get_ind_resource();
751     break;
752     case NATIVE_GET_1_IND_RESOURCE:
753     get_1_ind_resource();
754     break;
755     case NATIVE_R_GET_RESOURCE:
756     r_get_resource();
757     break;
758     case NATIVE_SERIAL_NOTHING:
759     case NATIVE_SERIAL_OPEN:
760     case NATIVE_SERIAL_PRIME_IN:
761     case NATIVE_SERIAL_PRIME_OUT:
762     case NATIVE_SERIAL_CONTROL:
763     case NATIVE_SERIAL_STATUS:
764     case NATIVE_SERIAL_CLOSE: {
765     typedef int16 (*SerialCallback)(uint32, uint32);
766     static const SerialCallback serial_callbacks[] = {
767     SerialNothing,
768     SerialOpen,
769     SerialPrimeIn,
770     SerialPrimeOut,
771     SerialControl,
772     SerialStatus,
773     SerialClose
774     };
775     GPR(3) = serial_callbacks[selector - NATIVE_SERIAL_NOTHING](GPR(3), GPR(4));
776     break;
777     }
778 gbeauche 1.2 case NATIVE_DISABLE_INTERRUPT:
779     DisableInterrupt();
780     break;
781     case NATIVE_ENABLE_INTERRUPT:
782     EnableInterrupt();
783 gbeauche 1.7 break;
784     case NATIVE_MAKE_EXECUTABLE:
785     MakeExecutable(0, (void *)GPR(4), GPR(5));
786 gbeauche 1.2 break;
787 gbeauche 1.1 default:
788     printf("FATAL: NATIVE_OP called with bogus selector %d\n", selector);
789     QuitEmulator();
790     break;
791     }
792     }
793    
794     /*
795     * Execute native subroutine (LR must contain return address)
796     */
797    
798     void ExecuteNative(int selector)
799     {
800     uint32 tvect[2];
801     tvect[0] = tswap32(POWERPC_NATIVE_OP_FUNC(selector));
802     tvect[1] = 0; // Fake TVECT
803     RoutineDescriptor desc = BUILD_PPC_ROUTINE_DESCRIPTOR(0, tvect);
804     M68kRegisters r;
805     Execute68k((uint32)&desc, &r);
806     }
807    
808     /*
809     * Execute 68k subroutine (must be ended with EXEC_RETURN)
810     * This must only be called by the emul_thread when in EMUL_OP mode
811     * r->a[7] is unused, the routine runs on the caller's stack
812     */
813    
814     void Execute68k(uint32 pc, M68kRegisters *r)
815     {
816     current_cpu->execute_68k(pc, r);
817     }
818    
819     /*
820     * Execute 68k A-Trap from EMUL_OP routine
821     * r->a[7] is unused, the routine runs on the caller's stack
822     */
823    
824     void Execute68kTrap(uint16 trap, M68kRegisters *r)
825     {
826 gbeauche 1.5 uint16 proc[2];
827     proc[0] = htons(trap);
828     proc[1] = htons(M68K_RTS);
829 gbeauche 1.1 Execute68k((uint32)proc, r);
830     }
831    
832     /*
833     * Call MacOS PPC code
834     */
835    
836     uint32 call_macos(uint32 tvect)
837     {
838     return current_cpu->execute_macos_code(tvect, 0, NULL);
839     }
840    
841     uint32 call_macos1(uint32 tvect, uint32 arg1)
842     {
843     const uint32 args[] = { arg1 };
844     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
845     }
846    
847     uint32 call_macos2(uint32 tvect, uint32 arg1, uint32 arg2)
848     {
849     const uint32 args[] = { arg1, arg2 };
850     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
851     }
852    
853     uint32 call_macos3(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3)
854     {
855     const uint32 args[] = { arg1, arg2, arg3 };
856     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
857     }
858    
859     uint32 call_macos4(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4)
860     {
861     const uint32 args[] = { arg1, arg2, arg3, arg4 };
862     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
863     }
864    
865     uint32 call_macos5(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5)
866     {
867     const uint32 args[] = { arg1, arg2, arg3, arg4, arg5 };
868     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
869     }
870    
871     uint32 call_macos6(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6)
872     {
873     const uint32 args[] = { arg1, arg2, arg3, arg4, arg5, arg6 };
874     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
875     }
876    
877     uint32 call_macos7(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6, uint32 arg7)
878     {
879     const uint32 args[] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7 };
880     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
881     }
882    
883     /*
884     * Resource Manager thunks
885     */
886    
887     void get_resource(void)
888     {
889     current_cpu->get_resource(ReadMacInt32(XLM_GET_RESOURCE));
890     }
891    
892     void get_1_resource(void)
893     {
894     current_cpu->get_resource(ReadMacInt32(XLM_GET_1_RESOURCE));
895     }
896    
897     void get_ind_resource(void)
898     {
899     current_cpu->get_resource(ReadMacInt32(XLM_GET_IND_RESOURCE));
900     }
901    
902     void get_1_ind_resource(void)
903     {
904     current_cpu->get_resource(ReadMacInt32(XLM_GET_1_IND_RESOURCE));
905     }
906    
907     void r_get_resource(void)
908     {
909     current_cpu->get_resource(ReadMacInt32(XLM_R_GET_RESOURCE));
910     }