ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/kpx_cpu/sheepshaver_glue.cpp
Revision: 1.76
Committed: 2009-08-18T18:26:11Z (15 years, 1 month ago) by asvitkine
Branch: MAIN
Changes since 1.75: +9 -9 lines
Log Message:
[Michael Schmitt]
Attached is a patch to SheepShaver to fix memory allocation problems when OS X 10.5 is the host. It also relaxes the 512 MB RAM limit on OS X hosts.


Problem
-------
Some users have been unable to run SheepShaver on OS X 10.5 (Leopard) hosts. The symptom is error "ERROR: Cannot map RAM: File already exists".

SheepShaver allocates RAM at fixed addresses. If it is running in "Real" addressing mode, and can't allocate at address 0, then it was hard-coded to allocate the RAM area at 0x20000000. The ROM area as allocated at 0x40800000.

The normal configuration is for SheepShaver to run under SDL, which is a Cocoa wrapper. By the time SheepShaver does its memory allocations, the Cocoa application has already started. The result is the SheepShaver memory address space already contains libraries, fonts, Input Managers, and IOKit areas.

On Leopard hosts these areas can land on the same addresses SheepShaver needs, so SheepShaver's memory allocation fails.


Solution
--------
The approach is to change SheepShaver (on Unix & OS X hosts) to allocate the RAM area anywhere it can find the space, rather than at a fixed address.

This could result in the RAM allocated higher than the ROM area, which causes a crash. To prevent this from occurring, the RAM and ROM areas are allocated contiguously.

Previously the ROM starting address was a constant ROM_BASE, which was used throughout the source files. The ROM start address is now a variable ROMBase. ROMBase is allocated and set by main_*.cpp just like RAMBase.

A side-effect of this change is that it lifts the 512 MB RAM limit for OS X hosts. The limit was because the fixed RAM and ROM addresses were such that the RAM could only be 512 MB before it overlapped the ROM area.


Impact
------
The change to make ROMBase a variable is throughout all hosts & addressing modes.

The RAM and ROM areas will only shift when run on Unix & OS X hosts, otherwise the same fixed allocation address is used as before.

This change is limited to "Real" addressing mode. Unlike Basilisk II, SheepShaver *pre-calculates* the offset for "Direct" addressing mode; the offset is compiled into the program. If the RAM address were allowed to shift, it could result in the RAM area wrapping around address 0.


Changes to main_unix.cpp
------------------------
1. Real addressing mode no longer defines a RAM_BASE constant.

2. The base address of the Mac ROM (ROMBase) is defined and exported by this program.

3. Memory management helper vm_mac_acquire is renamed to vm_mac_acquire_fixed. Added a new memory management helper vm_mac_acquire, which allocates memory at any address.

4. Changed and rearranged the allocation of RAM and ROM areas.

Before it worked like this:

  - Allocate ROM area
  - If can, attempt to allocate RAM at address zero
  - If RAM not allocated at 0, allocate at fixed address

We still want to try allocating the RAM at zero, and if using DIRECT addressing we're still going to use the fixed addresses. So we don't know where the ROM should be until after we do the RAM. The new logic is:

  - If can, attempt to allocate RAM at address zero
  - If RAM not allocated at 0
      if REAL addressing
         allocate RAM and ROM together. The ROM address is aligned to a 1 MB boundary
      else (direct addressing)
         allocate RAM at fixed address
  - If ROM hasn't been allocated yet, allocate at fixed address

5. Calculate ROMBase and ROMBaseHost based on where the ROM was loaded.

6. There is a crash if the RAM is allocated too high. To try and catch this, check if it was allocated higher than the kernel data address.

7. Change subsequent code from using constant ROM_BASE to variable ROMBase.


Changes to Other Programs
-------------------------
emul_op.cpp, main.cpp, name_registery.cpp, rom_patches.cpp, rsrc_patches.cpp, emul_ppc.cpp, sheepshaver_glue.cpp, ppc-translate-cpp:
Change from constant ROM_BASE to variable ROMBase.

ppc_asm.S: It was setting register to a hard-coded literal address: 0x40b0d000. Changed to set it to ROMBase + 0x30d000.

ppc_asm.tmpl: It defined a macro ASM_LO16 but it assumed that the macro would always be used with operands that included a register specification. This is not true. Moved the register specification from the macro to the macro invocations.

main_beos.cpp, main_windows.cpp: Since the subprograms are all expecting a variable ROMBase, all the main_*.cpp pgrams have to define and export it. The ROM_BASE constant is moved here for consistency. The mains for beos and windows just allocate the ROM at the same fixed address as before, set ROMBaseHost and ROMBase to that address, and then use ROMBase for the subsequent code.

cpu_emulation.h: removed ROM_BASE constant. This value is moved to the main_*.cpp modules, to be consistent with RAM_BASE.

user_strings_unix.cpp, user_strings_unix.h: Added new error messages related to errors that occur when the RAM and ROM are allocated anywhere.

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * sheepshaver_glue.cpp - Glue Kheperix CPU to SheepShaver CPU engine interface
3     *
4 gbeauche 1.75 * SheepShaver (C) 1997-2008 Christian Bauer and Marc Hellwig
5 gbeauche 1.1 *
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 gbeauche 1.18 #include "cpu/ppc/ppc-instructions.hpp"
34 gbeauche 1.21 #include "thunks.h"
35 gbeauche 1.1
36     // Used for NativeOp trampolines
37     #include "video.h"
38     #include "name_registry.h"
39     #include "serial.h"
40 gbeauche 1.16 #include "ether.h"
41 gbeauche 1.37 #include "timer.h"
42 gbeauche 1.1
43     #include <stdio.h>
44 gbeauche 1.31 #include <stdlib.h>
45 gbeauche 1.53 #ifdef HAVE_MALLOC_H
46     #include <malloc.h>
47     #endif
48 gbeauche 1.1
49 gbeauche 1.47 #ifdef USE_SDL_VIDEO
50     #include <SDL_events.h>
51     #endif
52    
53 gbeauche 1.1 #if ENABLE_MON
54     #include "mon.h"
55     #include "mon_disass.h"
56     #endif
57    
58 gbeauche 1.10 #define DEBUG 0
59 gbeauche 1.1 #include "debug.h"
60    
61 gbeauche 1.15 // Emulation time statistics
62 gbeauche 1.44 #ifndef EMUL_TIME_STATS
63     #define EMUL_TIME_STATS 0
64     #endif
65 gbeauche 1.15
66     #if EMUL_TIME_STATS
67     static clock_t emul_start_time;
68 gbeauche 1.44 static uint32 interrupt_count = 0, ppc_interrupt_count = 0;
69 gbeauche 1.15 static clock_t interrupt_time = 0;
70     static uint32 exec68k_count = 0;
71     static clock_t exec68k_time = 0;
72     static uint32 native_exec_count = 0;
73     static clock_t native_exec_time = 0;
74     static uint32 macos_exec_count = 0;
75     static clock_t macos_exec_time = 0;
76     #endif
77    
78 gbeauche 1.1 static void enter_mon(void)
79     {
80     // Start up mon in real-mode
81     #if ENABLE_MON
82     char *arg[4] = {"mon", "-m", "-r", NULL};
83     mon(3, arg);
84     #endif
85     }
86    
87 gbeauche 1.23 // From main_*.cpp
88     extern uintptr SignalStackBase();
89    
90 gbeauche 1.26 // From rsrc_patches.cpp
91     extern "C" void check_load_invoc(uint32 type, int16 id, uint32 h);
92 gbeauche 1.68 extern "C" void named_check_load_invoc(uint32 type, uint32 name, uint32 h);
93 gbeauche 1.26
94 gbeauche 1.21 // PowerPC EmulOp to exit from emulation looop
95     const uint32 POWERPC_EXEC_RETURN = POWERPC_EMUL_OP | 1;
96    
97 gbeauche 1.1 // Enable Execute68k() safety checks?
98     #define SAFE_EXEC_68K 1
99    
100     // Save FP state in Execute68k()?
101     #define SAVE_FP_EXEC_68K 1
102    
103     // Interrupts in EMUL_OP mode?
104     #define INTERRUPTS_IN_EMUL_OP_MODE 1
105    
106     // Interrupts in native mode?
107     #define INTERRUPTS_IN_NATIVE_MODE 1
108    
109     // Pointer to Kernel Data
110 gbeauche 1.52 static KernelData * kernel_data;
111 gbeauche 1.1
112 gbeauche 1.17 // SIGSEGV handler
113 gbeauche 1.48 sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t);
114 gbeauche 1.17
115 gbeauche 1.38 #if PPC_ENABLE_JIT && PPC_REENTRANT_JIT
116     // Special trampolines for EmulOp and NativeOp
117     static uint8 *emul_op_trampoline;
118     static uint8 *native_op_trampoline;
119     #endif
120    
121 gbeauche 1.1
122     /**
123     * PowerPC emulator glue with special 'sheep' opcodes
124     **/
125    
126 gbeauche 1.18 enum {
127     PPC_I(SHEEP) = PPC_I(MAX),
128     PPC_I(SHEEP_MAX)
129     };
130    
131 gbeauche 1.1 class sheepshaver_cpu
132     : public powerpc_cpu
133     {
134     void init_decoder();
135     void execute_sheep(uint32 opcode);
136    
137     public:
138    
139 gbeauche 1.10 // Constructor
140     sheepshaver_cpu();
141 gbeauche 1.1
142 gbeauche 1.24 // CR & XER accessors
143 gbeauche 1.1 uint32 get_cr() const { return cr().get(); }
144     void set_cr(uint32 v) { cr().set(v); }
145 gbeauche 1.24 uint32 get_xer() const { return xer().get(); }
146     void set_xer(uint32 v) { xer().set(v); }
147 gbeauche 1.1
148 gbeauche 1.38 // Execute NATIVE_OP routine
149     void execute_native_op(uint32 native_op);
150    
151 gbeauche 1.26 // Execute EMUL_OP routine
152     void execute_emul_op(uint32 emul_op);
153    
154 gbeauche 1.1 // Execute 68k routine
155     void execute_68k(uint32 entry, M68kRegisters *r);
156    
157 gbeauche 1.2 // Execute ppc routine
158     void execute_ppc(uint32 entry);
159    
160 gbeauche 1.1 // Execute MacOS/PPC code
161     uint32 execute_macos_code(uint32 tvect, int nargs, uint32 const *args);
162    
163 gbeauche 1.53 #if PPC_ENABLE_JIT
164 gbeauche 1.26 // Compile one instruction
165 gbeauche 1.38 virtual int compile1(codegen_context_t & cg_context);
166 gbeauche 1.53 #endif
167 gbeauche 1.1 // Resource manager thunk
168     void get_resource(uint32 old_get_resource);
169    
170     // Handle MacOS interrupt
171 gbeauche 1.4 void interrupt(uint32 entry);
172 gbeauche 1.2
173 gbeauche 1.17 // Make sure the SIGSEGV handler can access CPU registers
174 gbeauche 1.74 friend sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip);
175 gbeauche 1.1 };
176    
177 gbeauche 1.10 sheepshaver_cpu::sheepshaver_cpu()
178     {
179     init_decoder();
180 gbeauche 1.73
181     #if PPC_ENABLE_JIT
182     if (PrefsFindBool("jit"))
183     enable_jit();
184     #endif
185 gbeauche 1.10 }
186    
187 gbeauche 1.1 void sheepshaver_cpu::init_decoder()
188     {
189     static const instr_info_t sheep_ii_table[] = {
190     { "sheep",
191 gbeauche 1.13 (execute_pmf)&sheepshaver_cpu::execute_sheep,
192 gbeauche 1.18 PPC_I(SHEEP),
193 gbeauche 1.7 D_form, 6, 0, CFLOW_JUMP | CFLOW_TRAP
194 gbeauche 1.1 }
195     };
196    
197     const int ii_count = sizeof(sheep_ii_table)/sizeof(sheep_ii_table[0]);
198     D(bug("SheepShaver extra decode table has %d entries\n", ii_count));
199    
200     for (int i = 0; i < ii_count; i++) {
201     const instr_info_t * ii = &sheep_ii_table[i];
202     init_decoder_entry(ii);
203     }
204     }
205    
206 gbeauche 1.2 /* NativeOp instruction format:
207 gbeauche 1.35 +------------+-------------------------+--+-----------+------------+
208     | 6 | |FN| OP | 2 |
209     +------------+-------------------------+--+-----------+------------+
210     0 5 |6 18 19 20 25 26 31
211 gbeauche 1.2 */
212    
213 gbeauche 1.35 typedef bit_field< 19, 19 > FN_field;
214     typedef bit_field< 20, 25 > NATIVE_OP_field;
215 gbeauche 1.2 typedef bit_field< 26, 31 > EMUL_OP_field;
216    
217 gbeauche 1.26 // Execute EMUL_OP routine
218     void sheepshaver_cpu::execute_emul_op(uint32 emul_op)
219     {
220     M68kRegisters r68;
221     WriteMacInt32(XLM_68K_R25, gpr(25));
222     WriteMacInt32(XLM_RUN_MODE, MODE_EMUL_OP);
223     for (int i = 0; i < 8; i++)
224     r68.d[i] = gpr(8 + i);
225     for (int i = 0; i < 7; i++)
226     r68.a[i] = gpr(16 + i);
227     r68.a[7] = gpr(1);
228 gbeauche 1.62 uint32 saved_cr = get_cr() & 0xff9fffff; // mask_operand::compute(11, 8)
229 gbeauche 1.26 uint32 saved_xer = get_xer();
230     EmulOp(&r68, gpr(24), emul_op);
231     set_cr(saved_cr);
232     set_xer(saved_xer);
233     for (int i = 0; i < 8; i++)
234     gpr(8 + i) = r68.d[i];
235     for (int i = 0; i < 7; i++)
236     gpr(16 + i) = r68.a[i];
237     gpr(1) = r68.a[7];
238     WriteMacInt32(XLM_RUN_MODE, MODE_68K);
239     }
240    
241 gbeauche 1.1 // Execute SheepShaver instruction
242     void sheepshaver_cpu::execute_sheep(uint32 opcode)
243     {
244     // D(bug("Extended opcode %08x at %08x (68k pc %08x)\n", opcode, pc(), gpr(24)));
245     assert((((opcode >> 26) & 0x3f) == 6) && OP_MAX <= 64 + 3);
246    
247     switch (opcode & 0x3f) {
248     case 0: // EMUL_RETURN
249     QuitEmulator();
250     break;
251 gbeauche 1.8
252 gbeauche 1.1 case 1: // EXEC_RETURN
253 gbeauche 1.12 spcflags().set(SPCFLAG_CPU_EXEC_RETURN);
254 gbeauche 1.1 break;
255    
256     case 2: // EXEC_NATIVE
257 gbeauche 1.38 execute_native_op(NATIVE_OP_field::extract(opcode));
258 gbeauche 1.2 if (FN_field::test(opcode))
259     pc() = lr();
260     else
261     pc() += 4;
262 gbeauche 1.1 break;
263    
264 gbeauche 1.26 default: // EMUL_OP
265     execute_emul_op(EMUL_OP_field::extract(opcode) - 3);
266     pc() += 4;
267     break;
268     }
269     }
270    
271     // Compile one instruction
272 gbeauche 1.53 #if PPC_ENABLE_JIT
273 gbeauche 1.38 int sheepshaver_cpu::compile1(codegen_context_t & cg_context)
274 gbeauche 1.26 {
275     const instr_info_t *ii = cg_context.instr_info;
276     if (ii->mnemo != PPC_I(SHEEP))
277 gbeauche 1.38 return COMPILE_FAILURE;
278 gbeauche 1.26
279 gbeauche 1.38 int status = COMPILE_FAILURE;
280 gbeauche 1.26 powerpc_dyngen & dg = cg_context.codegen;
281     uint32 opcode = cg_context.opcode;
282    
283     switch (opcode & 0x3f) {
284     case 0: // EMUL_RETURN
285     dg.gen_invoke(QuitEmulator);
286 gbeauche 1.38 status = COMPILE_CODE_OK;
287 gbeauche 1.26 break;
288    
289     case 1: // EXEC_RETURN
290     dg.gen_spcflags_set(SPCFLAG_CPU_EXEC_RETURN);
291 gbeauche 1.38 // Don't check for pending interrupts, we do know we have to
292     // get out of this block ASAP
293     dg.gen_exec_return();
294     status = COMPILE_EPILOGUE_OK;
295 gbeauche 1.26 break;
296    
297     case 2: { // EXEC_NATIVE
298     uint32 selector = NATIVE_OP_field::extract(opcode);
299     switch (selector) {
300 gbeauche 1.38 #if !PPC_REENTRANT_JIT
301     // Filter out functions that may invoke Execute68k() or
302     // CallMacOS(), this would break reentrancy as they could
303     // invalidate the translation cache and even overwrite
304     // continuation code when we are done with them.
305 gbeauche 1.26 case NATIVE_PATCH_NAME_REGISTRY:
306     dg.gen_invoke(DoPatchNameRegistry);
307 gbeauche 1.38 status = COMPILE_CODE_OK;
308 gbeauche 1.26 break;
309     case NATIVE_VIDEO_INSTALL_ACCEL:
310     dg.gen_invoke(VideoInstallAccel);
311 gbeauche 1.38 status = COMPILE_CODE_OK;
312 gbeauche 1.26 break;
313     case NATIVE_VIDEO_VBL:
314     dg.gen_invoke(VideoVBL);
315 gbeauche 1.38 status = COMPILE_CODE_OK;
316 gbeauche 1.26 break;
317     case NATIVE_GET_RESOURCE:
318     case NATIVE_GET_1_RESOURCE:
319     case NATIVE_GET_IND_RESOURCE:
320     case NATIVE_GET_1_IND_RESOURCE:
321     case NATIVE_R_GET_RESOURCE: {
322     static const uint32 get_resource_ptr[] = {
323     XLM_GET_RESOURCE,
324     XLM_GET_1_RESOURCE,
325     XLM_GET_IND_RESOURCE,
326     XLM_GET_1_IND_RESOURCE,
327     XLM_R_GET_RESOURCE
328     };
329     uint32 old_get_resource = ReadMacInt32(get_resource_ptr[selector - NATIVE_GET_RESOURCE]);
330     typedef void (*func_t)(dyngen_cpu_base, uint32);
331     func_t func = (func_t)nv_mem_fun(&sheepshaver_cpu::get_resource).ptr();
332     dg.gen_invoke_CPU_im(func, old_get_resource);
333 gbeauche 1.38 status = COMPILE_CODE_OK;
334 gbeauche 1.26 break;
335     }
336 gbeauche 1.70 #endif
337 gbeauche 1.26 case NATIVE_CHECK_LOAD_INVOC:
338     dg.gen_load_T0_GPR(3);
339     dg.gen_load_T1_GPR(4);
340     dg.gen_se_16_32_T1();
341     dg.gen_load_T2_GPR(5);
342     dg.gen_invoke_T0_T1_T2((void (*)(uint32, uint32, uint32))check_load_invoc);
343 gbeauche 1.38 status = COMPILE_CODE_OK;
344     break;
345 gbeauche 1.68 case NATIVE_NAMED_CHECK_LOAD_INVOC:
346     dg.gen_load_T0_GPR(3);
347     dg.gen_load_T1_GPR(4);
348     dg.gen_load_T2_GPR(5);
349     dg.gen_invoke_T0_T1_T2((void (*)(uint32, uint32, uint32))named_check_load_invoc);
350     status = COMPILE_CODE_OK;
351     break;
352 gbeauche 1.70 case NATIVE_NQD_SYNC_HOOK:
353     dg.gen_load_T0_GPR(3);
354     dg.gen_invoke_T0_ret_T0((uint32 (*)(uint32))NQD_sync_hook);
355     dg.gen_store_T0_GPR(3);
356     status = COMPILE_CODE_OK;
357     break;
358     case NATIVE_NQD_BITBLT_HOOK:
359     dg.gen_load_T0_GPR(3);
360     dg.gen_invoke_T0_ret_T0((uint32 (*)(uint32))NQD_bitblt_hook);
361     dg.gen_store_T0_GPR(3);
362     status = COMPILE_CODE_OK;
363     break;
364     case NATIVE_NQD_FILLRECT_HOOK:
365     dg.gen_load_T0_GPR(3);
366     dg.gen_invoke_T0_ret_T0((uint32 (*)(uint32))NQD_fillrect_hook);
367     dg.gen_store_T0_GPR(3);
368     status = COMPILE_CODE_OK;
369     break;
370     case NATIVE_NQD_UNKNOWN_HOOK:
371     dg.gen_load_T0_GPR(3);
372     dg.gen_invoke_T0_ret_T0((uint32 (*)(uint32))NQD_unknown_hook);
373     dg.gen_store_T0_GPR(3);
374     status = COMPILE_CODE_OK;
375     break;
376 gbeauche 1.69 case NATIVE_NQD_BITBLT:
377 gbeauche 1.35 dg.gen_load_T0_GPR(3);
378     dg.gen_invoke_T0((void (*)(uint32))NQD_bitblt);
379 gbeauche 1.38 status = COMPILE_CODE_OK;
380 gbeauche 1.35 break;
381 gbeauche 1.69 case NATIVE_NQD_INVRECT:
382 gbeauche 1.35 dg.gen_load_T0_GPR(3);
383     dg.gen_invoke_T0((void (*)(uint32))NQD_invrect);
384 gbeauche 1.38 status = COMPILE_CODE_OK;
385 gbeauche 1.35 break;
386 gbeauche 1.69 case NATIVE_NQD_FILLRECT:
387 gbeauche 1.35 dg.gen_load_T0_GPR(3);
388     dg.gen_invoke_T0((void (*)(uint32))NQD_fillrect);
389 gbeauche 1.38 status = COMPILE_CODE_OK;
390 gbeauche 1.26 break;
391     }
392 gbeauche 1.38 // Could we fully translate this NativeOp?
393 gbeauche 1.42 if (status == COMPILE_CODE_OK) {
394     if (!FN_field::test(opcode))
395     cg_context.done_compile = false;
396     else {
397 gbeauche 1.71 dg.gen_load_T0_LR_aligned();
398     dg.gen_set_PC_T0();
399 gbeauche 1.42 cg_context.done_compile = true;
400 gbeauche 1.26 }
401 gbeauche 1.38 break;
402     }
403     #if PPC_REENTRANT_JIT
404     // Try to execute NativeOp trampoline
405 gbeauche 1.42 if (!FN_field::test(opcode))
406     dg.gen_set_PC_im(cg_context.pc + 4);
407     else {
408 gbeauche 1.71 dg.gen_load_T0_LR_aligned();
409     dg.gen_set_PC_T0();
410 gbeauche 1.42 }
411 gbeauche 1.38 dg.gen_mov_32_T0_im(selector);
412     dg.gen_jmp(native_op_trampoline);
413     cg_context.done_compile = true;
414     status = COMPILE_EPILOGUE_OK;
415     break;
416     #endif
417     // Invoke NativeOp handler
418 gbeauche 1.42 if (!FN_field::test(opcode)) {
419     typedef void (*func_t)(dyngen_cpu_base, uint32);
420     func_t func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_native_op).ptr();
421     dg.gen_invoke_CPU_im(func, selector);
422     cg_context.done_compile = false;
423     status = COMPILE_CODE_OK;
424     }
425     // Otherwise, let it generate a call to execute_sheep() which
426     // will cause necessary updates to the program counter
427 gbeauche 1.26 break;
428     }
429    
430 gbeauche 1.1 default: { // EMUL_OP
431 gbeauche 1.37 uint32 emul_op = EMUL_OP_field::extract(opcode) - 3;
432 gbeauche 1.38 #if PPC_REENTRANT_JIT
433     // Try to execute EmulOp trampoline
434     dg.gen_set_PC_im(cg_context.pc + 4);
435     dg.gen_mov_32_T0_im(emul_op);
436     dg.gen_jmp(emul_op_trampoline);
437     cg_context.done_compile = true;
438     status = COMPILE_EPILOGUE_OK;
439     break;
440     #endif
441     // Invoke EmulOp handler
442 gbeauche 1.26 typedef void (*func_t)(dyngen_cpu_base, uint32);
443     func_t func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_emul_op).ptr();
444 gbeauche 1.37 dg.gen_invoke_CPU_im(func, emul_op);
445 gbeauche 1.26 cg_context.done_compile = false;
446 gbeauche 1.38 status = COMPILE_CODE_OK;
447 gbeauche 1.1 break;
448     }
449     }
450 gbeauche 1.38 return status;
451 gbeauche 1.53 }
452 gbeauche 1.26 #endif
453 gbeauche 1.1
454     // Handle MacOS interrupt
455 gbeauche 1.4 void sheepshaver_cpu::interrupt(uint32 entry)
456 gbeauche 1.1 {
457 gbeauche 1.15 #if EMUL_TIME_STATS
458 gbeauche 1.44 ppc_interrupt_count++;
459 gbeauche 1.15 const clock_t interrupt_start = clock();
460     #endif
461    
462 gbeauche 1.2 // Save program counters and branch registers
463     uint32 saved_pc = pc();
464     uint32 saved_lr = lr();
465     uint32 saved_ctr= ctr();
466 gbeauche 1.4 uint32 saved_sp = gpr(1);
467 gbeauche 1.2
468 gbeauche 1.4 // Initialize stack pointer to SheepShaver alternate stack base
469 gbeauche 1.23 gpr(1) = SignalStackBase() - 64;
470 gbeauche 1.1
471     // Build trampoline to return from interrupt
472 gbeauche 1.21 SheepVar32 trampoline = POWERPC_EXEC_RETURN;
473 gbeauche 1.1
474     // Prepare registers for nanokernel interrupt routine
475 gbeauche 1.5 kernel_data->v[0x004 >> 2] = htonl(gpr(1));
476     kernel_data->v[0x018 >> 2] = htonl(gpr(6));
477 gbeauche 1.1
478 gbeauche 1.5 gpr(6) = ntohl(kernel_data->v[0x65c >> 2]);
479 gbeauche 1.2 assert(gpr(6) != 0);
480 gbeauche 1.1 WriteMacInt32(gpr(6) + 0x13c, gpr(7));
481     WriteMacInt32(gpr(6) + 0x144, gpr(8));
482     WriteMacInt32(gpr(6) + 0x14c, gpr(9));
483     WriteMacInt32(gpr(6) + 0x154, gpr(10));
484     WriteMacInt32(gpr(6) + 0x15c, gpr(11));
485     WriteMacInt32(gpr(6) + 0x164, gpr(12));
486     WriteMacInt32(gpr(6) + 0x16c, gpr(13));
487    
488     gpr(1) = KernelDataAddr;
489 gbeauche 1.5 gpr(7) = ntohl(kernel_data->v[0x660 >> 2]);
490 gbeauche 1.1 gpr(8) = 0;
491 gbeauche 1.21 gpr(10) = trampoline.addr();
492     gpr(12) = trampoline.addr();
493 gbeauche 1.8 gpr(13) = get_cr();
494 gbeauche 1.1
495     // rlwimi. r7,r7,8,0,0
496     uint32 result = op_ppc_rlwimi::apply(gpr(7), 8, 0x80000000, gpr(7));
497     record_cr0(result);
498     gpr(7) = result;
499    
500     gpr(11) = 0xf072; // MSR (SRR1)
501 gbeauche 1.8 cr().set((gpr(11) & 0x0fff0000) | (get_cr() & ~0x0fff0000));
502 gbeauche 1.1
503     // Enter nanokernel
504     execute(entry);
505    
506 gbeauche 1.2 // Restore program counters and branch registers
507     pc() = saved_pc;
508     lr() = saved_lr;
509     ctr()= saved_ctr;
510 gbeauche 1.4 gpr(1) = saved_sp;
511 gbeauche 1.15
512     #if EMUL_TIME_STATS
513     interrupt_time += (clock() - interrupt_start);
514     #endif
515 gbeauche 1.1 }
516    
517     // Execute 68k routine
518     void sheepshaver_cpu::execute_68k(uint32 entry, M68kRegisters *r)
519     {
520 gbeauche 1.15 #if EMUL_TIME_STATS
521     exec68k_count++;
522     const clock_t exec68k_start = clock();
523     #endif
524    
525 gbeauche 1.1 #if SAFE_EXEC_68K
526     if (ReadMacInt32(XLM_RUN_MODE) != MODE_EMUL_OP)
527     printf("FATAL: Execute68k() not called from EMUL_OP mode\n");
528     #endif
529    
530     // Save program counters and branch registers
531     uint32 saved_pc = pc();
532     uint32 saved_lr = lr();
533     uint32 saved_ctr= ctr();
534 gbeauche 1.8 uint32 saved_cr = get_cr();
535 gbeauche 1.1
536     // Create MacOS stack frame
537 gbeauche 1.6 // FIXME: make sure MacOS doesn't expect PPC registers to live on top
538 gbeauche 1.1 uint32 sp = gpr(1);
539 gbeauche 1.6 gpr(1) -= 56;
540 gbeauche 1.1 WriteMacInt32(gpr(1), sp);
541    
542     // Save PowerPC registers
543 gbeauche 1.6 uint32 saved_GPRs[19];
544     memcpy(&saved_GPRs[0], &gpr(13), sizeof(uint32)*(32-13));
545 gbeauche 1.1 #if SAVE_FP_EXEC_68K
546 gbeauche 1.6 double saved_FPRs[18];
547     memcpy(&saved_FPRs[0], &fpr(14), sizeof(double)*(32-14));
548 gbeauche 1.1 #endif
549    
550     // Setup registers for 68k emulator
551 gbeauche 1.2 cr().set(CR_SO_field<2>::mask()); // Supervisor mode
552 gbeauche 1.1 for (int i = 0; i < 8; i++) // d[0]..d[7]
553     gpr(8 + i) = r->d[i];
554     for (int i = 0; i < 7; i++) // a[0]..a[6]
555     gpr(16 + i) = r->a[i];
556     gpr(23) = 0;
557     gpr(24) = entry;
558     gpr(25) = ReadMacInt32(XLM_68K_R25); // MSB of SR
559     gpr(26) = 0;
560     gpr(28) = 0; // VBR
561 gbeauche 1.5 gpr(29) = ntohl(kernel_data->ed.v[0x74 >> 2]); // Pointer to opcode table
562     gpr(30) = ntohl(kernel_data->ed.v[0x78 >> 2]); // Address of emulator
563 gbeauche 1.1 gpr(31) = KernelDataAddr + 0x1000;
564    
565     // Push return address (points to EXEC_RETURN opcode) on stack
566     gpr(1) -= 4;
567     WriteMacInt32(gpr(1), XLM_EXEC_RETURN_OPCODE);
568    
569     // Rentering 68k emulator
570     WriteMacInt32(XLM_RUN_MODE, MODE_68K);
571    
572     // Set r0 to 0 for 68k emulator
573     gpr(0) = 0;
574    
575     // Execute 68k opcode
576     uint32 opcode = ReadMacInt16(gpr(24));
577     gpr(27) = (int32)(int16)ReadMacInt16(gpr(24) += 2);
578     gpr(29) += opcode * 8;
579     execute(gpr(29));
580    
581     // Save r25 (contains current 68k interrupt level)
582     WriteMacInt32(XLM_68K_R25, gpr(25));
583    
584     // Reentering EMUL_OP mode
585     WriteMacInt32(XLM_RUN_MODE, MODE_EMUL_OP);
586    
587     // Save 68k registers
588     for (int i = 0; i < 8; i++) // d[0]..d[7]
589     r->d[i] = gpr(8 + i);
590     for (int i = 0; i < 7; i++) // a[0]..a[6]
591     r->a[i] = gpr(16 + i);
592    
593     // Restore PowerPC registers
594 gbeauche 1.6 memcpy(&gpr(13), &saved_GPRs[0], sizeof(uint32)*(32-13));
595 gbeauche 1.1 #if SAVE_FP_EXEC_68K
596 gbeauche 1.6 memcpy(&fpr(14), &saved_FPRs[0], sizeof(double)*(32-14));
597 gbeauche 1.1 #endif
598    
599     // Cleanup stack
600 gbeauche 1.6 gpr(1) += 56;
601 gbeauche 1.1
602     // Restore program counters and branch registers
603     pc() = saved_pc;
604     lr() = saved_lr;
605     ctr()= saved_ctr;
606 gbeauche 1.8 set_cr(saved_cr);
607 gbeauche 1.15
608     #if EMUL_TIME_STATS
609     exec68k_time += (clock() - exec68k_start);
610     #endif
611 gbeauche 1.1 }
612    
613     // Call MacOS PPC code
614     uint32 sheepshaver_cpu::execute_macos_code(uint32 tvect, int nargs, uint32 const *args)
615     {
616 gbeauche 1.15 #if EMUL_TIME_STATS
617     macos_exec_count++;
618     const clock_t macos_exec_start = clock();
619     #endif
620    
621 gbeauche 1.1 // Save program counters and branch registers
622     uint32 saved_pc = pc();
623     uint32 saved_lr = lr();
624     uint32 saved_ctr= ctr();
625    
626     // Build trampoline with EXEC_RETURN
627 gbeauche 1.21 SheepVar32 trampoline = POWERPC_EXEC_RETURN;
628     lr() = trampoline.addr();
629 gbeauche 1.1
630     gpr(1) -= 64; // Create stack frame
631     uint32 proc = ReadMacInt32(tvect); // Get routine address
632     uint32 toc = ReadMacInt32(tvect + 4); // Get TOC pointer
633    
634     // Save PowerPC registers
635     uint32 regs[8];
636     regs[0] = gpr(2);
637     for (int i = 0; i < nargs; i++)
638     regs[i + 1] = gpr(i + 3);
639    
640     // Prepare and call MacOS routine
641     gpr(2) = toc;
642     for (int i = 0; i < nargs; i++)
643     gpr(i + 3) = args[i];
644     execute(proc);
645     uint32 retval = gpr(3);
646    
647     // Restore PowerPC registers
648     for (int i = 0; i <= nargs; i++)
649     gpr(i + 2) = regs[i];
650    
651     // Cleanup stack
652     gpr(1) += 64;
653    
654     // Restore program counters and branch registers
655     pc() = saved_pc;
656     lr() = saved_lr;
657     ctr()= saved_ctr;
658    
659 gbeauche 1.15 #if EMUL_TIME_STATS
660     macos_exec_time += (clock() - macos_exec_start);
661     #endif
662    
663 gbeauche 1.1 return retval;
664     }
665    
666 gbeauche 1.2 // Execute ppc routine
667     inline void sheepshaver_cpu::execute_ppc(uint32 entry)
668     {
669     // Save branch registers
670     uint32 saved_lr = lr();
671    
672 gbeauche 1.21 SheepVar32 trampoline = POWERPC_EXEC_RETURN;
673     WriteMacInt32(trampoline.addr(), POWERPC_EXEC_RETURN);
674     lr() = trampoline.addr();
675 gbeauche 1.2
676     execute(entry);
677    
678     // Restore branch registers
679     lr() = saved_lr;
680     }
681    
682 gbeauche 1.1 // Resource Manager thunk
683     inline void sheepshaver_cpu::get_resource(uint32 old_get_resource)
684     {
685 gbeauche 1.2 uint32 type = gpr(3);
686     int16 id = gpr(4);
687    
688     // Create stack frame
689     gpr(1) -= 56;
690    
691     // Call old routine
692     execute_ppc(old_get_resource);
693    
694     // Call CheckLoad()
695 gbeauche 1.5 uint32 handle = gpr(3);
696 gbeauche 1.2 check_load_invoc(type, id, handle);
697 gbeauche 1.5 gpr(3) = handle;
698 gbeauche 1.2
699     // Cleanup stack
700     gpr(1) += 56;
701 gbeauche 1.1 }
702    
703    
704     /**
705     * SheepShaver CPU engine interface
706     **/
707    
708 gbeauche 1.41 // PowerPC CPU emulator
709     static sheepshaver_cpu *ppc_cpu = NULL;
710 gbeauche 1.1
711 gbeauche 1.7 void FlushCodeCache(uintptr start, uintptr end)
712     {
713     D(bug("FlushCodeCache(%08x, %08x)\n", start, end));
714 gbeauche 1.41 ppc_cpu->invalidate_cache_range(start, end);
715 gbeauche 1.2 }
716    
717 gbeauche 1.1 // Dump PPC registers
718     static void dump_registers(void)
719     {
720 gbeauche 1.41 ppc_cpu->dump_registers();
721 gbeauche 1.1 }
722    
723     // Dump log
724     static void dump_log(void)
725     {
726 gbeauche 1.41 ppc_cpu->dump_log();
727 gbeauche 1.1 }
728    
729     /*
730     * Initialize CPU emulation
731     */
732    
733 gbeauche 1.74 sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip)
734 gbeauche 1.1 {
735     #if ENABLE_VOSF
736 gbeauche 1.3 // Handle screen fault
737 gbeauche 1.74 extern bool Screen_fault_handler(sigsegv_info_t *sip);
738     if (Screen_fault_handler(sip))
739 gbeauche 1.3 return SIGSEGV_RETURN_SUCCESS;
740 gbeauche 1.1 #endif
741 gbeauche 1.3
742 gbeauche 1.74 const uintptr addr = (uintptr)sigsegv_get_fault_address(sip);
743 gbeauche 1.3 #if HAVE_SIGSEGV_SKIP_INSTRUCTION
744     // Ignore writes to ROM
745 gbeauche 1.52 if ((addr - (uintptr)ROMBaseHost) < ROM_SIZE)
746 gbeauche 1.3 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
747    
748 gbeauche 1.17 // Get program counter of target CPU
749 gbeauche 1.41 sheepshaver_cpu * const cpu = ppc_cpu;
750 gbeauche 1.17 const uint32 pc = cpu->pc();
751    
752     // Fault in Mac ROM or RAM?
753 asvitkine 1.76 bool mac_fault = (pc >= ROMBase) && (pc < (ROMBase + ROM_AREA_SIZE)) || (pc >= RAMBase) && (pc < (RAMBase + RAMSize)) || (pc >= DR_CACHE_BASE && pc < (DR_CACHE_BASE + DR_CACHE_SIZE));
754 gbeauche 1.17 if (mac_fault) {
755    
756     // "VM settings" during MacOS 8 installation
757 asvitkine 1.76 if (pc == ROMBase + 0x488160 && cpu->gpr(20) == 0xf8000000)
758 gbeauche 1.17 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
759    
760     // MacOS 8.5 installation
761 asvitkine 1.76 else if (pc == ROMBase + 0x488140 && cpu->gpr(16) == 0xf8000000)
762 gbeauche 1.17 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
763    
764     // MacOS 8 serial drivers on startup
765 asvitkine 1.76 else if (pc == ROMBase + 0x48e080 && (cpu->gpr(8) == 0xf3012002 || cpu->gpr(8) == 0xf3012000))
766 gbeauche 1.17 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
767    
768     // MacOS 8.1 serial drivers on startup
769 asvitkine 1.76 else if (pc == ROMBase + 0x48c5e0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000))
770 gbeauche 1.17 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
771 asvitkine 1.76 else if (pc == ROMBase + 0x4a10a0 && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000))
772 gbeauche 1.17 return SIGSEGV_RETURN_SKIP_INSTRUCTION;
773 gbeauche 1.43
774     // MacOS 8.6 serial drivers on startup (with DR Cache and OldWorld ROM)
775     else if ((pc - DR_CACHE_BASE) < DR_CACHE_SIZE && (cpu->gpr(16) == 0xf3012002 || cpu->gpr(16) == 0xf3012000))
776     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
777     else if ((pc - DR_CACHE_BASE) < DR_CACHE_SIZE && (cpu->gpr(20) == 0xf3012002 || cpu->gpr(20) == 0xf3012000))
778     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
779 gbeauche 1.17
780 gbeauche 1.30 // Ignore writes to the zero page
781     else if ((uint32)(addr - SheepMem::ZeroPage()) < (uint32)SheepMem::PageSize())
782     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
783    
784 gbeauche 1.17 // Ignore all other faults, if requested
785     if (PrefsFindBool("ignoresegv"))
786     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
787     }
788 gbeauche 1.3 #else
789     #error "FIXME: You don't have the capability to skip instruction within signal handlers"
790 gbeauche 1.1 #endif
791 gbeauche 1.3
792 gbeauche 1.60 fprintf(stderr, "SIGSEGV\n");
793 gbeauche 1.74 fprintf(stderr, " pc %p\n", sigsegv_get_fault_instruction_address(sip));
794     fprintf(stderr, " ea %p\n", sigsegv_get_fault_address(sip));
795 gbeauche 1.1 dump_registers();
796 gbeauche 1.41 ppc_cpu->dump_log();
797 gbeauche 1.1 enter_mon();
798     QuitEmulator();
799 gbeauche 1.3
800     return SIGSEGV_RETURN_FAILURE;
801 gbeauche 1.1 }
802    
803     void init_emul_ppc(void)
804     {
805 gbeauche 1.52 // Get pointer to KernelData in host address space
806     kernel_data = (KernelData *)Mac2HostAddr(KERNEL_DATA_BASE);
807    
808 gbeauche 1.1 // Initialize main CPU emulator
809 gbeauche 1.41 ppc_cpu = new sheepshaver_cpu();
810 asvitkine 1.76 ppc_cpu->set_register(powerpc_registers::GPR(3), any_register((uint32)ROMBase + 0x30d000));
811 gbeauche 1.41 ppc_cpu->set_register(powerpc_registers::GPR(4), any_register(KernelDataAddr + 0x1000));
812 gbeauche 1.1 WriteMacInt32(XLM_RUN_MODE, MODE_68K);
813    
814     #if ENABLE_MON
815     // Install "regs" command in cxmon
816     mon_add_command("regs", dump_registers, "regs Dump PowerPC registers\n");
817     mon_add_command("log", dump_log, "log Dump PowerPC emulation log\n");
818     #endif
819 gbeauche 1.15
820     #if EMUL_TIME_STATS
821     emul_start_time = clock();
822     #endif
823 gbeauche 1.1 }
824    
825     /*
826 gbeauche 1.14 * Deinitialize emulation
827     */
828    
829     void exit_emul_ppc(void)
830     {
831 gbeauche 1.15 #if EMUL_TIME_STATS
832     clock_t emul_end_time = clock();
833    
834     printf("### Statistics for SheepShaver emulation parts\n");
835     const clock_t emul_time = emul_end_time - emul_start_time;
836     printf("Total emulation time : %.1f sec\n", double(emul_time) / double(CLOCKS_PER_SEC));
837     printf("Total interrupt count: %d (%2.1f Hz)\n", interrupt_count,
838     (double(interrupt_count) * CLOCKS_PER_SEC) / double(emul_time));
839 gbeauche 1.44 printf("Total ppc interrupt count: %d (%2.1f %%)\n", ppc_interrupt_count,
840     (double(ppc_interrupt_count) * 100.0) / double(interrupt_count));
841 gbeauche 1.15
842     #define PRINT_STATS(LABEL, VAR_PREFIX) do { \
843     printf("Total " LABEL " count : %d\n", VAR_PREFIX##_count); \
844     printf("Total " LABEL " time : %.1f sec (%.1f%%)\n", \
845     double(VAR_PREFIX##_time) / double(CLOCKS_PER_SEC), \
846     100.0 * double(VAR_PREFIX##_time) / double(emul_time)); \
847     } while (0)
848    
849     PRINT_STATS("Execute68k[Trap] execution", exec68k);
850     PRINT_STATS("NativeOp execution", native_exec);
851     PRINT_STATS("MacOS routine execution", macos_exec);
852    
853     #undef PRINT_STATS
854     printf("\n");
855     #endif
856    
857 gbeauche 1.41 delete ppc_cpu;
858 gbeauche 1.67 ppc_cpu = NULL;
859 gbeauche 1.14 }
860    
861 gbeauche 1.38 #if PPC_ENABLE_JIT && PPC_REENTRANT_JIT
862     // Initialize EmulOp trampolines
863     void init_emul_op_trampolines(basic_dyngen & dg)
864     {
865     typedef void (*func_t)(dyngen_cpu_base, uint32);
866     func_t func;
867    
868     // EmulOp
869     emul_op_trampoline = dg.gen_start();
870     func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_emul_op).ptr();
871     dg.gen_invoke_CPU_T0(func);
872     dg.gen_exec_return();
873     dg.gen_end();
874    
875     // NativeOp
876     native_op_trampoline = dg.gen_start();
877     func = (func_t)nv_mem_fun(&sheepshaver_cpu::execute_native_op).ptr();
878     dg.gen_invoke_CPU_T0(func);
879     dg.gen_exec_return();
880     dg.gen_end();
881    
882     D(bug("EmulOp trampoline: %p\n", emul_op_trampoline));
883     D(bug("NativeOp trampoline: %p\n", native_op_trampoline));
884     }
885     #endif
886    
887 gbeauche 1.14 /*
888 gbeauche 1.1 * Emulation loop
889     */
890    
891     void emul_ppc(uint32 entry)
892     {
893 gbeauche 1.24 #if 0
894 gbeauche 1.41 ppc_cpu->start_log();
895 gbeauche 1.10 #endif
896     // start emulation loop and enable code translation or caching
897 gbeauche 1.41 ppc_cpu->execute(entry);
898 gbeauche 1.1 }
899    
900     /*
901     * Handle PowerPC interrupt
902     */
903    
904 gbeauche 1.2 void TriggerInterrupt(void)
905     {
906 gbeauche 1.64 idle_resume();
907 gbeauche 1.2 #if 0
908     WriteMacInt32(0x16a, ReadMacInt32(0x16a) + 1);
909     #else
910 gbeauche 1.10 // Trigger interrupt to main cpu only
911 gbeauche 1.41 if (ppc_cpu)
912     ppc_cpu->trigger_interrupt();
913 gbeauche 1.2 #endif
914     }
915    
916 gbeauche 1.58 void HandleInterrupt(powerpc_registers *r)
917 gbeauche 1.1 {
918 gbeauche 1.47 #ifdef USE_SDL_VIDEO
919     // We must fill in the events queue in the same thread that did call SDL_SetVideoMode()
920     SDL_PumpEvents();
921     #endif
922    
923 gbeauche 1.1 // Do nothing if interrupts are disabled
924 gbeauche 1.46 if (int32(ReadMacInt32(XLM_IRQ_NEST)) > 0)
925 gbeauche 1.1 return;
926    
927 gbeauche 1.63 // Update interrupt count
928 gbeauche 1.44 #if EMUL_TIME_STATS
929     interrupt_count++;
930     #endif
931 gbeauche 1.40
932 gbeauche 1.1 // Interrupt action depends on current run mode
933     switch (ReadMacInt32(XLM_RUN_MODE)) {
934     case MODE_68K:
935     // 68k emulator active, trigger 68k interrupt level 1
936     WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
937 gbeauche 1.58 r->cr.set(r->cr.get() | tswap32(kernel_data->v[0x674 >> 2]));
938 gbeauche 1.1 break;
939    
940     #if INTERRUPTS_IN_NATIVE_MODE
941     case MODE_NATIVE:
942     // 68k emulator inactive, in nanokernel?
943 gbeauche 1.63 if (r->gpr[1] != KernelDataAddr) {
944 gbeauche 1.39
945 gbeauche 1.1 // Prepare for 68k interrupt level 1
946     WriteMacInt16(tswap32(kernel_data->v[0x67c >> 2]), 1);
947     WriteMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc,
948     ReadMacInt32(tswap32(kernel_data->v[0x658 >> 2]) + 0xdc)
949     | tswap32(kernel_data->v[0x674 >> 2]));
950    
951     // Execute nanokernel interrupt routine (this will activate the 68k emulator)
952 gbeauche 1.2 DisableInterrupt();
953 gbeauche 1.1 if (ROMType == ROMTYPE_NEWWORLD)
954 asvitkine 1.76 ppc_cpu->interrupt(ROMBase + 0x312b1c);
955 gbeauche 1.1 else
956 asvitkine 1.76 ppc_cpu->interrupt(ROMBase + 0x312a3c);
957 gbeauche 1.1 }
958     break;
959     #endif
960    
961     #if INTERRUPTS_IN_EMUL_OP_MODE
962     case MODE_EMUL_OP:
963     // 68k emulator active, within EMUL_OP routine, execute 68k interrupt routine directly when interrupt level is 0
964     if ((ReadMacInt32(XLM_68K_R25) & 7) == 0) {
965 gbeauche 1.44 #if EMUL_TIME_STATS
966     const clock_t interrupt_start = clock();
967     #endif
968 gbeauche 1.1 #if 1
969     // Execute full 68k interrupt routine
970     M68kRegisters r;
971     uint32 old_r25 = ReadMacInt32(XLM_68K_R25); // Save interrupt level
972     WriteMacInt32(XLM_68K_R25, 0x21); // Execute with interrupt level 1
973 gbeauche 1.53 static const uint8 proc_template[] = {
974 gbeauche 1.2 0x3f, 0x3c, 0x00, 0x00, // move.w #$0000,-(sp) (fake format word)
975     0x48, 0x7a, 0x00, 0x0a, // pea @1(pc) (return address)
976     0x40, 0xe7, // move sr,-(sp) (saved SR)
977     0x20, 0x78, 0x00, 0x064, // move.l $64,a0
978     0x4e, 0xd0, // jmp (a0)
979     M68K_RTS >> 8, M68K_RTS & 0xff // @1
980 gbeauche 1.1 };
981 gbeauche 1.53 BUILD_SHEEPSHAVER_PROCEDURE(proc);
982     Execute68k(proc, &r);
983 gbeauche 1.1 WriteMacInt32(XLM_68K_R25, old_r25); // Restore interrupt level
984     #else
985     // Only update cursor
986     if (HasMacStarted()) {
987     if (InterruptFlags & INTFLAG_VIA) {
988     ClearInterruptFlag(INTFLAG_VIA);
989     ADBInterrupt();
990 gbeauche 1.22 ExecuteNative(NATIVE_VIDEO_VBL);
991 gbeauche 1.1 }
992     }
993     #endif
994 gbeauche 1.44 #if EMUL_TIME_STATS
995     interrupt_time += (clock() - interrupt_start);
996     #endif
997 gbeauche 1.1 }
998     break;
999     #endif
1000     }
1001     }
1002    
1003 gbeauche 1.38 // Execute NATIVE_OP routine
1004     void sheepshaver_cpu::execute_native_op(uint32 selector)
1005 gbeauche 1.1 {
1006 gbeauche 1.15 #if EMUL_TIME_STATS
1007     native_exec_count++;
1008     const clock_t native_exec_start = clock();
1009     #endif
1010    
1011 gbeauche 1.1 switch (selector) {
1012     case NATIVE_PATCH_NAME_REGISTRY:
1013     DoPatchNameRegistry();
1014     break;
1015     case NATIVE_VIDEO_INSTALL_ACCEL:
1016     VideoInstallAccel();
1017     break;
1018     case NATIVE_VIDEO_VBL:
1019     VideoVBL();
1020     break;
1021     case NATIVE_VIDEO_DO_DRIVER_IO:
1022 gbeauche 1.52 gpr(3) = (int32)(int16)VideoDoDriverIO(gpr(3), gpr(4), gpr(5), gpr(6), gpr(7));
1023 gbeauche 1.1 break;
1024 gbeauche 1.65 case NATIVE_ETHER_AO_GET_HWADDR:
1025     AO_get_ethernet_address(gpr(3));
1026     break;
1027     case NATIVE_ETHER_AO_ADD_MULTI:
1028     AO_enable_multicast(gpr(3));
1029     break;
1030     case NATIVE_ETHER_AO_DEL_MULTI:
1031     AO_disable_multicast(gpr(3));
1032     break;
1033     case NATIVE_ETHER_AO_SEND_PACKET:
1034     AO_transmit_packet(gpr(3));
1035     break;
1036 gbeauche 1.16 case NATIVE_ETHER_IRQ:
1037     EtherIRQ();
1038     break;
1039     case NATIVE_ETHER_INIT:
1040 gbeauche 1.38 gpr(3) = InitStreamModule((void *)gpr(3));
1041 gbeauche 1.16 break;
1042     case NATIVE_ETHER_TERM:
1043     TerminateStreamModule();
1044     break;
1045     case NATIVE_ETHER_OPEN:
1046 gbeauche 1.38 gpr(3) = ether_open((queue_t *)gpr(3), (void *)gpr(4), gpr(5), gpr(6), (void*)gpr(7));
1047 gbeauche 1.1 break;
1048 gbeauche 1.16 case NATIVE_ETHER_CLOSE:
1049 gbeauche 1.38 gpr(3) = ether_close((queue_t *)gpr(3), gpr(4), (void *)gpr(5));
1050 gbeauche 1.1 break;
1051 gbeauche 1.16 case NATIVE_ETHER_WPUT:
1052 gbeauche 1.38 gpr(3) = ether_wput((queue_t *)gpr(3), (mblk_t *)gpr(4));
1053 gbeauche 1.1 break;
1054 gbeauche 1.16 case NATIVE_ETHER_RSRV:
1055 gbeauche 1.38 gpr(3) = ether_rsrv((queue_t *)gpr(3));
1056 gbeauche 1.1 break;
1057 gbeauche 1.69 case NATIVE_NQD_SYNC_HOOK:
1058 gbeauche 1.38 gpr(3) = NQD_sync_hook(gpr(3));
1059 gbeauche 1.32 break;
1060 gbeauche 1.70 case NATIVE_NQD_UNKNOWN_HOOK:
1061     gpr(3) = NQD_unknown_hook(gpr(3));
1062     break;
1063 gbeauche 1.69 case NATIVE_NQD_BITBLT_HOOK:
1064 gbeauche 1.38 gpr(3) = NQD_bitblt_hook(gpr(3));
1065 gbeauche 1.32 break;
1066 gbeauche 1.69 case NATIVE_NQD_BITBLT:
1067 gbeauche 1.38 NQD_bitblt(gpr(3));
1068 gbeauche 1.32 break;
1069 gbeauche 1.69 case NATIVE_NQD_FILLRECT_HOOK:
1070 gbeauche 1.38 gpr(3) = NQD_fillrect_hook(gpr(3));
1071 gbeauche 1.32 break;
1072 gbeauche 1.69 case NATIVE_NQD_INVRECT:
1073 gbeauche 1.38 NQD_invrect(gpr(3));
1074 gbeauche 1.32 break;
1075 gbeauche 1.69 case NATIVE_NQD_FILLRECT:
1076 gbeauche 1.38 NQD_fillrect(gpr(3));
1077 gbeauche 1.32 break;
1078 gbeauche 1.1 case NATIVE_SERIAL_NOTHING:
1079     case NATIVE_SERIAL_OPEN:
1080     case NATIVE_SERIAL_PRIME_IN:
1081     case NATIVE_SERIAL_PRIME_OUT:
1082     case NATIVE_SERIAL_CONTROL:
1083     case NATIVE_SERIAL_STATUS:
1084     case NATIVE_SERIAL_CLOSE: {
1085     typedef int16 (*SerialCallback)(uint32, uint32);
1086     static const SerialCallback serial_callbacks[] = {
1087     SerialNothing,
1088     SerialOpen,
1089     SerialPrimeIn,
1090     SerialPrimeOut,
1091     SerialControl,
1092     SerialStatus,
1093     SerialClose
1094     };
1095 gbeauche 1.38 gpr(3) = serial_callbacks[selector - NATIVE_SERIAL_NOTHING](gpr(3), gpr(4));
1096 gbeauche 1.16 break;
1097     }
1098     case NATIVE_GET_RESOURCE:
1099 gbeauche 1.68 get_resource(ReadMacInt32(XLM_GET_RESOURCE));
1100     break;
1101 gbeauche 1.16 case NATIVE_GET_1_RESOURCE:
1102 gbeauche 1.68 get_resource(ReadMacInt32(XLM_GET_1_RESOURCE));
1103     break;
1104 gbeauche 1.16 case NATIVE_GET_IND_RESOURCE:
1105 gbeauche 1.68 get_resource(ReadMacInt32(XLM_GET_IND_RESOURCE));
1106     break;
1107 gbeauche 1.16 case NATIVE_GET_1_IND_RESOURCE:
1108 gbeauche 1.68 get_resource(ReadMacInt32(XLM_GET_1_IND_RESOURCE));
1109     break;
1110     case NATIVE_R_GET_RESOURCE:
1111     get_resource(ReadMacInt32(XLM_R_GET_RESOURCE));
1112 gbeauche 1.1 break;
1113 gbeauche 1.7 case NATIVE_MAKE_EXECUTABLE:
1114 gbeauche 1.52 MakeExecutable(0, gpr(4), gpr(5));
1115 gbeauche 1.26 break;
1116     case NATIVE_CHECK_LOAD_INVOC:
1117 gbeauche 1.38 check_load_invoc(gpr(3), gpr(4), gpr(5));
1118 gbeauche 1.2 break;
1119 gbeauche 1.68 case NATIVE_NAMED_CHECK_LOAD_INVOC:
1120     named_check_load_invoc(gpr(3), gpr(4), gpr(5));
1121     break;
1122 gbeauche 1.1 default:
1123     printf("FATAL: NATIVE_OP called with bogus selector %d\n", selector);
1124     QuitEmulator();
1125     break;
1126     }
1127 gbeauche 1.15
1128     #if EMUL_TIME_STATS
1129     native_exec_time += (clock() - native_exec_start);
1130     #endif
1131 gbeauche 1.1 }
1132    
1133     /*
1134     * Execute 68k subroutine (must be ended with EXEC_RETURN)
1135     * This must only be called by the emul_thread when in EMUL_OP mode
1136     * r->a[7] is unused, the routine runs on the caller's stack
1137     */
1138    
1139     void Execute68k(uint32 pc, M68kRegisters *r)
1140     {
1141 gbeauche 1.41 ppc_cpu->execute_68k(pc, r);
1142 gbeauche 1.1 }
1143    
1144     /*
1145     * Execute 68k A-Trap from EMUL_OP routine
1146     * r->a[7] is unused, the routine runs on the caller's stack
1147     */
1148    
1149     void Execute68kTrap(uint16 trap, M68kRegisters *r)
1150     {
1151 gbeauche 1.21 SheepVar proc_var(4);
1152     uint32 proc = proc_var.addr();
1153     WriteMacInt16(proc, trap);
1154     WriteMacInt16(proc + 2, M68K_RTS);
1155     Execute68k(proc, r);
1156 gbeauche 1.1 }
1157    
1158     /*
1159     * Call MacOS PPC code
1160     */
1161    
1162     uint32 call_macos(uint32 tvect)
1163     {
1164 gbeauche 1.41 return ppc_cpu->execute_macos_code(tvect, 0, NULL);
1165 gbeauche 1.1 }
1166    
1167     uint32 call_macos1(uint32 tvect, uint32 arg1)
1168     {
1169     const uint32 args[] = { arg1 };
1170 gbeauche 1.41 return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1171 gbeauche 1.1 }
1172    
1173     uint32 call_macos2(uint32 tvect, uint32 arg1, uint32 arg2)
1174     {
1175     const uint32 args[] = { arg1, arg2 };
1176 gbeauche 1.41 return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1177 gbeauche 1.1 }
1178    
1179     uint32 call_macos3(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3)
1180     {
1181     const uint32 args[] = { arg1, arg2, arg3 };
1182 gbeauche 1.41 return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1183 gbeauche 1.1 }
1184    
1185     uint32 call_macos4(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4)
1186     {
1187     const uint32 args[] = { arg1, arg2, arg3, arg4 };
1188 gbeauche 1.41 return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1189 gbeauche 1.1 }
1190    
1191     uint32 call_macos5(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5)
1192     {
1193     const uint32 args[] = { arg1, arg2, arg3, arg4, arg5 };
1194 gbeauche 1.41 return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1195 gbeauche 1.1 }
1196    
1197     uint32 call_macos6(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6)
1198     {
1199     const uint32 args[] = { arg1, arg2, arg3, arg4, arg5, arg6 };
1200 gbeauche 1.41 return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1201 gbeauche 1.1 }
1202    
1203     uint32 call_macos7(uint32 tvect, uint32 arg1, uint32 arg2, uint32 arg3, uint32 arg4, uint32 arg5, uint32 arg6, uint32 arg7)
1204     {
1205     const uint32 args[] = { arg1, arg2, arg3, arg4, arg5, arg6, arg7 };
1206 gbeauche 1.41 return ppc_cpu->execute_macos_code(tvect, sizeof(args)/sizeof(args[0]), args);
1207 gbeauche 1.1 }