ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/main_unix.cpp
Revision: 1.38
Committed: 2001-07-07T09:07:38Z (23 years ago) by gbeauche
Branch: MAIN
Changes since 1.37: +10 -10 lines
Log Message:
- Try to map memory contiguously with base addresses returned in increasing
  order. No host memory region used for Mac emulation (ScratchMem, RAM, ROM,
  frame buffer) shall be allocated below the RAM space. Actually, MEMBaseDiff
  should be set to the min(above-mentioned address spaces).
  ==> Temporary fix for 64-bit addressing systems (e.g. Linux/ia64)

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