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.74 by gbeauche, 2006-04-16T21:25:41Z

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines