ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/main_unix.cpp
Revision: 1.34
Committed: 2001-06-28T21:19:59Z (23 years, 1 month ago) by cebix
Branch: MAIN
Changes since 1.33: +1 -2 lines
Log Message:
video_x.cpp supports resolution switching in windowed mode: the available
resolutions are 512x384, 640x480, 800x600, 1024x768 and 1280x1024 (the prefs
editor has to be updated to reflect this). The resolution selected in the
prefs editor is used as the default, but it can be changed in the Monitors
control panel. So far only tested with direct addressing.

File Contents

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