ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/main_unix.cpp
Revision: 1.47
Committed: 2002-05-16T15:48:06Z (22 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.46: +27 -0 lines
Log Message:
- video_vosh.h (Screen_fault_handler): Move unrecoverable fault case to...
- main_unix.cpp (sigsegv_dump_state): ... Here.
- sigsegv.h (sigsegv_fault_handler_t): Rename from sigsegv_handler_t.
- sigsegv.h (sigsegv_state_dumper_t): New.

File Contents

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