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.7 by cebix, 1999-10-28T15:33:14Z vs.
Revision 1.82 by asvitkine, 2012-04-01T15:05:55Z

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines