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.6 by cebix, 1999-10-27T16:59:46Z vs.
Revision 1.47 by gbeauche, 2002-05-16T15:48:06Z

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines