ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp
Revision: 1.17
Committed: 2003-11-10T16:23:58Z (21 years ago) by gbeauche
Branch: MAIN
Changes since 1.16: +36 -3 lines
Log Message:
Fix "ignoresegv" case to actually skip the faulty instruction. Merge
conditions to skip instruction on SIGSEGVfrom PowerPC native mode. The
instruction skipper takes care to set the output register to 0.

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     #include "cpu/ppc/ppc-cpu.hpp"
32     #include "cpu/ppc/ppc-operations.hpp"
33    
34     // Used for NativeOp trampolines
35     #include "video.h"
36     #include "name_registry.h"
37     #include "serial.h"
38 gbeauche 1.16 #include "ether.h"
39 gbeauche 1.1
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 gbeauche 1.15 // Emulation time statistics
51     #define EMUL_TIME_STATS 1
52    
53     #if EMUL_TIME_STATS
54     static clock_t emul_start_time;
55     static uint32 interrupt_count = 0;
56     static clock_t interrupt_time = 0;
57     static uint32 exec68k_count = 0;
58     static clock_t exec68k_time = 0;
59     static uint32 native_exec_count = 0;
60     static clock_t native_exec_time = 0;
61     static uint32 macos_exec_count = 0;
62     static clock_t macos_exec_time = 0;
63     #endif
64    
65 gbeauche 1.1 static void enter_mon(void)
66     {
67     // Start up mon in real-mode
68     #if ENABLE_MON
69     char *arg[4] = {"mon", "-m", "-r", NULL};
70     mon(3, arg);
71     #endif
72     }
73    
74 gbeauche 1.2 // Enable multicore (main/interrupts) cpu emulation?
75 gbeauche 1.9 #define MULTICORE_CPU (ASYNC_IRQ ? 1 : 0)
76 gbeauche 1.2
77 gbeauche 1.1 // Enable Execute68k() safety checks?
78     #define SAFE_EXEC_68K 1
79    
80     // Save FP state in Execute68k()?
81     #define SAVE_FP_EXEC_68K 1
82    
83     // Interrupts in EMUL_OP mode?
84     #define INTERRUPTS_IN_EMUL_OP_MODE 1
85    
86     // Interrupts in native mode?
87     #define INTERRUPTS_IN_NATIVE_MODE 1
88    
89     // Pointer to Kernel Data
90 gbeauche 1.4 static KernelData * const kernel_data = (KernelData *)KERNEL_DATA_BASE;
91 gbeauche 1.1
92 gbeauche 1.17 // SIGSEGV handler
93     static sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t);
94    
95 gbeauche 1.1
96     /**
97     * PowerPC emulator glue with special 'sheep' opcodes
98     **/
99    
100     class sheepshaver_cpu
101     : public powerpc_cpu
102     {
103     void init_decoder();
104     void execute_sheep(uint32 opcode);
105    
106     public:
107    
108 gbeauche 1.10 // Constructor
109     sheepshaver_cpu();
110 gbeauche 1.1
111     // Condition Register accessors
112     uint32 get_cr() const { return cr().get(); }
113     void set_cr(uint32 v) { cr().set(v); }
114    
115     // Execution loop
116 gbeauche 1.10 void execute(uint32 entry, bool enable_cache = false);
117 gbeauche 1.1
118     // Execute 68k routine
119     void execute_68k(uint32 entry, M68kRegisters *r);
120    
121 gbeauche 1.2 // Execute ppc routine
122     void execute_ppc(uint32 entry);
123    
124 gbeauche 1.1 // Execute MacOS/PPC code
125     uint32 execute_macos_code(uint32 tvect, int nargs, uint32 const *args);
126    
127     // Resource manager thunk
128     void get_resource(uint32 old_get_resource);
129    
130     // Handle MacOS interrupt
131 gbeauche 1.4 void interrupt(uint32 entry);
132 gbeauche 1.10 void handle_interrupt();
133 gbeauche 1.2
134 gbeauche 1.1 // Lazy memory allocator (one item at a time)
135     void *operator new(size_t size)
136     { return allocator_helper< sheepshaver_cpu, lazy_allocator >::allocate(); }
137     void operator delete(void *p)
138     { allocator_helper< sheepshaver_cpu, lazy_allocator >::deallocate(p); }
139     // FIXME: really make surre array allocation fail at link time?
140     void *operator new[](size_t);
141     void operator delete[](void *p);
142 gbeauche 1.17
143     // Make sure the SIGSEGV handler can access CPU registers
144     friend sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t);
145 gbeauche 1.1 };
146    
147     lazy_allocator< sheepshaver_cpu > allocator_helper< sheepshaver_cpu, lazy_allocator >::allocator;
148    
149 gbeauche 1.10 sheepshaver_cpu::sheepshaver_cpu()
150     : powerpc_cpu()
151     {
152     init_decoder();
153     }
154    
155 gbeauche 1.1 void sheepshaver_cpu::init_decoder()
156     {
157     #ifndef PPC_NO_STATIC_II_INDEX_TABLE
158     static bool initialized = false;
159     if (initialized)
160     return;
161     initialized = true;
162     #endif
163    
164     static const instr_info_t sheep_ii_table[] = {
165     { "sheep",
166 gbeauche 1.13 (execute_pmf)&sheepshaver_cpu::execute_sheep,
167 gbeauche 1.1 NULL,
168 gbeauche 1.7 D_form, 6, 0, CFLOW_JUMP | CFLOW_TRAP
169 gbeauche 1.1 }
170     };
171    
172     const int ii_count = sizeof(sheep_ii_table)/sizeof(sheep_ii_table[0]);
173     D(bug("SheepShaver extra decode table has %d entries\n", ii_count));
174    
175     for (int i = 0; i < ii_count; i++) {
176     const instr_info_t * ii = &sheep_ii_table[i];
177     init_decoder_entry(ii);
178     }
179     }
180    
181     // Forward declaration for native opcode handler
182     static void NativeOp(int selector);
183    
184 gbeauche 1.2 /* NativeOp instruction format:
185     +------------+--------------------------+--+----------+------------+
186     | 6 | |FN| OP | 2 |
187     +------------+--------------------------+--+----------+------------+
188     0 5 |6 19 20 21 25 26 31
189     */
190    
191     typedef bit_field< 20, 20 > FN_field;
192     typedef bit_field< 21, 25 > NATIVE_OP_field;
193     typedef bit_field< 26, 31 > EMUL_OP_field;
194    
195 gbeauche 1.1 // Execute SheepShaver instruction
196     void sheepshaver_cpu::execute_sheep(uint32 opcode)
197     {
198     // D(bug("Extended opcode %08x at %08x (68k pc %08x)\n", opcode, pc(), gpr(24)));
199     assert((((opcode >> 26) & 0x3f) == 6) && OP_MAX <= 64 + 3);
200    
201     switch (opcode & 0x3f) {
202     case 0: // EMUL_RETURN
203     QuitEmulator();
204     break;
205 gbeauche 1.8
206 gbeauche 1.1 case 1: // EXEC_RETURN
207 gbeauche 1.12 spcflags().set(SPCFLAG_CPU_EXEC_RETURN);
208 gbeauche 1.1 break;
209    
210     case 2: // EXEC_NATIVE
211 gbeauche 1.2 NativeOp(NATIVE_OP_field::extract(opcode));
212     if (FN_field::test(opcode))
213     pc() = lr();
214     else
215     pc() += 4;
216 gbeauche 1.1 break;
217    
218     default: { // EMUL_OP
219     M68kRegisters r68;
220     WriteMacInt32(XLM_68K_R25, gpr(25));
221     WriteMacInt32(XLM_RUN_MODE, MODE_EMUL_OP);
222     for (int i = 0; i < 8; i++)
223     r68.d[i] = gpr(8 + i);
224     for (int i = 0; i < 7; i++)
225     r68.a[i] = gpr(16 + i);
226     r68.a[7] = gpr(1);
227 gbeauche 1.2 EmulOp(&r68, gpr(24), EMUL_OP_field::extract(opcode) - 3);
228 gbeauche 1.1 for (int i = 0; i < 8; i++)
229     gpr(8 + i) = r68.d[i];
230     for (int i = 0; i < 7; i++)
231     gpr(16 + i) = r68.a[i];
232     gpr(1) = r68.a[7];
233     WriteMacInt32(XLM_RUN_MODE, MODE_68K);
234     pc() += 4;
235     break;
236     }
237     }
238     }
239    
240     // Execution loop
241 gbeauche 1.10 void sheepshaver_cpu::execute(uint32 entry, bool enable_cache)
242 gbeauche 1.1 {
243 gbeauche 1.12 powerpc_cpu::execute(entry, enable_cache);
244 gbeauche 1.1 }
245    
246     // Handle MacOS interrupt
247 gbeauche 1.4 void sheepshaver_cpu::interrupt(uint32 entry)
248 gbeauche 1.1 {
249 gbeauche 1.15 #if EMUL_TIME_STATS
250     interrupt_count++;
251     const clock_t interrupt_start = clock();
252     #endif
253    
254 gbeauche 1.4 #if !MULTICORE_CPU
255 gbeauche 1.2 // Save program counters and branch registers
256     uint32 saved_pc = pc();
257     uint32 saved_lr = lr();
258     uint32 saved_ctr= ctr();
259 gbeauche 1.4 uint32 saved_sp = gpr(1);
260 gbeauche 1.2 #endif
261    
262 gbeauche 1.4 // Initialize stack pointer to SheepShaver alternate stack base
263     gpr(1) = SheepStack1Base - 64;
264 gbeauche 1.1
265     // Build trampoline to return from interrupt
266 gbeauche 1.5 uint32 trampoline[] = { htonl(POWERPC_EMUL_OP | 1) };
267 gbeauche 1.1
268     // Prepare registers for nanokernel interrupt routine
269 gbeauche 1.5 kernel_data->v[0x004 >> 2] = htonl(gpr(1));
270     kernel_data->v[0x018 >> 2] = htonl(gpr(6));
271 gbeauche 1.1
272 gbeauche 1.5 gpr(6) = ntohl(kernel_data->v[0x65c >> 2]);
273 gbeauche 1.2 assert(gpr(6) != 0);
274 gbeauche 1.1 WriteMacInt32(gpr(6) + 0x13c, gpr(7));
275     WriteMacInt32(gpr(6) + 0x144, gpr(8));
276     WriteMacInt32(gpr(6) + 0x14c, gpr(9));
277     WriteMacInt32(gpr(6) + 0x154, gpr(10));
278     WriteMacInt32(gpr(6) + 0x15c, gpr(11));
279     WriteMacInt32(gpr(6) + 0x164, gpr(12));
280     WriteMacInt32(gpr(6) + 0x16c, gpr(13));
281    
282     gpr(1) = KernelDataAddr;
283 gbeauche 1.5 gpr(7) = ntohl(kernel_data->v[0x660 >> 2]);
284 gbeauche 1.1 gpr(8) = 0;
285     gpr(10) = (uint32)trampoline;
286     gpr(12) = (uint32)trampoline;
287 gbeauche 1.8 gpr(13) = get_cr();
288 gbeauche 1.1
289     // rlwimi. r7,r7,8,0,0
290     uint32 result = op_ppc_rlwimi::apply(gpr(7), 8, 0x80000000, gpr(7));
291     record_cr0(result);
292     gpr(7) = result;
293    
294     gpr(11) = 0xf072; // MSR (SRR1)
295 gbeauche 1.8 cr().set((gpr(11) & 0x0fff0000) | (get_cr() & ~0x0fff0000));
296 gbeauche 1.1
297     // Enter nanokernel
298     execute(entry);
299    
300 gbeauche 1.2 #if !MULTICORE_CPU
301     // Restore program counters and branch registers
302     pc() = saved_pc;
303     lr() = saved_lr;
304     ctr()= saved_ctr;
305 gbeauche 1.4 gpr(1) = saved_sp;
306 gbeauche 1.2 #endif
307 gbeauche 1.15
308     #if EMUL_TIME_STATS
309     interrupt_time += (clock() - interrupt_start);
310     #endif
311 gbeauche 1.1 }
312    
313     // Execute 68k routine
314     void sheepshaver_cpu::execute_68k(uint32 entry, M68kRegisters *r)
315     {
316 gbeauche 1.15 #if EMUL_TIME_STATS
317     exec68k_count++;
318     const clock_t exec68k_start = clock();
319     #endif
320    
321 gbeauche 1.1 #if SAFE_EXEC_68K
322     if (ReadMacInt32(XLM_RUN_MODE) != MODE_EMUL_OP)
323     printf("FATAL: Execute68k() not called from EMUL_OP mode\n");
324     #endif
325    
326     // Save program counters and branch registers
327     uint32 saved_pc = pc();
328     uint32 saved_lr = lr();
329     uint32 saved_ctr= ctr();
330 gbeauche 1.8 uint32 saved_cr = get_cr();
331 gbeauche 1.1
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 gbeauche 1.8 set_cr(saved_cr);
403 gbeauche 1.15
404     #if EMUL_TIME_STATS
405     exec68k_time += (clock() - exec68k_start);
406     #endif
407 gbeauche 1.1 }
408    
409     // Call MacOS PPC code
410     uint32 sheepshaver_cpu::execute_macos_code(uint32 tvect, int nargs, uint32 const *args)
411     {
412 gbeauche 1.15 #if EMUL_TIME_STATS
413     macos_exec_count++;
414     const clock_t macos_exec_start = clock();
415     #endif
416    
417 gbeauche 1.1 // Save program counters and branch registers
418     uint32 saved_pc = pc();
419     uint32 saved_lr = lr();
420     uint32 saved_ctr= ctr();
421    
422     // Build trampoline with EXEC_RETURN
423 gbeauche 1.5 uint32 trampoline[] = { htonl(POWERPC_EMUL_OP | 1) };
424 gbeauche 1.1 lr() = (uint32)trampoline;
425    
426     gpr(1) -= 64; // Create stack frame
427     uint32 proc = ReadMacInt32(tvect); // Get routine address
428     uint32 toc = ReadMacInt32(tvect + 4); // Get TOC pointer
429    
430     // Save PowerPC registers
431     uint32 regs[8];
432     regs[0] = gpr(2);
433     for (int i = 0; i < nargs; i++)
434     regs[i + 1] = gpr(i + 3);
435    
436     // Prepare and call MacOS routine
437     gpr(2) = toc;
438     for (int i = 0; i < nargs; i++)
439     gpr(i + 3) = args[i];
440     execute(proc);
441     uint32 retval = gpr(3);
442    
443     // Restore PowerPC registers
444     for (int i = 0; i <= nargs; i++)
445     gpr(i + 2) = regs[i];
446    
447     // Cleanup stack
448     gpr(1) += 64;
449    
450     // Restore program counters and branch registers
451     pc() = saved_pc;
452     lr() = saved_lr;
453     ctr()= saved_ctr;
454    
455 gbeauche 1.15 #if EMUL_TIME_STATS
456     macos_exec_time += (clock() - macos_exec_start);
457     #endif
458    
459 gbeauche 1.1 return retval;
460     }
461    
462 gbeauche 1.2 // Execute ppc routine
463     inline void sheepshaver_cpu::execute_ppc(uint32 entry)
464     {
465     // Save branch registers
466     uint32 saved_lr = lr();
467    
468 gbeauche 1.5 const uint32 trampoline[] = { htonl(POWERPC_EMUL_OP | 1) };
469 gbeauche 1.6 lr() = (uint32)trampoline;
470 gbeauche 1.2
471     execute(entry);
472    
473     // Restore branch registers
474     lr() = saved_lr;
475     }
476    
477 gbeauche 1.1 // Resource Manager thunk
478 gbeauche 1.5 extern "C" void check_load_invoc(uint32 type, int16 id, uint32 h);
479 gbeauche 1.2
480 gbeauche 1.1 inline void sheepshaver_cpu::get_resource(uint32 old_get_resource)
481     {
482 gbeauche 1.2 uint32 type = gpr(3);
483     int16 id = gpr(4);
484    
485     // Create stack frame
486     gpr(1) -= 56;
487    
488     // Call old routine
489     execute_ppc(old_get_resource);
490    
491     // Call CheckLoad()
492 gbeauche 1.5 uint32 handle = gpr(3);
493 gbeauche 1.2 check_load_invoc(type, id, handle);
494 gbeauche 1.5 gpr(3) = handle;
495 gbeauche 1.2
496     // Cleanup stack
497     gpr(1) += 56;
498 gbeauche 1.1 }
499    
500    
501     /**
502     * SheepShaver CPU engine interface
503     **/
504    
505     static sheepshaver_cpu *main_cpu = NULL; // CPU emulator to handle usual control flow
506     static sheepshaver_cpu *interrupt_cpu = NULL; // CPU emulator to handle interrupts
507     static sheepshaver_cpu *current_cpu = NULL; // Current CPU emulator context
508    
509 gbeauche 1.7 void FlushCodeCache(uintptr start, uintptr end)
510     {
511     D(bug("FlushCodeCache(%08x, %08x)\n", start, end));
512     main_cpu->invalidate_cache_range(start, end);
513     #if MULTICORE_CPU
514     interrupt_cpu->invalidate_cache_range(start, end);
515     #endif
516     }
517    
518 gbeauche 1.2 static inline void cpu_push(sheepshaver_cpu *new_cpu)
519     {
520     #if MULTICORE_CPU
521     current_cpu = new_cpu;
522     #endif
523     }
524    
525     static inline void cpu_pop()
526     {
527     #if MULTICORE_CPU
528     current_cpu = main_cpu;
529     #endif
530     }
531    
532 gbeauche 1.1 // Dump PPC registers
533     static void dump_registers(void)
534     {
535     current_cpu->dump_registers();
536     }
537    
538     // Dump log
539     static void dump_log(void)
540     {
541     current_cpu->dump_log();
542     }
543    
544     /*
545     * Initialize CPU emulation
546     */
547    
548 gbeauche 1.3 static sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
549 gbeauche 1.1 {
550     #if ENABLE_VOSF
551 gbeauche 1.3 // Handle screen fault
552     extern bool Screen_fault_handler(sigsegv_address_t, sigsegv_address_t);
553     if (Screen_fault_handler(fault_address, fault_instruction))
554     return SIGSEGV_RETURN_SUCCESS;
555 gbeauche 1.1 #endif
556 gbeauche 1.3
557     const uintptr addr = (uintptr)fault_address;
558     #if HAVE_SIGSEGV_SKIP_INSTRUCTION
559     // Ignore writes to ROM
560     if ((addr - ROM_BASE) < ROM_SIZE)
561     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
562    
563 gbeauche 1.17 // Get program counter of target CPU
564     sheepshaver_cpu * const cpu = current_cpu;
565     const uint32 pc = cpu->pc();
566    
567     // Fault in Mac ROM or RAM?
568     bool mac_fault = (pc >= ROM_BASE) && (pc < (ROM_BASE + ROM_AREA_SIZE)) || (pc >= RAMBase) && (pc < (RAMBase + RAMSize));
569     if (mac_fault) {
570    
571     // "VM settings" during MacOS 8 installation
572     if (pc == ROM_BASE + 0x488160 && cpu->gpr(20) == 0xf8000000)
573     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
574    
575     // MacOS 8.5 installation
576     else if (pc == ROM_BASE + 0x488140 && cpu->gpr(16) == 0xf8000000)
577     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
578    
579     // MacOS 8 serial drivers on startup
580     else if (pc == ROM_BASE + 0x48e080 && (cpu->gpr(8) == 0xf3012002 || cpu->gpr(8) == 0xf3012000))
581     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
582    
583     // MacOS 8.1 serial drivers on startup
584     else if (pc == ROM_BASE + 0x48c5e0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000))
585     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
586     else if (pc == ROM_BASE + 0x4a10a0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000))
587     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
588    
589     // Ignore all other faults, if requested
590     if (PrefsFindBool("ignoresegv"))
591     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
592     }
593 gbeauche 1.3 #else
594     #error "FIXME: You don't have the capability to skip instruction within signal handlers"
595 gbeauche 1.1 #endif
596 gbeauche 1.3
597     printf("SIGSEGV\n");
598     printf(" pc %p\n", fault_instruction);
599     printf(" ea %p\n", fault_address);
600     printf(" cpu %s\n", current_cpu == main_cpu ? "main" : "interrupts");
601 gbeauche 1.1 dump_registers();
602     current_cpu->dump_log();
603     enter_mon();
604     QuitEmulator();
605 gbeauche 1.3
606     return SIGSEGV_RETURN_FAILURE;
607 gbeauche 1.1 }
608    
609     void init_emul_ppc(void)
610     {
611     // Initialize main CPU emulator
612     main_cpu = new sheepshaver_cpu();
613     main_cpu->set_register(powerpc_registers::GPR(3), any_register((uint32)ROM_BASE + 0x30d000));
614     WriteMacInt32(XLM_RUN_MODE, MODE_68K);
615    
616 gbeauche 1.2 #if MULTICORE_CPU
617 gbeauche 1.1 // Initialize alternate CPU emulator to handle interrupts
618     interrupt_cpu = new sheepshaver_cpu();
619 gbeauche 1.2 #endif
620 gbeauche 1.1
621 gbeauche 1.3 // Install the handler for SIGSEGV
622     sigsegv_install_handler(sigsegv_handler);
623 gbeauche 1.4
624 gbeauche 1.1 #if ENABLE_MON
625     // Install "regs" command in cxmon
626     mon_add_command("regs", dump_registers, "regs Dump PowerPC registers\n");
627     mon_add_command("log", dump_log, "log Dump PowerPC emulation log\n");
628     #endif
629 gbeauche 1.15
630     #if EMUL_TIME_STATS
631     emul_start_time = clock();
632     #endif
633 gbeauche 1.1 }
634    
635     /*
636 gbeauche 1.14 * Deinitialize emulation
637     */
638    
639     void exit_emul_ppc(void)
640     {
641 gbeauche 1.15 #if EMUL_TIME_STATS
642     clock_t emul_end_time = clock();
643    
644     printf("### Statistics for SheepShaver emulation parts\n");
645     const clock_t emul_time = emul_end_time - emul_start_time;
646     printf("Total emulation time : %.1f sec\n", double(emul_time) / double(CLOCKS_PER_SEC));
647     printf("Total interrupt count: %d (%2.1f Hz)\n", interrupt_count,
648     (double(interrupt_count) * CLOCKS_PER_SEC) / double(emul_time));
649    
650     #define PRINT_STATS(LABEL, VAR_PREFIX) do { \
651     printf("Total " LABEL " count : %d\n", VAR_PREFIX##_count); \
652     printf("Total " LABEL " time : %.1f sec (%.1f%%)\n", \
653     double(VAR_PREFIX##_time) / double(CLOCKS_PER_SEC), \
654     100.0 * double(VAR_PREFIX##_time) / double(emul_time)); \
655     } while (0)
656    
657     PRINT_STATS("Execute68k[Trap] execution", exec68k);
658     PRINT_STATS("NativeOp execution", native_exec);
659     PRINT_STATS("MacOS routine execution", macos_exec);
660    
661     #undef PRINT_STATS
662     printf("\n");
663     #endif
664    
665 gbeauche 1.14 delete main_cpu;
666     #if MULTICORE_CPU
667     delete interrupt_cpu;
668     #endif
669     }
670    
671     /*
672 gbeauche 1.1 * Emulation loop
673     */
674    
675     void emul_ppc(uint32 entry)
676     {
677     current_cpu = main_cpu;
678 gbeauche 1.10 #if DEBUG
679 gbeauche 1.1 current_cpu->start_log();
680 gbeauche 1.10 #endif
681     // start emulation loop and enable code translation or caching
682     current_cpu->execute(entry, true);
683 gbeauche 1.1 }
684    
685     /*
686     * Handle PowerPC interrupt
687     */
688    
689 gbeauche 1.11 #if ASYNC_IRQ
690     void HandleInterrupt(void)
691     {
692     main_cpu->handle_interrupt();
693     }
694     #else
695 gbeauche 1.2 void TriggerInterrupt(void)
696     {
697     #if 0
698     WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
699     #else
700 gbeauche 1.10 // Trigger interrupt to main cpu only
701     if (main_cpu)
702     main_cpu->trigger_interrupt();
703 gbeauche 1.2 #endif
704     }
705 gbeauche 1.4 #endif
706 gbeauche 1.2
707 gbeauche 1.10 void sheepshaver_cpu::handle_interrupt(void)
708 gbeauche 1.1 {
709     // Do nothing if interrupts are disabled
710 gbeauche 1.16 if (*(int32 *)XLM_IRQ_NEST > 0)
711 gbeauche 1.1 return;
712    
713 gbeauche 1.2 // Do nothing if there is no interrupt pending
714     if (InterruptFlags == 0)
715 gbeauche 1.1 return;
716    
717     // Disable MacOS stack sniffer
718     WriteMacInt32(0x110, 0);
719    
720     // Interrupt action depends on current run mode
721     switch (ReadMacInt32(XLM_RUN_MODE)) {
722     case MODE_68K:
723     // 68k emulator active, trigger 68k interrupt level 1
724     assert(current_cpu == main_cpu);
725     WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
726 gbeauche 1.10 set_cr(get_cr() | tswap32(kernel_data->v[0x674 >> 2]));
727 gbeauche 1.1 break;
728    
729     #if INTERRUPTS_IN_NATIVE_MODE
730     case MODE_NATIVE:
731     // 68k emulator inactive, in nanokernel?
732     assert(current_cpu == main_cpu);
733 gbeauche 1.10 if (gpr(1) != KernelDataAddr) {
734 gbeauche 1.1 // Prepare for 68k interrupt level 1
735     WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
736     WriteMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc,
737     ReadMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc)
738     | tswap32(kernel_data->v[0x674 >> 2]));
739    
740     // Execute nanokernel interrupt routine (this will activate the 68k emulator)
741 gbeauche 1.2 DisableInterrupt();
742     cpu_push(interrupt_cpu);
743 gbeauche 1.1 if (ROMType == ROMTYPE_NEWWORLD)
744 gbeauche 1.4 current_cpu->interrupt(ROM_BASE + 0x312b1c);
745 gbeauche 1.1 else
746 gbeauche 1.4 current_cpu->interrupt(ROM_BASE + 0x312a3c);
747 gbeauche 1.2 cpu_pop();
748 gbeauche 1.1 }
749     break;
750     #endif
751    
752     #if INTERRUPTS_IN_EMUL_OP_MODE
753     case MODE_EMUL_OP:
754     // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
755     if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) {
756     #if 1
757     // Execute full 68k interrupt routine
758     M68kRegisters r;
759     uint32 old_r25 = ReadMacInt32(XLM_68K_R25); // Save interrupt level
760     WriteMacInt32(XLM_68K_R25, 0x21); // Execute with interrupt level 1
761 gbeauche 1.2 static const uint8 proc[] = {
762     0x3f, 0x3c, 0x00, 0x00, // move.w #$0000,-(sp) (fake format word)
763     0x48, 0x7a, 0x00, 0x0a, // pea @1(pc) (return address)
764     0x40, 0xe7, // move sr,-(sp) (saved SR)
765     0x20, 0x78, 0x00, 0x064, // move.l $64,a0
766     0x4e, 0xd0, // jmp (a0)
767     M68K_RTS >> 8, M68K_RTS & 0xff // @1
768 gbeauche 1.1 };
769     Execute68k((uint32)proc, &r);
770     WriteMacInt32(XLM_68K_R25, old_r25); // Restore interrupt level
771     #else
772     // Only update cursor
773     if (HasMacStarted()) {
774     if (InterruptFlags & INTFLAG_VIA) {
775     ClearInterruptFlag(INTFLAG_VIA);
776     ADBInterrupt();
777     ExecutePPC(VideoVBL);
778     }
779     }
780     #endif
781     }
782     break;
783     #endif
784     }
785     }
786    
787     /*
788     * Execute NATIVE_OP opcode (called by PowerPC emulator)
789     */
790    
791 gbeauche 1.2 #define POWERPC_NATIVE_OP_INIT(LR, OP) \
792     tswap32(POWERPC_EMUL_OP | ((LR) << 11) | (((uint32)OP) << 6) | 2)
793 gbeauche 1.1
794     // FIXME: Make sure 32-bit relocations are used
795     const uint32 NativeOpTable[NATIVE_OP_MAX] = {
796 gbeauche 1.2 POWERPC_NATIVE_OP_INIT(1, NATIVE_PATCH_NAME_REGISTRY),
797     POWERPC_NATIVE_OP_INIT(1, NATIVE_VIDEO_INSTALL_ACCEL),
798     POWERPC_NATIVE_OP_INIT(1, NATIVE_VIDEO_VBL),
799     POWERPC_NATIVE_OP_INIT(1, NATIVE_VIDEO_DO_DRIVER_IO),
800     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_IRQ),
801     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_INIT),
802     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_TERM),
803     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_OPEN),
804     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_CLOSE),
805     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_WPUT),
806     POWERPC_NATIVE_OP_INIT(1, NATIVE_ETHER_RSRV),
807     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_NOTHING),
808     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_OPEN),
809     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_PRIME_IN),
810     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_PRIME_OUT),
811     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_CONTROL),
812     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_STATUS),
813     POWERPC_NATIVE_OP_INIT(1, NATIVE_SERIAL_CLOSE),
814     POWERPC_NATIVE_OP_INIT(1, NATIVE_GET_RESOURCE),
815     POWERPC_NATIVE_OP_INIT(1, NATIVE_GET_1_RESOURCE),
816     POWERPC_NATIVE_OP_INIT(1, NATIVE_GET_IND_RESOURCE),
817     POWERPC_NATIVE_OP_INIT(1, NATIVE_GET_1_IND_RESOURCE),
818     POWERPC_NATIVE_OP_INIT(1, NATIVE_R_GET_RESOURCE),
819     POWERPC_NATIVE_OP_INIT(0, NATIVE_DISABLE_INTERRUPT),
820     POWERPC_NATIVE_OP_INIT(0, NATIVE_ENABLE_INTERRUPT),
821 gbeauche 1.7 POWERPC_NATIVE_OP_INIT(1, NATIVE_MAKE_EXECUTABLE),
822 gbeauche 1.1 };
823    
824     static void get_resource(void);
825     static void get_1_resource(void);
826     static void get_ind_resource(void);
827     static void get_1_ind_resource(void);
828     static void r_get_resource(void);
829    
830     #define GPR(REG) current_cpu->gpr(REG)
831    
832     static void NativeOp(int selector)
833     {
834 gbeauche 1.15 #if EMUL_TIME_STATS
835     native_exec_count++;
836     const clock_t native_exec_start = clock();
837     #endif
838    
839 gbeauche 1.1 switch (selector) {
840     case NATIVE_PATCH_NAME_REGISTRY:
841     DoPatchNameRegistry();
842     break;
843     case NATIVE_VIDEO_INSTALL_ACCEL:
844     VideoInstallAccel();
845     break;
846     case NATIVE_VIDEO_VBL:
847     VideoVBL();
848     break;
849     case NATIVE_VIDEO_DO_DRIVER_IO:
850     GPR(3) = (int32)(int16)VideoDoDriverIO((void *)GPR(3), (void *)GPR(4),
851     (void *)GPR(5), GPR(6), GPR(7));
852     break;
853 gbeauche 1.16 #ifdef WORDS_BIGENDIAN
854     case NATIVE_ETHER_IRQ:
855     EtherIRQ();
856     break;
857     case NATIVE_ETHER_INIT:
858     GPR(3) = InitStreamModule((void *)GPR(3));
859     break;
860     case NATIVE_ETHER_TERM:
861     TerminateStreamModule();
862     break;
863     case NATIVE_ETHER_OPEN:
864     GPR(3) = ether_open((queue_t *)GPR(3), (void *)GPR(4), GPR(5), GPR(6), (void*)GPR(7));
865 gbeauche 1.1 break;
866 gbeauche 1.16 case NATIVE_ETHER_CLOSE:
867     GPR(3) = ether_close((queue_t *)GPR(3), GPR(4), (void *)GPR(5));
868 gbeauche 1.1 break;
869 gbeauche 1.16 case NATIVE_ETHER_WPUT:
870     GPR(3) = ether_wput((queue_t *)GPR(3), (mblk_t *)GPR(4));
871 gbeauche 1.1 break;
872 gbeauche 1.16 case NATIVE_ETHER_RSRV:
873     GPR(3) = ether_rsrv((queue_t *)GPR(3));
874 gbeauche 1.1 break;
875 gbeauche 1.16 #else
876     case NATIVE_ETHER_INIT:
877     // FIXME: needs more complicated thunks
878     GPR(3) = false;
879 gbeauche 1.1 break;
880 gbeauche 1.16 #endif
881 gbeauche 1.1 case NATIVE_SERIAL_NOTHING:
882     case NATIVE_SERIAL_OPEN:
883     case NATIVE_SERIAL_PRIME_IN:
884     case NATIVE_SERIAL_PRIME_OUT:
885     case NATIVE_SERIAL_CONTROL:
886     case NATIVE_SERIAL_STATUS:
887     case NATIVE_SERIAL_CLOSE: {
888     typedef int16 (*SerialCallback)(uint32, uint32);
889     static const SerialCallback serial_callbacks[] = {
890     SerialNothing,
891     SerialOpen,
892     SerialPrimeIn,
893     SerialPrimeOut,
894     SerialControl,
895     SerialStatus,
896     SerialClose
897     };
898     GPR(3) = serial_callbacks[selector - NATIVE_SERIAL_NOTHING](GPR(3), GPR(4));
899 gbeauche 1.16 break;
900     }
901     case NATIVE_GET_RESOURCE:
902     case NATIVE_GET_1_RESOURCE:
903     case NATIVE_GET_IND_RESOURCE:
904     case NATIVE_GET_1_IND_RESOURCE:
905     case NATIVE_R_GET_RESOURCE: {
906     typedef void (*GetResourceCallback)(void);
907     static const GetResourceCallback get_resource_callbacks[] = {
908     get_resource,
909     get_1_resource,
910     get_ind_resource,
911     get_1_ind_resource,
912     r_get_resource
913     };
914     get_resource_callbacks[selector - NATIVE_GET_RESOURCE]();
915 gbeauche 1.1 break;
916     }
917 gbeauche 1.2 case NATIVE_DISABLE_INTERRUPT:
918     DisableInterrupt();
919     break;
920     case NATIVE_ENABLE_INTERRUPT:
921     EnableInterrupt();
922 gbeauche 1.7 break;
923     case NATIVE_MAKE_EXECUTABLE:
924     MakeExecutable(0, (void *)GPR(4), GPR(5));
925 gbeauche 1.2 break;
926 gbeauche 1.1 default:
927     printf("FATAL: NATIVE_OP called with bogus selector %d\n", selector);
928     QuitEmulator();
929     break;
930     }
931 gbeauche 1.15
932     #if EMUL_TIME_STATS
933     native_exec_time += (clock() - native_exec_start);
934     #endif
935 gbeauche 1.1 }
936    
937     /*
938     * Execute native subroutine (LR must contain return address)
939     */
940    
941     void ExecuteNative(int selector)
942     {
943     uint32 tvect[2];
944     tvect[0] = tswap32(POWERPC_NATIVE_OP_FUNC(selector));
945     tvect[1] = 0; // Fake TVECT
946     RoutineDescriptor desc = BUILD_PPC_ROUTINE_DESCRIPTOR(0, tvect);
947     M68kRegisters r;
948     Execute68k((uint32)&desc, &r);
949     }
950    
951     /*
952     * Execute 68k subroutine (must be ended with EXEC_RETURN)
953     * This must only be called by the emul_thread when in EMUL_OP mode
954     * r->a[7] is unused, the routine runs on the caller's stack
955     */
956    
957     void Execute68k(uint32 pc, M68kRegisters *r)
958     {
959     current_cpu->execute_68k(pc, r);
960     }
961    
962     /*
963     * Execute 68k A-Trap from EMUL_OP routine
964     * r->a[7] is unused, the routine runs on the caller's stack
965     */
966    
967     void Execute68kTrap(uint16 trap, M68kRegisters *r)
968     {
969 gbeauche 1.5 uint16 proc[2];
970     proc[0] = htons(trap);
971     proc[1] = htons(M68K_RTS);
972 gbeauche 1.1 Execute68k((uint32)proc, r);
973     }
974    
975     /*
976     * Call MacOS PPC code
977     */
978    
979     uint32 call_macos(uint32 tvect)
980     {
981     return current_cpu->execute_macos_code(tvect, 0, NULL);
982     }
983    
984     uint32 call_macos1(uint32 tvect, uint32 arg1)
985     {
986     const uint32 args[] = { arg1 };
987     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
988     }
989    
990     uint32 call_macos2(uint32 tvect, uint32 arg1, uint32 arg2)
991     {
992     const uint32 args[] = { arg1, arg2 };
993     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
994     }
995    
996     uint32 call_macos3(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3)
997     {
998     const uint32 args[] = { arg1, arg2, arg3 };
999     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1000     }
1001    
1002     uint32 call_macos4(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4)
1003     {
1004     const uint32 args[] = { arg1, arg2, arg3, arg4 };
1005     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1006     }
1007    
1008     uint32 call_macos5(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5)
1009     {
1010     const uint32 args[] = { arg1, arg2, arg3, arg4, arg5 };
1011     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1012     }
1013    
1014     uint32 call_macos6(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6)
1015     {
1016     const uint32 args[] = { arg1, arg2, arg3, arg4, arg5, arg6 };
1017     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1018     }
1019    
1020     uint32 call_macos7(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6, uint32 arg7)
1021     {
1022     const uint32 args[] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7 };
1023     return current_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1024     }
1025    
1026     /*
1027     * Resource Manager thunks
1028     */
1029    
1030     void get_resource(void)
1031     {
1032     current_cpu->get_resource(ReadMacInt32(XLM_GET_RESOURCE));
1033     }
1034    
1035     void get_1_resource(void)
1036     {
1037     current_cpu->get_resource(ReadMacInt32(XLM_GET_1_RESOURCE));
1038     }
1039    
1040     void get_ind_resource(void)
1041     {
1042     current_cpu->get_resource(ReadMacInt32(XLM_GET_IND_RESOURCE));
1043     }
1044    
1045     void get_1_ind_resource(void)
1046     {
1047     current_cpu->get_resource(ReadMacInt32(XLM_GET_1_IND_RESOURCE));
1048     }
1049    
1050     void r_get_resource(void)
1051     {
1052     current_cpu->get_resource(ReadMacInt32(XLM_R_GET_RESOURCE));
1053     }