ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/main_unix.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/main_unix.cpp (file contents):
Revision 1.11 by cebix, 2000-04-10T18:53:02Z vs.
Revision 1.57 by gbeauche, 2003-11-21T14:19:58Z

# Line 1 | Line 1
1   /*
2   *  main_unix.cpp - Startup code for Unix
3   *
4 < *  Basilisk II (C) 1997-2000 Christian Bauer
4 > *  Basilisk II (C) 1997-2002 Christian Bauer
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
# Line 22 | Line 22
22  
23   #include <stdio.h>
24   #include <stdlib.h>
25 #include <pthread.h>
25   #include <signal.h>
26 + #include <errno.h>
27 + #include <X11/Xlib.h>
28 +
29 + #ifdef HAVE_PTHREADS
30 + # include <pthread.h>
31 + #endif
32 +
33 + #if REAL_ADDRESSING || DIRECT_ADDRESSING
34 + # include <sys/mman.h>
35 + #endif
36 +
37 + #if !EMULATED_68K && defined(__NetBSD__)
38 + # include <m68k/sync_icache.h>
39 + # include <m68k/frame.h>
40 + # include <sys/param.h>
41 + # include <sys/sysctl.h>
42 + struct sigstate {
43 +        int ss_flags;
44 +        struct frame ss_frame;
45 +        struct fpframe ss_fpstate;
46 + };
47 + # define SS_FPSTATE  0x02
48 + # define SS_USERREGS 0x04
49 + #endif
50 +
51 + #ifdef ENABLE_GTK
52 + # include <gtk/gtk.h>
53 + # include <gdk/gdk.h>
54 + # ifdef HAVE_GNOMEUI
55 + #  include <gnome.h>
56 + # endif
57 + #endif
58 +
59 + #ifdef ENABLE_XF86_DGA
60 + # include <X11/Xutil.h>
61 + # include <X11/extensions/xf86dga.h>
62 + #endif
63 +
64 + #include <string>
65 + using std::string;
66  
67   #include "cpu_emulation.h"
68   #include "sys.h"
# Line 31 | Line 70
70   #include "xpram.h"
71   #include "timer.h"
72   #include "video.h"
73 + #include "emul_op.h"
74   #include "prefs.h"
75   #include "prefs_editor.h"
76   #include "macos_util.h"
77   #include "user_strings.h"
78   #include "version.h"
79   #include "main.h"
80 + #include "vm_alloc.h"
81 + #include "sigsegv.h"
82  
83 < #define DEBUG 0
84 < #include "debug.h"
43 <
44 <
45 < #include <X11/Xlib.h>
46 <
47 < #if ENABLE_GTK
48 < #include <gtk/gtk.h>
83 > #if USE_JIT
84 > extern void flush_icache_range(uint32 start, uint32 size); // from compemu_support.cpp
85   #endif
86  
87 < #if ENABLE_XF86_DGA
88 < #include <X11/Xlib.h>
53 < #include <X11/Xutil.h>
54 < #include <X11/extensions/xf86dga.h>
87 > #ifdef ENABLE_MON
88 > # include "mon.h"
89   #endif
90  
91 < #if ENABLE_MON
92 < #include "mon.h"
59 < #endif
60 <
61 < #ifdef USE_MAPPED_MEMORY
62 < #include <sys/mman.h>
63 < extern char *address_space, *good_address_map;
64 < #endif
91 > #define DEBUG 0
92 > #include "debug.h"
93  
94  
95   // Constants
96   const char ROM_FILE_NAME[] = "ROM";
97 + #if !EMULATED_68K
98 + const int SIG_STACK_SIZE = SIGSTKSZ;    // Size of signal stack
99 + #endif
100 + const int SCRATCH_MEM_SIZE = 0x10000;   // Size of scratch memory area
101 +
102 +
103 + #if !EMULATED_68K
104 + // RAM and ROM pointers
105 + uint32 RAMBaseMac;              // RAM base (Mac address space)
106 + uint8 *RAMBaseHost;             // RAM base (host address space)
107 + uint32 RAMSize;                 // Size of RAM
108 + uint32 ROMBaseMac;              // ROM base (Mac address space)
109 + uint8 *ROMBaseHost;             // ROM base (host address space)
110 + uint32 ROMSize;                 // Size of ROM
111 + #endif
112  
113  
114   // CPU and FPU type, addressing mode
# Line 76 | Line 119 | bool TwentyFourBitAddressing;
119  
120  
121   // Global variables
122 < static char *x_display_name = NULL;                                     // X11 display name
122 > char *x_display_name = NULL;                                            // X11 display name
123   Display *x_display = NULL;                                                      // X11 display handle
124  
125 + static uint8 last_xpram[XPRAM_SIZE];                            // Buffer for monitoring XPRAM changes
126 +
127 + #ifdef HAVE_PTHREADS
128 + #if !EMULATED_68K
129 + static pthread_t emul_thread;                                           // Handle of MacOS emulation thread (main thread)
130 + #endif
131 +
132   static bool xpram_thread_active = false;                        // Flag: XPRAM watchdog installed
133   static volatile bool xpram_thread_cancel = false;       // Flag: Cancel XPRAM thread
134   static pthread_t xpram_thread;                                          // XPRAM watchdog
# Line 89 | Line 139 | static pthread_t tick_thread;                                          // 60
139   static pthread_attr_t tick_thread_attr;                         // 60Hz thread attributes
140  
141   static pthread_mutex_t intflag_lock = PTHREAD_MUTEX_INITIALIZER;        // Mutex to protect InterruptFlags
142 + #define LOCK_INTFLAGS pthread_mutex_lock(&intflag_lock)
143 + #define UNLOCK_INTFLAGS pthread_mutex_unlock(&intflag_lock)
144 +
145 + #else
146 +
147 + #define LOCK_INTFLAGS
148 + #define UNLOCK_INTFLAGS
149 +
150 + #endif
151 +
152 + #if !EMULATED_68K
153 + #define SIG_IRQ SIGUSR1
154 + static struct sigaction sigirq_sa;      // Virtual 68k interrupt signal
155 + static struct sigaction sigill_sa;      // Illegal instruction
156 + static void *sig_stack = NULL;          // Stack for signal handlers
157 + uint16 EmulatedSR;                                      // Emulated bits of SR (supervisor bit and interrupt mask)
158 + #endif
159 +
160 + #if USE_SCRATCHMEM_SUBTERFUGE
161 + uint8 *ScratchMem = NULL;                       // Scratch memory for Mac ROM writes
162 + #endif
163 +
164 + #if !defined(HAVE_PTHREADS)
165 + static struct sigaction timer_sa;       // sigaction used for timer
166  
167   #if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
168   #define SIG_TIMER SIGRTMIN
169 < static struct sigaction timer_sa;                                       // sigaction used for timer
96 < static timer_t timer;                                                           // 60Hz timer
169 > static timer_t timer;                           // 60Hz timer
170   #endif
171 + #endif // !HAVE_PTHREADS
172  
173 < #if ENABLE_MON
174 < static struct sigaction sigint_sa;                                      // sigaction for SIGINT handler
173 > #ifdef ENABLE_MON
174 > static struct sigaction sigint_sa;      // sigaction for SIGINT handler
175   static void sigint_handler(...);
176   #endif
177  
178 + #if REAL_ADDRESSING
179 + static bool lm_area_mapped = false;     // Flag: Low Memory area mmap()ped
180 + #endif
181 +
182  
183   // Prototypes
184   static void *xpram_func(void *arg);
185   static void *tick_func(void *arg);
186   static void one_tick(...);
187 + #if !EMULATED_68K
188 + static void sigirq_handler(int sig, int code, struct sigcontext *scp);
189 + static void sigill_handler(int sig, int code, struct sigcontext *scp);
190 + extern "C" void EmulOpTrampoline(void);
191 + #endif
192  
193  
194   /*
# Line 127 | Line 210 | char *strdup(const char *s)
210  
211  
212   /*
213 + *  SIGSEGV handler
214 + */
215 +
216 + static sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
217 + {
218 + #if ENABLE_VOSF
219 +        // Handle screen fault
220 +        extern bool Screen_fault_handler(sigsegv_address_t, sigsegv_address_t);
221 +        if (Screen_fault_handler(fault_address, fault_instruction))
222 +                return SIGSEGV_RETURN_SUCCESS;
223 + #endif
224 +
225 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
226 +        // Ignore writes to ROM
227 +        if (((uintptr)fault_address - (uintptr)ROMBaseHost) < ROMSize)
228 +                return SIGSEGV_RETURN_SKIP_INSTRUCTION;
229 +
230 +        // Ignore all other faults, if requested
231 +        if (PrefsFindBool("ignoresegv"))
232 +                return SIGSEGV_RETURN_SKIP_INSTRUCTION;
233 + #endif
234 +
235 +        return SIGSEGV_RETURN_FAILURE;
236 + }
237 +
238 + /*
239 + *  Dump state when everything went wrong after a SEGV
240 + */
241 +
242 + static void sigsegv_dump_state(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
243 + {
244 +        fprintf(stderr, "Caught SIGSEGV at address %p", fault_address);
245 +        if (fault_instruction != SIGSEGV_INVALID_PC)
246 +                fprintf(stderr, " [IP=%p]", fault_instruction);
247 +        fprintf(stderr, "\n");
248 + #if EMULATED_68K
249 +        uaecptr nextpc;
250 +        extern void m68k_dumpstate(uaecptr *nextpc);
251 +        m68k_dumpstate(&nextpc);
252 + #endif
253 + #if USE_JIT && JIT_DEBUG
254 +        extern void compiler_dumpstate(void);
255 +        compiler_dumpstate();
256 + #endif
257 +        VideoQuitFullScreen();
258 + #ifdef ENABLE_MON
259 +        char *arg[4] = {"mon", "-m", "-r", NULL};
260 +        mon(3, arg);
261 +        QuitEmulator();
262 + #endif
263 + }
264 +
265 +
266 + /*
267   *  Main program
268   */
269  
270 + static void usage(const char *prg_name)
271 + {
272 +        printf(
273 +                "Usage: %s [OPTION...]\n"
274 +                "\nUnix options:\n"
275 +                "  --config FILE\n    read/write configuration from/to FILE\n"
276 +                "  --display STRING\n    X display to use\n"
277 +                "  --break ADDRESS\n    set ROM breakpoint\n"
278 +                "  --rominfo\n    dump ROM information\n", prg_name
279 +        );
280 +        LoadPrefs(); // read the prefs file so PrefsPrintUsage() will print the correct default values
281 +        PrefsPrintUsage();
282 +        exit(0);
283 + }
284 +
285   int main(int argc, char **argv)
286   {
287 +        char str[256];
288 +
289          // Initialize variables
290          RAMBaseHost = NULL;
291          ROMBaseHost = NULL;
# Line 142 | Line 296 | int main(int argc, char **argv)
296          printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
297          printf(" %s\n", GetString(STR_ABOUT_TEXT2));
298  
299 <        // Parse arguments
299 >        // Parse command line arguments
300          for (int i=1; i<argc; i++) {
301 <                if (strcmp(argv[i], "-display") == 0 && ++i < argc)
302 <                        x_display_name = argv[i];
303 <                else if (strcmp(argv[i], "-break") == 0 && ++i < argc)
304 <                        ROMBreakpoint = strtol(argv[i], NULL, 0);
305 <                else if (strcmp(argv[i], "-rominfo") == 0)
301 >                if (strcmp(argv[i], "--help") == 0) {
302 >                        usage(argv[0]);
303 >                } else if (strcmp(argv[i], "--display") == 0) {
304 >                        i++; // don't remove the argument, gtk_init() needs it too
305 >                        if (i < argc)
306 >                                x_display_name = strdup(argv[i]);
307 >                } else if (strcmp(argv[i], "--break") == 0) {
308 >                        argv[i++] = NULL;
309 >                        if (i < argc) {
310 >                                ROMBreakpoint = strtol(argv[i], NULL, 0);
311 >                                argv[i] = NULL;
312 >                        }
313 >                } else if (strcmp(argv[i], "--config") == 0) {
314 >                        argv[i++] = NULL;
315 >                        if (i < argc) {
316 >                                extern string UserPrefsPath; // from prefs_unix.cpp
317 >                                UserPrefsPath = argv[i];
318 >                                argv[i] = NULL;
319 >                        }
320 >                } else if (strcmp(argv[i], "--rominfo") == 0) {
321 >                        argv[i] = NULL;
322                          PrintROMInfo = true;
323 +                }
324 +        }
325 +
326 +        // Remove processed arguments
327 +        for (int i=1; i<argc; i++) {
328 +                int k;
329 +                for (k=i; k<argc; k++)
330 +                        if (argv[k] != NULL)
331 +                                break;
332 +                if (k > i) {
333 +                        k -= i;
334 +                        for (int j=i+k; j<argc; j++)
335 +                                argv[j-k] = argv[j];
336 +                        argc -= k;
337 +                }
338 +        }
339 +
340 + #ifdef ENABLE_GTK
341 + #ifdef HAVE_GNOMEUI
342 +        // Init GNOME/GTK
343 +        char version[16];
344 +        sprintf(version, "%d.%d", VERSION_MAJOR, VERSION_MINOR);
345 +        gnome_init("Basilisk II", version, argc, argv);
346 + #else
347 +        // Init GTK
348 +        gtk_set_locale();
349 +        gtk_init(&argc, &argv);
350 + #endif
351 + #endif
352 +
353 +        // Read preferences
354 +        PrefsInit(argc, argv);
355 +
356 +        // Any command line arguments left?
357 +        for (int i=1; i<argc; i++) {
358 +                if (argv[i][0] == '-') {
359 +                        fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
360 +                        usage(argv[0]);
361 +                }
362          }
363  
364          // Open display
# Line 161 | Line 370 | int main(int argc, char **argv)
370                  QuitEmulator();
371          }
372  
373 < #if ENABLE_XF86_DGA && !ENABLE_MON
373 > #if defined(ENABLE_XF86_DGA) && !defined(ENABLE_MON)
374          // Fork out, so we can return from fullscreen mode when things get ugly
375          XF86DGAForkApp(DefaultScreen(x_display));
376   #endif
377  
169 #if ENABLE_GTK
170        // Init GTK
171        gtk_set_locale();
172        gtk_init(&argc, &argv);
173 #endif
174
175        // Read preferences
176        PrefsInit();
177
378          // Init system routines
379          SysInit();
380  
# Line 183 | Line 383 | int main(int argc, char **argv)
383                  if (!PrefsEditor())
384                          QuitEmulator();
385  
386 +        // Install the handler for SIGSEGV
387 +        if (!sigsegv_install_handler(sigsegv_handler)) {
388 +                sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGSEGV", strerror(errno));
389 +                ErrorAlert(str);
390 +                QuitEmulator();
391 +        }
392 +        
393 +        // Register dump state function when we got mad after a segfault
394 +        sigsegv_set_dump_state(sigsegv_dump_state);
395 +
396          // Read RAM size
397          RAMSize = PrefsFindInt32("ramsize") & 0xfff00000;       // Round down to 1MB boundary
398          if (RAMSize < 1024*1024) {
# Line 190 | Line 400 | int main(int argc, char **argv)
400                  RAMSize = 1024*1024;
401          }
402  
403 <        // Create areas for Mac RAM and ROM
404 < #ifdef USE_MAPPED_MEMORY
405 <    int fd = open("/dev/zero", O_RDWR);
406 <    good_address_map = (char *)mmap(NULL, 1<<24, PROT_READ, MAP_PRIVATE, fd, 0);
407 <    address_space = (char *)mmap(NULL, 1<<24, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
408 <    if ((int)address_space < 0 || (int)good_address_map < 0) {
409 <                ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
410 <                QuitEmulator();
411 <    }
412 <    RAMBaseHost = (uint8 *)mmap(address_space, RAMSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0);
413 <    ROMBaseHost = (uint8 *)mmap(address_space + 0x00400000, 0x80000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0);
414 <    close(fd);
415 <        char *nam = tmpnam(NULL);
416 <    int good_address_fd = open(nam, O_CREAT | O_RDWR, 0600);
417 <        char buffer[4096];
208 <    memset(buffer, 1, sizeof(buffer));
209 <    write(good_address_fd, buffer, sizeof(buffer));
210 <    unlink(nam);
211 <    for (int i=0; i<RAMSize; i+=4096)
212 <        mmap(good_address_map + i, 4096, PROT_READ, MAP_FIXED | MAP_PRIVATE, good_address_fd, 0);
213 <    for (int i=0; i<0x80000; i+=4096)
214 <        mmap(good_address_map + i + 0x00400000, 4096, PROT_READ, MAP_FIXED | MAP_PRIVATE, good_address_fd, 0);
403 > #if REAL_ADDRESSING || DIRECT_ADDRESSING
404 >        RAMSize = RAMSize & -getpagesize();                                     // Round down to page boundary
405 > #endif
406 >        
407 >        // Initialize VM system
408 >        vm_init();
409 >
410 > #if REAL_ADDRESSING
411 >        // Flag: RAM and ROM are contigously allocated from address 0
412 >        bool memory_mapped_from_zero = false;
413 >        
414 >        // Under Solaris/SPARC and NetBSD/m68k, Basilisk II is known to crash
415 >        // when trying to map a too big chunk of memory starting at address 0
416 > #if defined(OS_solaris) || defined(OS_netbsd) || defined(PAGEZERO_HACK)
417 >        const bool can_map_all_memory = false;
418   #else
419 <        RAMBaseHost = new uint8[RAMSize];
217 <        ROMBaseHost = new uint8[0x100000];
419 >        const bool can_map_all_memory = true;
420   #endif
421 +        
422 +        // Try to allocate all memory from 0x0000, if it is not known to crash
423 +        if (can_map_all_memory && (vm_acquire_fixed(0, RAMSize + 0x100000) == 0)) {
424 +                D(bug("Could allocate RAM and ROM from 0x0000\n"));
425 +                memory_mapped_from_zero = true;
426 +        }
427 +        
428 + #ifndef PAGEZERO_HACK
429 +        // Otherwise, just create the Low Memory area (0x0000..0x2000)
430 +        else if (vm_acquire_fixed(0, 0x2000) == 0) {
431 +                D(bug("Could allocate the Low Memory globals\n"));
432 +                lm_area_mapped = true;
433 +        }
434 +        
435 +        // Exit on failure
436 +        else {
437 +                sprintf(str, GetString(STR_LOW_MEM_MMAP_ERR), strerror(errno));
438 +                ErrorAlert(str);
439 +                QuitEmulator();
440 +        }
441 + #endif
442 + #endif /* REAL_ADDRESSING */
443  
444 +        // Create areas for Mac RAM and ROM
445 + #if REAL_ADDRESSING
446 +        if (memory_mapped_from_zero) {
447 +                RAMBaseHost = (uint8 *)0;
448 +                ROMBaseHost = RAMBaseHost + RAMSize;
449 +        }
450 +        else
451 + #endif
452 +        {
453 +                RAMBaseHost = (uint8 *)vm_acquire(RAMSize);
454 +                ROMBaseHost = (uint8 *)vm_acquire(0x100000);
455 +                if (RAMBaseHost == VM_MAP_FAILED || ROMBaseHost == VM_MAP_FAILED) {
456 +                        ErrorAlert(STR_NO_MEM_ERR);
457 +                        QuitEmulator();
458 +                }
459 +        }
460 +
461 + #if USE_SCRATCHMEM_SUBTERFUGE
462 +        // Allocate scratch memory
463 +        ScratchMem = (uint8 *)vm_acquire(SCRATCH_MEM_SIZE);
464 +        if (ScratchMem == VM_MAP_FAILED) {
465 +                ErrorAlert(STR_NO_MEM_ERR);
466 +                QuitEmulator();
467 +        }
468 +        ScratchMem += SCRATCH_MEM_SIZE/2;       // ScratchMem points to middle of block
469 + #endif
470 +
471 + #if DIRECT_ADDRESSING
472 +        // RAMBaseMac shall always be zero
473 +        MEMBaseDiff = (uintptr)RAMBaseHost;
474 +        RAMBaseMac = 0;
475 +        ROMBaseMac = Host2MacAddr(ROMBaseHost);
476 + #endif
477 + #if REAL_ADDRESSING
478 +        RAMBaseMac = (uint32)RAMBaseHost;
479 +        ROMBaseMac = (uint32)ROMBaseHost;
480 + #endif
481 +        D(bug("Mac RAM starts at %p (%08x)\n", RAMBaseHost, RAMBaseMac));
482 +        D(bug("Mac ROM starts at %p (%08x)\n", ROMBaseHost, ROMBaseMac));
483 +        
484          // Get rom file path from preferences
485          const char *rom_path = PrefsFindString("rom");
486  
487          // Load Mac ROM
488          int rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME, O_RDONLY);
489          if (rom_fd < 0) {
490 <                ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
490 >                ErrorAlert(STR_NO_ROM_FILE_ERR);
491                  QuitEmulator();
492          }
493          printf(GetString(STR_READING_ROM_FILE));
494          ROMSize = lseek(rom_fd, 0, SEEK_END);
495          if (ROMSize != 64*1024 && ROMSize != 128*1024 && ROMSize != 256*1024 && ROMSize != 512*1024 && ROMSize != 1024*1024) {
496 <                ErrorAlert(GetString(STR_ROM_SIZE_ERR));
496 >                ErrorAlert(STR_ROM_SIZE_ERR);
497                  close(rom_fd);
498                  QuitEmulator();
499          }
500          lseek(rom_fd, 0, SEEK_SET);
501          if (read(rom_fd, ROMBaseHost, ROMSize) != (ssize_t)ROMSize) {
502 <                ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
502 >                ErrorAlert(STR_ROM_FILE_READ_ERR);
503                  close(rom_fd);
504                  QuitEmulator();
505          }
506  
507 + #if !EMULATED_68K
508 +        // Get CPU model
509 +        int mib[2] = {CTL_HW, HW_MODEL};
510 +        char *model;
511 +        size_t model_len;
512 +        sysctl(mib, 2, NULL, &model_len, NULL, 0);
513 +        model = (char *)malloc(model_len);
514 +        sysctl(mib, 2, model, &model_len, NULL, 0);
515 +        D(bug("Model: %s\n", model));
516 +
517 +        // Set CPU and FPU type
518 +        CPUIs68060 = false;
519 +        if (strstr(model, "020"))
520 +                CPUType = 2;
521 +        else if (strstr(model, "030"))
522 +                CPUType = 3;
523 +        else if (strstr(model, "040"))
524 +                CPUType = 4;
525 +        else if (strstr(model, "060")) {
526 +                CPUType = 4;
527 +                CPUIs68060 = true;
528 +        } else {
529 +                printf("WARNING: Cannot detect CPU type, assuming 68020\n");
530 +                CPUType = 2;
531 +        }
532 +        FPUType = 1;    // NetBSD has an FPU emulation, so the FPU ought to be available at all times
533 +        TwentyFourBitAddressing = false;
534 + #endif
535 +
536          // Initialize everything
537          if (!InitAll())
538                  QuitEmulator();
539 +        D(bug("Initialization complete\n"));
540  
541 <        // Start XPRAM watchdog thread
542 <        xpram_thread_active = (pthread_create(&xpram_thread, NULL, xpram_func, NULL) == 0);
541 > #if !EMULATED_68K
542 >        // (Virtual) supervisor mode, disable interrupts
543 >        EmulatedSR = 0x2700;
544 >
545 > #ifdef HAVE_PTHREADS
546 >        // Get handle of main thread
547 >        emul_thread = pthread_self();
548 > #endif
549 >
550 >        // Create and install stack for signal handlers
551 >        sig_stack = malloc(SIG_STACK_SIZE);
552 >        D(bug("Signal stack at %p\n", sig_stack));
553 >        if (sig_stack == NULL) {
554 >                ErrorAlert(STR_NOT_ENOUGH_MEMORY_ERR);
555 >                QuitEmulator();
556 >        }
557 >        stack_t new_stack;
558 >        new_stack.ss_sp = sig_stack;
559 >        new_stack.ss_flags = 0;
560 >        new_stack.ss_size = SIG_STACK_SIZE;
561 >        if (sigaltstack(&new_stack, NULL) < 0) {
562 >                sprintf(str, GetString(STR_SIGALTSTACK_ERR), strerror(errno));
563 >                ErrorAlert(str);
564 >                QuitEmulator();
565 >        }
566  
567 < #if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
568 <        // Start 60Hz timer
567 >        // Install SIGILL handler for emulating privileged instructions and
568 >        // executing A-Trap and EMUL_OP opcodes
569 >        sigemptyset(&sigill_sa.sa_mask);        // Block virtual 68k interrupts during SIGILL handling
570 >        sigaddset(&sigill_sa.sa_mask, SIG_IRQ);
571 >        sigaddset(&sigill_sa.sa_mask, SIGALRM);
572 >        sigill_sa.sa_handler = (void (*)(int))sigill_handler;
573 >        sigill_sa.sa_flags = SA_ONSTACK;
574 >        if (sigaction(SIGILL, &sigill_sa, NULL) < 0) {
575 >                sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGILL", strerror(errno));
576 >                ErrorAlert(str);
577 >                QuitEmulator();
578 >        }
579 >
580 >        // Install virtual 68k interrupt signal handler
581 >        sigemptyset(&sigirq_sa.sa_mask);
582 >        sigaddset(&sigirq_sa.sa_mask, SIGALRM);
583 >        sigirq_sa.sa_handler = (void (*)(int))sigirq_handler;
584 >        sigirq_sa.sa_flags = SA_ONSTACK | SA_RESTART;
585 >        if (sigaction(SIG_IRQ, &sigirq_sa, NULL) < 0) {
586 >                sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIG_IRQ", strerror(errno));
587 >                ErrorAlert(str);
588 >                QuitEmulator();
589 >        }
590 > #endif
591 >
592 > #ifdef ENABLE_MON
593 >        // Setup SIGINT handler to enter mon
594 >        sigemptyset(&sigint_sa.sa_mask);
595 >        sigint_sa.sa_handler = (void (*)(int))sigint_handler;
596 >        sigint_sa.sa_flags = 0;
597 >        sigaction(SIGINT, &sigint_sa, NULL);
598 > #endif
599 >
600 > #if defined(HAVE_PTHREADS)
601 >
602 >        // POSIX threads available, start 60Hz thread
603 >        Set_pthread_attr(&tick_thread_attr, 0);
604 >        tick_thread_active = (pthread_create(&tick_thread, &tick_thread_attr, tick_func, NULL) == 0);
605 >        if (!tick_thread_active) {
606 >                sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno));
607 >                ErrorAlert(str);
608 >                QuitEmulator();
609 >        }
610 >        D(bug("60Hz thread started\n"));
611 >
612 > #elif defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
613 >
614 >        // POSIX.4 timers and real-time signals available, start 60Hz timer
615          sigemptyset(&timer_sa.sa_mask);
616 +        timer_sa.sa_sigaction = (void (*)(int, siginfo_t *, void *))one_tick;
617          timer_sa.sa_flags = SA_SIGINFO | SA_RESTART;
254        timer_sa.sa_sigaction = one_tick;
618          if (sigaction(SIG_TIMER, &timer_sa, NULL) < 0) {
619 <                printf("FATAL: cannot set up timer signal handler\n");
619 >                sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIG_TIMER", strerror(errno));
620 >                ErrorAlert(str);
621                  QuitEmulator();
622          }
623          struct sigevent timer_event;
624          timer_event.sigev_notify = SIGEV_SIGNAL;
625          timer_event.sigev_signo = SIG_TIMER;
626          if (timer_create(CLOCK_REALTIME, &timer_event, &timer) < 0) {
627 <                printf("FATAL: cannot create timer\n");
627 >                sprintf(str, GetString(STR_TIMER_CREATE_ERR), strerror(errno));
628 >                ErrorAlert(str);
629                  QuitEmulator();
630          }
631          struct itimerspec req;
# Line 269 | Line 634 | int main(int argc, char **argv)
634          req.it_interval.tv_sec = 0;
635          req.it_interval.tv_nsec = 16625000;
636          if (timer_settime(timer, 0, &req, NULL) < 0) {
637 <                printf("FATAL: cannot start timer\n");
637 >                sprintf(str, GetString(STR_TIMER_SETTIME_ERR), strerror(errno));
638 >                ErrorAlert(str);
639                  QuitEmulator();
640          }
641 +        D(bug("60Hz timer started\n"));
642  
643   #else
644  
645 <        // Start 60Hz thread
646 <        pthread_attr_init(&tick_thread_attr);
647 < #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
648 <        if (geteuid() == 0) {
649 <                pthread_attr_setinheritsched(&tick_thread_attr, PTHREAD_EXPLICIT_SCHED);
650 <                pthread_attr_setschedpolicy(&tick_thread_attr, SCHED_FIFO);
651 <                struct sched_param fifo_param;
652 <                fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2;
653 <                pthread_attr_setschedparam(&tick_thread_attr, &fifo_param);
654 <        }
288 < #endif
289 <        tick_thread_active = (pthread_create(&tick_thread, &tick_thread_attr, tick_func, NULL) == 0);
290 <        if (!tick_thread_active) {
291 <                printf("FATAL: cannot create tick thread\n");
645 >        // Start 60Hz timer
646 >        sigemptyset(&timer_sa.sa_mask);         // Block virtual 68k interrupts during SIGARLM handling
647 > #if !EMULATED_68K
648 >        sigaddset(&timer_sa.sa_mask, SIG_IRQ);
649 > #endif
650 >        timer_sa.sa_handler = one_tick;
651 >        timer_sa.sa_flags = SA_ONSTACK | SA_RESTART;
652 >        if (sigaction(SIGALRM, &timer_sa, NULL) < 0) {
653 >                sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGALRM", strerror(errno));
654 >                ErrorAlert(str);
655                  QuitEmulator();
656          }
657 +        struct itimerval req;
658 +        req.it_interval.tv_sec = req.it_value.tv_sec = 0;
659 +        req.it_interval.tv_usec = req.it_value.tv_usec = 16625;
660 +        setitimer(ITIMER_REAL, &req, NULL);
661 +
662   #endif
663  
664 < #if ENABLE_MON
665 <        // Setup SIGINT handler to enter mon
666 <        sigemptyset(&sigint_sa.sa_mask);
667 <        sigint_sa.sa_flags = 0;
668 <        sigint_sa.sa_handler = sigint_handler;
301 <        sigaction(SIGINT, &sigint_sa, NULL);
664 > #ifdef HAVE_PTHREADS
665 >        // Start XPRAM watchdog thread
666 >        memcpy(last_xpram, XPRAM, XPRAM_SIZE);
667 >        xpram_thread_active = (pthread_create(&xpram_thread, NULL, xpram_func, NULL) == 0);
668 >        D(bug("XPRAM thread started\n"));
669   #endif
670  
671          // Start 68k and jump to ROM boot routine
672 +        D(bug("Starting emulation...\n"));
673          Start680x0();
674  
675          QuitEmulator();
# Line 315 | Line 683 | int main(int argc, char **argv)
683  
684   void QuitEmulator(void)
685   {
686 +        D(bug("QuitEmulator\n"));
687 +
688 + #if EMULATED_68K
689          // Exit 680x0 emulation
690          Exit680x0();
691 + #endif
692  
693 < #if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
322 <        // Stop 60Hz timer
323 <        timer_delete(timer);
324 < #else
693 > #if defined(HAVE_PTHREADS)
694          // Stop 60Hz thread
695          if (tick_thread_active) {
696                  tick_thread_cancel = true;
# Line 330 | Line 699 | void QuitEmulator(void)
699   #endif
700                  pthread_join(tick_thread, NULL);
701          }
702 + #elif defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
703 +        // Stop 60Hz timer
704 +        timer_delete(timer);
705 + #else
706 +        struct itimerval req;
707 +        req.it_interval.tv_sec = req.it_value.tv_sec = 0;
708 +        req.it_interval.tv_usec = req.it_value.tv_usec = 0;
709 +        setitimer(ITIMER_REAL, &req, NULL);
710   #endif
711  
712 + #ifdef HAVE_PTHREADS
713          // Stop XPRAM watchdog thread
714          if (xpram_thread_active) {
715                  xpram_thread_cancel = true;
# Line 340 | Line 718 | void QuitEmulator(void)
718   #endif
719                  pthread_join(xpram_thread, NULL);
720          }
721 + #endif
722  
723          // Deinitialize everything
724          ExitAll();
725  
726 <        // Delete ROM area
727 <        delete[] ROMBaseHost;
726 >        // Free ROM/RAM areas
727 >        if (RAMBaseHost != VM_MAP_FAILED) {
728 >                vm_release(RAMBaseHost, RAMSize);
729 >                RAMBaseHost = NULL;
730 >        }
731 >        if (ROMBaseHost != VM_MAP_FAILED) {
732 >                vm_release(ROMBaseHost, 0x100000);
733 >                ROMBaseHost = NULL;
734 >        }
735 >
736 > #if USE_SCRATCHMEM_SUBTERFUGE
737 >        // Delete scratch memory area
738 >        if (ScratchMem != (uint8 *)VM_MAP_FAILED) {
739 >                vm_release((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE);
740 >                ScratchMem = NULL;
741 >        }
742 > #endif
743  
744 <        // Delete RAM area
745 <        delete[] RAMBaseHost;
744 > #if REAL_ADDRESSING
745 >        // Delete Low Memory area
746 >        if (lm_area_mapped)
747 >                vm_release(0, 0x2000);
748 > #endif
749 >        
750 >        // Exit VM wrappers
751 >        vm_exit();
752  
753          // Exit system routines
754          SysExit();
# Line 369 | Line 769 | void QuitEmulator(void)
769   *  or a dynamically recompiling emulator)
770   */
771  
372 #if EMULATED_68K
772   void FlushCodeCache(void *start, uint32 size)
773   {
774 < }
774 > #if USE_JIT
775 >    if (UseJIT)
776 >                flush_icache_range((uintptr)start, size);
777   #endif
778 + #if !EMULATED_68K && defined(__NetBSD__)
779 +        m68k_sync_icache(start, size);
780 + #endif
781 + }
782  
783  
784   /*
785   *  SIGINT handler, enters mon
786   */
787  
788 < #if ENABLE_MON
384 < extern void m68k_dumpstate(uaecptr *nextpc);
788 > #ifdef ENABLE_MON
789   static void sigint_handler(...)
790   {
791 + #if EMULATED_68K
792          uaecptr nextpc;
793 +        extern void m68k_dumpstate(uaecptr *nextpc);
794          m68k_dumpstate(&nextpc);
795 <        char *arg[2] = {"rmon", NULL};
796 <        mon(1, arg);
795 > #endif
796 >        VideoQuitFullScreen();
797 >        char *arg[4] = {"mon", "-m", "-r", NULL};
798 >        mon(3, arg);
799          QuitEmulator();
800   }
801   #endif
802  
803  
804 + #ifdef HAVE_PTHREADS
805 + /*
806 + *  Pthread configuration
807 + */
808 +
809 + void Set_pthread_attr(pthread_attr_t *attr, int priority)
810 + {
811 +        pthread_attr_init(attr);
812 + #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
813 +        // Some of these only work for superuser
814 +        if (geteuid() == 0) {
815 +                pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
816 +                pthread_attr_setschedpolicy(attr, SCHED_FIFO);
817 +                struct sched_param fifo_param;
818 +                fifo_param.sched_priority = ((sched_get_priority_min(SCHED_FIFO) +
819 +                                              sched_get_priority_max(SCHED_FIFO)) / 2 +
820 +                                             priority);
821 +                pthread_attr_setschedparam(attr, &fifo_param);
822 +        }
823 +        if (pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM) != 0) {
824 + #ifdef PTHREAD_SCOPE_BOUND_NP
825 +            // If system scope is not available (eg. we're not running
826 +            // with CAP_SCHED_MGT capability on an SGI box), try bound
827 +            // scope.  It exposes pthread scheduling to the kernel,
828 +            // without setting realtime priority.
829 +            pthread_attr_setscope(attr, PTHREAD_SCOPE_BOUND_NP);
830 + #endif
831 +        }
832 + #endif
833 + }
834 + #endif // HAVE_PTHREADS
835 +
836 +
837 + /*
838 + *  Mutexes
839 + */
840 +
841 + #ifdef HAVE_PTHREADS
842 +
843 + struct B2_mutex {
844 +        B2_mutex() {
845 +            pthread_mutexattr_t attr;
846 +            pthread_mutexattr_init(&attr);
847 +            // Initialize the mutex for priority inheritance --
848 +            // required for accurate timing.
849 + #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
850 +            pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
851 + #endif
852 + #if defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE) && defined(PTHREAD_MUTEX_NORMAL)
853 +            pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
854 + #endif
855 + #ifdef HAVE_PTHREAD_MUTEXATTR_SETPSHARED
856 +            pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
857 + #endif
858 +            pthread_mutex_init(&m, &attr);
859 +            pthread_mutexattr_destroy(&attr);
860 +        }
861 +        ~B2_mutex() {
862 +            pthread_mutex_trylock(&m); // Make sure it's locked before
863 +            pthread_mutex_unlock(&m);  // unlocking it.
864 +            pthread_mutex_destroy(&m);
865 +        }
866 +        pthread_mutex_t m;
867 + };
868 +
869 + B2_mutex *B2_create_mutex(void)
870 + {
871 +        return new B2_mutex;
872 + }
873 +
874 + void B2_lock_mutex(B2_mutex *mutex)
875 + {
876 +        pthread_mutex_lock(&mutex->m);
877 + }
878 +
879 + void B2_unlock_mutex(B2_mutex *mutex)
880 + {
881 +        pthread_mutex_unlock(&mutex->m);
882 + }
883 +
884 + void B2_delete_mutex(B2_mutex *mutex)
885 + {
886 +        delete mutex;
887 + }
888 +
889 + #else
890 +
891 + struct B2_mutex {
892 +        int dummy;
893 + };
894 +
895 + B2_mutex *B2_create_mutex(void)
896 + {
897 +        return new B2_mutex;
898 + }
899 +
900 + void B2_lock_mutex(B2_mutex *mutex)
901 + {
902 + }
903 +
904 + void B2_unlock_mutex(B2_mutex *mutex)
905 + {
906 + }
907 +
908 + void B2_delete_mutex(B2_mutex *mutex)
909 + {
910 +        delete mutex;
911 + }
912 +
913 + #endif
914 +
915 +
916   /*
917   *  Interrupt flags (must be handled atomically!)
918   */
919  
920   uint32 InterruptFlags = 0;
921  
922 + #if EMULATED_68K
923   void SetInterruptFlag(uint32 flag)
924   {
925 <        pthread_mutex_lock(&intflag_lock);
925 >        LOCK_INTFLAGS;
926          InterruptFlags |= flag;
927 <        pthread_mutex_unlock(&intflag_lock);
927 >        UNLOCK_INTFLAGS;
928   }
929  
930   void ClearInterruptFlag(uint32 flag)
931   {
932 <        pthread_mutex_lock(&intflag_lock);
932 >        LOCK_INTFLAGS;
933          InterruptFlags &= ~flag;
934 <        pthread_mutex_unlock(&intflag_lock);
934 >        UNLOCK_INTFLAGS;
935 > }
936 > #endif
937 >
938 > #if !EMULATED_68K
939 > void TriggerInterrupt(void)
940 > {
941 > #if defined(HAVE_PTHREADS)
942 >        pthread_kill(emul_thread, SIG_IRQ);
943 > #else
944 >        raise(SIG_IRQ);
945 > #endif
946 > }
947 >
948 > void TriggerNMI(void)
949 > {
950 >        // not yet supported
951 > }
952 > #endif
953 >
954 >
955 > /*
956 > *  XPRAM watchdog thread (saves XPRAM every minute)
957 > */
958 >
959 > static void xpram_watchdog(void)
960 > {
961 >        if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
962 >                memcpy(last_xpram, XPRAM, XPRAM_SIZE);
963 >                SaveXPRAM();
964 >        }
965   }
966  
967 + #ifdef HAVE_PTHREADS
968 + static void *xpram_func(void *arg)
969 + {
970 +        while (!xpram_thread_cancel) {
971 +                for (int i=0; i<60 && !xpram_thread_cancel; i++)
972 +                        Delay_usec(999999);             // Only wait 1 second so we quit promptly when xpram_thread_cancel becomes true
973 +                xpram_watchdog();
974 +        }
975 +        return NULL;
976 + }
977 + #endif
978 +
979  
980   /*
981   *  60Hz thread (really 60.15Hz)
982   */
983  
984 + static void one_second(void)
985 + {
986 +        // Pseudo Mac 1Hz interrupt, update local time
987 +        WriteMacInt32(0x20c, TimerDateTime());
988 +
989 +        SetInterruptFlag(INTFLAG_1HZ);
990 +        TriggerInterrupt();
991 +
992 + #ifndef HAVE_PTHREADS
993 +        static int second_counter = 0;
994 +        if (++second_counter > 60) {
995 +                second_counter = 0;
996 +                xpram_watchdog();
997 +        }
998 + #endif
999 + }
1000 +
1001   static void one_tick(...)
1002   {
1003          static int tick_counter = 0;
424
425        // Pseudo Mac 1Hz interrupt, update local time
1004          if (++tick_counter > 60) {
1005                  tick_counter = 0;
1006 <                WriteMacInt32(0x20c, TimerDateTime());
1006 >                one_second();
1007          }
1008  
1009 + #ifndef HAVE_PTHREADS
1010 +        // No threads available, perform video refresh and networking from here
1011 +        VideoRefresh();
1012 +        SetInterruptFlag(INTFLAG_ETHER);
1013 + #endif
1014 +
1015          // Trigger 60Hz interrupt
1016          if (ROMVersion != ROM_VERSION_CLASSIC || HasMacStarted()) {
1017                  SetInterruptFlag(INTFLAG_60HZ);
# Line 435 | Line 1019 | static void one_tick(...)
1019          }
1020   }
1021  
1022 + #ifdef HAVE_PTHREADS
1023   static void *tick_func(void *arg)
1024   {
1025 +        uint64 start = GetTicks_usec();
1026 +        int64 ticks = 0;
1027 +        uint64 next = GetTicks_usec();
1028          while (!tick_thread_cancel) {
441
442                // Wait
443 #ifdef HAVE_NANOSLEEP
444                struct timespec req = {0, 16625000};
445                nanosleep(&req, NULL);
446 #else
447                usleep(16625);
448 #endif
449
450                // Action
1029                  one_tick();
1030 +                next += 16625;
1031 +                int64 delay = next - GetTicks_usec();
1032 +                if (delay > 0)
1033 +                        Delay_usec(delay);
1034 +                else if (delay < -16625)
1035 +                        next = GetTicks_usec();
1036 +                ticks++;
1037          }
1038 +        uint64 end = GetTicks_usec();
1039 +        D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
1040          return NULL;
1041   }
1042 + #endif
1043  
1044  
1045 + #if !EMULATED_68K
1046   /*
1047 < *  XPRAM watchdog thread (saves XPRAM every minute)
1047 > *  Virtual 68k interrupt handler
1048   */
1049  
1050 < void *xpram_func(void *arg)
1050 > static void sigirq_handler(int sig, int code, struct sigcontext *scp)
1051   {
1052 <        uint8 last_xpram[256];
1053 <        memcpy(last_xpram, XPRAM, 256);
1052 >        // Interrupts disabled? Then do nothing
1053 >        if (EmulatedSR & 0x0700)
1054 >                return;
1055  
1056 <        while (!xpram_thread_cancel) {
1057 <                for (int i=0; i<60 && !xpram_thread_cancel; i++) {
1058 < #ifdef HAVE_NANOSLEEP
1059 <                        struct timespec req = {1, 0};
1060 <                        nanosleep(&req, NULL);
1061 < #else
1062 <                        usleep(1000000);
1063 < #endif
1056 >        struct sigstate *state = (struct sigstate *)scp->sc_ap;
1057 >        M68kRegisters *regs = (M68kRegisters *)&state->ss_frame;
1058 >
1059 >        // Set up interrupt frame on stack
1060 >        uint32 a7 = regs->a[7];
1061 >        a7 -= 2;
1062 >        WriteMacInt16(a7, 0x64);
1063 >        a7 -= 4;
1064 >        WriteMacInt32(a7, scp->sc_pc);
1065 >        a7 -= 2;
1066 >        WriteMacInt16(a7, scp->sc_ps | EmulatedSR);
1067 >        scp->sc_sp = regs->a[7] = a7;
1068 >
1069 >        // Set interrupt level
1070 >        EmulatedSR |= 0x2100;
1071 >
1072 >        // Jump to MacOS interrupt handler on return
1073 >        scp->sc_pc = ReadMacInt32(0x64);
1074 > }
1075 >
1076 >
1077 > /*
1078 > *  SIGILL handler, for emulation of privileged instructions and executing
1079 > *  A-Trap and EMUL_OP opcodes
1080 > */
1081 >
1082 > static void sigill_handler(int sig, int code, struct sigcontext *scp)
1083 > {
1084 >        struct sigstate *state = (struct sigstate *)scp->sc_ap;
1085 >        uint16 *pc = (uint16 *)scp->sc_pc;
1086 >        uint16 opcode = *pc;
1087 >        M68kRegisters *regs = (M68kRegisters *)&state->ss_frame;
1088 >
1089 > #define INC_PC(n) scp->sc_pc += (n)
1090 >
1091 > #define GET_SR (scp->sc_ps | EmulatedSR)
1092 >
1093 > #define STORE_SR(v) \
1094 >        scp->sc_ps = (v) & 0xff; \
1095 >        EmulatedSR = (v) & 0xe700; \
1096 >        if (((v) & 0x0700) == 0 && InterruptFlags) \
1097 >                TriggerInterrupt();
1098 >
1099 > //printf("opcode %04x at %p, sr %04x, emul_sr %04x\n", opcode, pc, scp->sc_ps, EmulatedSR);
1100 >
1101 >        if ((opcode & 0xf000) == 0xa000) {
1102 >
1103 >                // A-Line instruction, set up A-Line trap frame on stack
1104 >                uint32 a7 = regs->a[7];
1105 >                a7 -= 2;
1106 >                WriteMacInt16(a7, 0x28);
1107 >                a7 -= 4;
1108 >                WriteMacInt32(a7, (uint32)pc);
1109 >                a7 -= 2;
1110 >                WriteMacInt16(a7, GET_SR);
1111 >                scp->sc_sp = regs->a[7] = a7;
1112 >
1113 >                // Jump to MacOS A-Line handler on return
1114 >                scp->sc_pc = ReadMacInt32(0x28);
1115 >
1116 >        } else if ((opcode & 0xff00) == 0x7100) {
1117 >
1118 >                // Extended opcode, push registers on user stack
1119 >                uint32 a7 = regs->a[7];
1120 >                a7 -= 4;
1121 >                WriteMacInt32(a7, (uint32)pc);
1122 >                a7 -= 2;
1123 >                WriteMacInt16(a7, scp->sc_ps);
1124 >                for (int i=7; i>=0; i--) {
1125 >                        a7 -= 4;
1126 >                        WriteMacInt32(a7, regs->a[i]);
1127 >                }
1128 >                for (int i=7; i>=0; i--) {
1129 >                        a7 -= 4;
1130 >                        WriteMacInt32(a7, regs->d[i]);
1131                  }
1132 <                if (memcmp(last_xpram, XPRAM, 256)) {
1133 <                        memcpy(last_xpram, XPRAM, 256);
1134 <                        SaveXPRAM();
1132 >                scp->sc_sp = regs->a[7] = a7;
1133 >
1134 >                // Jump to EmulOp trampoline code on return
1135 >                scp->sc_pc = (uint32)EmulOpTrampoline;
1136 >                
1137 >        } else switch (opcode) {        // Emulate privileged instructions
1138 >
1139 >                case 0x40e7:    // move sr,-(sp)
1140 >                        regs->a[7] -= 2;
1141 >                        WriteMacInt16(regs->a[7], GET_SR);
1142 >                        scp->sc_sp = regs->a[7];
1143 >                        INC_PC(2);
1144 >                        break;
1145 >
1146 >                case 0x46df: {  // move (sp)+,sr
1147 >                        uint16 sr = ReadMacInt16(regs->a[7]);
1148 >                        STORE_SR(sr);
1149 >                        regs->a[7] += 2;
1150 >                        scp->sc_sp = regs->a[7];
1151 >                        INC_PC(2);
1152 >                        break;
1153 >                }
1154 >
1155 >                case 0x007c: {  // ori #xxxx,sr
1156 >                        uint16 sr = GET_SR | pc[1];
1157 >                        scp->sc_ps = sr & 0xff;         // oring bits into the sr can't enable interrupts, so we don't need to call STORE_SR
1158 >                        EmulatedSR = sr & 0xe700;
1159 >                        INC_PC(4);
1160 >                        break;
1161                  }
1162 +
1163 +                case 0x027c: {  // andi #xxxx,sr
1164 +                        uint16 sr = GET_SR & pc[1];
1165 +                        STORE_SR(sr);
1166 +                        INC_PC(4);
1167 +                        break;
1168 +                }
1169 +
1170 +                case 0x46fc:    // move #xxxx,sr
1171 +                        STORE_SR(pc[1]);
1172 +                        INC_PC(4);
1173 +                        break;
1174 +
1175 +                case 0x46ef: {  // move (xxxx,sp),sr
1176 +                        uint16 sr = ReadMacInt16(regs->a[7] + (int32)(int16)pc[1]);
1177 +                        STORE_SR(sr);
1178 +                        INC_PC(4);
1179 +                        break;
1180 +                }
1181 +
1182 +                case 0x46d8:    // move (a0)+,sr
1183 +                case 0x46d9: {  // move (a1)+,sr
1184 +                        uint16 sr = ReadMacInt16(regs->a[opcode & 7]);
1185 +                        STORE_SR(sr);
1186 +                        regs->a[opcode & 7] += 2;
1187 +                        INC_PC(2);
1188 +                        break;
1189 +                }
1190 +
1191 +                case 0x40f8:    // move sr,xxxx.w
1192 +                        WriteMacInt16(pc[1], GET_SR);
1193 +                        INC_PC(4);
1194 +                        break;
1195 +
1196 +                case 0x40d0:    // move sr,(a0)
1197 +                case 0x40d1:    // move sr,(a1)
1198 +                case 0x40d2:    // move sr,(a2)
1199 +                case 0x40d3:    // move sr,(a3)
1200 +                case 0x40d4:    // move sr,(a4)
1201 +                case 0x40d5:    // move sr,(a5)
1202 +                case 0x40d6:    // move sr,(a6)
1203 +                case 0x40d7:    // move sr,(sp)
1204 +                        WriteMacInt16(regs->a[opcode & 7], GET_SR);
1205 +                        INC_PC(2);
1206 +                        break;
1207 +
1208 +                case 0x40c0:    // move sr,d0
1209 +                case 0x40c1:    // move sr,d1
1210 +                case 0x40c2:    // move sr,d2
1211 +                case 0x40c3:    // move sr,d3
1212 +                case 0x40c4:    // move sr,d4
1213 +                case 0x40c5:    // move sr,d5
1214 +                case 0x40c6:    // move sr,d6
1215 +                case 0x40c7:    // move sr,d7
1216 +                        regs->d[opcode & 7] = GET_SR;
1217 +                        INC_PC(2);
1218 +                        break;
1219 +
1220 +                case 0x46c0:    // move d0,sr
1221 +                case 0x46c1:    // move d1,sr
1222 +                case 0x46c2:    // move d2,sr
1223 +                case 0x46c3:    // move d3,sr
1224 +                case 0x46c4:    // move d4,sr
1225 +                case 0x46c5:    // move d5,sr
1226 +                case 0x46c6:    // move d6,sr
1227 +                case 0x46c7: {  // move d7,sr
1228 +                        uint16 sr = regs->d[opcode & 7];
1229 +                        STORE_SR(sr);
1230 +                        INC_PC(2);
1231 +                        break;
1232 +                }
1233 +
1234 +                case 0xf327:    // fsave -(sp)
1235 +                        regs->a[7] -= 4;
1236 +                        WriteMacInt32(regs->a[7], 0x41000000);  // Idle frame
1237 +                        scp->sc_sp = regs->a[7];
1238 +                        INC_PC(2);
1239 +                        break;
1240 +
1241 +                case 0xf35f:    // frestore (sp)+
1242 +                        regs->a[7] += 4;
1243 +                        scp->sc_sp = regs->a[7];
1244 +                        INC_PC(2);
1245 +                        break;
1246 +
1247 +                case 0x4e73: {  // rte
1248 +                        uint32 a7 = regs->a[7];
1249 +                        uint16 sr = ReadMacInt16(a7);
1250 +                        a7 += 2;
1251 +                        scp->sc_ps = sr & 0xff;
1252 +                        EmulatedSR = sr & 0xe700;
1253 +                        scp->sc_pc = ReadMacInt32(a7);
1254 +                        a7 += 4;
1255 +                        uint16 format = ReadMacInt16(a7) >> 12;
1256 +                        a7 += 2;
1257 +                        static const int frame_adj[16] = {
1258 +                                0, 0, 4, 4, 8, 0, 0, 52, 50, 12, 24, 84, 16, 0, 0, 0
1259 +                        };
1260 +                        scp->sc_sp = regs->a[7] = a7 + frame_adj[format];
1261 +                        break;
1262 +                }
1263 +
1264 +                case 0x4e7a:    // movec cr,x
1265 +                        switch (pc[1]) {
1266 +                                case 0x0002:    // movec cacr,d0
1267 +                                        regs->d[0] = 0x3111;
1268 +                                        break;
1269 +                                case 0x1002:    // movec cacr,d1
1270 +                                        regs->d[1] = 0x3111;
1271 +                                        break;
1272 +                                case 0x0003:    // movec tc,d0
1273 +                                case 0x0004:    // movec itt0,d0
1274 +                                case 0x0005:    // movec itt1,d0
1275 +                                case 0x0006:    // movec dtt0,d0
1276 +                                case 0x0007:    // movec dtt1,d0
1277 +                                case 0x0806:    // movec urp,d0
1278 +                                case 0x0807:    // movec srp,d0
1279 +                                        regs->d[0] = 0;
1280 +                                        break;
1281 +                                case 0x1000:    // movec sfc,d1
1282 +                                case 0x1001:    // movec dfc,d1
1283 +                                case 0x1003:    // movec tc,d1
1284 +                                case 0x1801:    // movec vbr,d1
1285 +                                        regs->d[1] = 0;
1286 +                                        break;
1287 +                                case 0x8801:    // movec vbr,a0
1288 +                                        regs->a[0] = 0;
1289 +                                        break;
1290 +                                case 0x9801:    // movec vbr,a1
1291 +                                        regs->a[1] = 0;
1292 +                                        break;
1293 +                                default:
1294 +                                        goto ill;
1295 +                        }
1296 +                        INC_PC(4);
1297 +                        break;
1298 +
1299 +                case 0x4e7b:    // movec x,cr
1300 +                        switch (pc[1]) {
1301 +                                case 0x1000:    // movec d1,sfc
1302 +                                case 0x1001:    // movec d1,dfc
1303 +                                case 0x0801:    // movec d0,vbr
1304 +                                case 0x1801:    // movec d1,vbr
1305 +                                        break;
1306 +                                case 0x0002:    // movec d0,cacr
1307 +                                case 0x1002:    // movec d1,cacr
1308 +                                        FlushCodeCache(NULL, 0);
1309 +                                        break;
1310 +                                default:
1311 +                                        goto ill;
1312 +                        }
1313 +                        INC_PC(4);
1314 +                        break;
1315 +
1316 +                case 0xf478:    // cpusha dc
1317 +                case 0xf4f8:    // cpusha dc/ic
1318 +                        FlushCodeCache(NULL, 0);
1319 +                        INC_PC(2);
1320 +                        break;
1321 +
1322 +                default:
1323 + ill:            printf("SIGILL num %d, code %d\n", sig, code);
1324 +                        printf(" context %p:\n", scp);
1325 +                        printf("  onstack %08x\n", scp->sc_onstack);
1326 +                        printf("  sp %08x\n", scp->sc_sp);
1327 +                        printf("  fp %08x\n", scp->sc_fp);
1328 +                        printf("  pc %08x\n", scp->sc_pc);
1329 +                        printf("   opcode %04x\n", opcode);
1330 +                        printf("  sr %08x\n", scp->sc_ps);
1331 +                        printf(" state %p:\n", state);
1332 +                        printf("  flags %d\n", state->ss_flags);
1333 +                        for (int i=0; i<8; i++)
1334 +                                printf("  d%d %08x\n", i, state->ss_frame.f_regs[i]);
1335 +                        for (int i=0; i<8; i++)
1336 +                                printf("  a%d %08x\n", i, state->ss_frame.f_regs[i+8]);
1337 +
1338 +                        VideoQuitFullScreen();
1339 + #ifdef ENABLE_MON
1340 +                        char *arg[4] = {"mon", "-m", "-r", NULL};
1341 +                        mon(3, arg);
1342 + #endif
1343 +                        QuitEmulator();
1344 +                        break;
1345          }
480        return NULL;
1346   }
1347 + #endif
1348  
1349  
1350   /*
1351   *  Display alert
1352   */
1353  
1354 < #if ENABLE_GTK
1354 > #ifdef ENABLE_GTK
1355   static void dl_destroyed(void)
1356   {
1357          gtk_main_quit();
# Line 530 | Line 1396 | void display_alert(int title_id, int pre
1396  
1397   void ErrorAlert(const char *text)
1398   {
1399 < #if ENABLE_GTK
1399 > #ifdef ENABLE_GTK
1400          if (PrefsFindBool("nogui") || x_display == NULL) {
1401                  printf(GetString(STR_SHELL_ERROR_PREFIX), text);
1402                  return;
# Line 549 | Line 1415 | void ErrorAlert(const char *text)
1415  
1416   void WarningAlert(const char *text)
1417   {
1418 < #if ENABLE_GTK
1418 > #ifdef ENABLE_GTK
1419          if (PrefsFindBool("nogui") || x_display == NULL) {
1420                  printf(GetString(STR_SHELL_WARNING_PREFIX), text);
1421                  return;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines