home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / Unix / main_unix.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-04-01  |  32.2 KB  |  1,346 lines

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