ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/main_unix.cpp
Revision: 1.82
Committed: 2012-04-01T15:05:55Z (12 years, 1 month ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.81: +1 -1 lines
Log Message:
|Description: important compiler warnings fixes
| This patch fix a compiler warning about the direct printing of strings
| using formatted printing functions without the use of a format string.
|Author: Giulio Paci <giuliopaci@gmail.com>
|Forwarded: no
|Last-Update: 2012-03-04

File Contents

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