home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / Unix / main_unix.cpp < prev    next >
C/C++ Source or Header  |  2000-01-21  |  13KB  |  573 lines

  1. /*
  2.  *  main_unix.cpp - Startup code for Unix
  3.  *
  4.  *  Basilisk II (C) 1997-1999 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 <pthread.h>
  26. #include <signal.h>
  27.  
  28. #include "cpu_emulation.h"
  29. #include "sys.h"
  30. #include "rom_patches.h"
  31. #include "xpram.h"
  32. #include "timer.h"
  33. #include "video.h"
  34. #include "prefs.h"
  35. #include "prefs_editor.h"
  36. #include "macos_util.h"
  37. #include "user_strings.h"
  38. #include "version.h"
  39. #include "main.h"
  40.  
  41. #define DEBUG 0
  42. #include "debug.h"
  43.  
  44.  
  45. #include <X11/Xlib.h>
  46.  
  47. #if ENABLE_GTK
  48. #include <gtk/gtk.h>
  49. #endif
  50.  
  51. #if ENABLE_XF86_DGA
  52. #include <X11/Xlib.h>
  53. #include <X11/Xutil.h>
  54. #include <X11/extensions/xf86dga.h>
  55. #endif
  56.  
  57. #if ENABLE_MON
  58. #include "mon.h"
  59. #endif
  60.  
  61. #ifdef USE_MAPPED_MEMORY
  62. #include <sys/mman.h>
  63. extern char *address_space, *good_address_map;
  64. #endif
  65.  
  66.  
  67. // Constants
  68. const char ROM_FILE_NAME[] = "ROM";
  69.  
  70.  
  71. // CPU and FPU type, addressing mode
  72. int CPUType;
  73. bool CPUIs68060;
  74. int FPUType;
  75. bool TwentyFourBitAddressing;
  76.  
  77.  
  78. // Global variables
  79. static char *x_display_name = NULL;                    // X11 display name
  80. Display *x_display = NULL;                            // X11 display handle
  81.  
  82. static bool xpram_thread_active = false;            // Flag: XPRAM watchdog installed
  83. static volatile bool xpram_thread_cancel = false;    // Flag: Cancel XPRAM thread
  84. static pthread_t xpram_thread;                        // XPRAM watchdog
  85.  
  86. static bool tick_thread_active = false;                // Flag: 60Hz thread installed
  87. static volatile bool tick_thread_cancel = false;    // Flag: Cancel 60Hz thread
  88. static pthread_t tick_thread;                        // 60Hz thread
  89. static pthread_attr_t tick_thread_attr;                // 60Hz thread attributes
  90.  
  91. static pthread_mutex_t intflag_lock = PTHREAD_MUTEX_INITIALIZER;    // Mutex to protect InterruptFlags
  92.  
  93. #if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
  94. #define SIG_TIMER SIGRTMIN
  95. static struct sigaction timer_sa;                    // sigaction used for timer
  96. static timer_t timer;                                // 60Hz timer
  97. #endif
  98.  
  99. #if ENABLE_MON
  100. static struct sigaction sigint_sa;                    // sigaction for SIGINT handler
  101. static void sigint_handler(...);
  102. #endif
  103.  
  104.  
  105. // Prototypes
  106. static void *xpram_func(void *arg);
  107. static void *tick_func(void *arg);
  108. static void one_tick(...);
  109.  
  110.  
  111. /*
  112.  *  Ersatz functions
  113.  */
  114.  
  115. extern "C" {
  116.  
  117. #ifndef HAVE_STRDUP
  118. char *strdup(const char *s)
  119. {
  120.     char *n = (char *)malloc(strlen(s) + 1);
  121.     strcpy(n, s);
  122.     return n;
  123. }
  124. #endif
  125.  
  126. }
  127.  
  128.  
  129. /*
  130.  *  Main program
  131.  */
  132.  
  133. int main(int argc, char **argv)
  134. {
  135.     // Initialize variables
  136.     RAMBaseHost = NULL;
  137.     ROMBaseHost = NULL;
  138.     srand(time(NULL));
  139.     tzset();
  140.  
  141.     // Print some info
  142.     printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
  143.     printf(" %s\n", GetString(STR_ABOUT_TEXT2));
  144.  
  145.     // Parse arguments
  146.     for (int i=1; i<argc; i++) {
  147.         if (strcmp(argv[i], "-display") == 0 && ++i < argc)
  148.             x_display_name = argv[i];
  149.         else if (strcmp(argv[i], "-break") == 0 && ++i < argc)
  150.             ROMBreakpoint = strtol(argv[i], NULL, 0);
  151.         else if (strcmp(argv[i], "-rominfo") == 0)
  152.             PrintROMInfo = true;
  153.     }
  154.  
  155.     // Open display
  156.     x_display = XOpenDisplay(x_display_name);
  157.     if (x_display == NULL) {
  158.         char str[256];
  159.         sprintf(str, GetString(STR_NO_XSERVER_ERR), XDisplayName(x_display_name));
  160.         ErrorAlert(str);
  161.         QuitEmulator();
  162.     }
  163.  
  164. #if ENABLE_XF86_DGA && !ENABLE_MON
  165.     // Fork out, so we can return from fullscreen mode when things get ugly
  166.     XF86DGAForkApp(DefaultScreen(x_display));
  167. #endif
  168.  
  169. #if ENABLE_GTK
  170.     // Init GTK
  171.     gtk_set_locale();
  172.     gtk_init(&argc, &argv);
  173. #endif
  174.  
  175.     // Read preferences
  176.     PrefsInit();
  177.  
  178.     // Init system routines
  179.     SysInit();
  180.  
  181.     // Show preferences editor
  182.     if (!PrefsFindBool("nogui"))
  183.         if (!PrefsEditor())
  184.             QuitEmulator();
  185.  
  186.     // Read RAM size
  187.     RAMSize = PrefsFindInt32("ramsize") & 0xfff00000;    // Round down to 1MB boundary
  188.     if (RAMSize < 1024*1024) {
  189.         WarningAlert(GetString(STR_SMALL_RAM_WARN));
  190.         RAMSize = 1024*1024;
  191.     }
  192.  
  193.     // Create areas for Mac RAM and ROM
  194. #ifdef USE_MAPPED_MEMORY
  195.     int fd = open("/dev/zero", O_RDWR);
  196.     good_address_map = (char *)mmap(NULL, 1<<24, PROT_READ, MAP_PRIVATE, fd, 0);
  197.     address_space = (char *)mmap(NULL, 1<<24, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
  198.     if ((int)address_space < 0 || (int)good_address_map < 0) {
  199.         ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
  200.         QuitEmulator();
  201.     }
  202.     RAMBaseHost = (uint8 *)mmap(address_space, RAMSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0);
  203.     ROMBaseHost = (uint8 *)mmap(address_space + 0x00400000, 0x80000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0);
  204.     close(fd);
  205.     char *nam = tmpnam(NULL);
  206.     int good_address_fd = open(nam, O_CREAT | O_RDWR, 0600);
  207.     char buffer[4096];
  208.     memset(buffer, 1, sizeof(buffer));
  209.     write(good_address_fd, buffer, sizeof(buffer));
  210.     unlink(nam);
  211.     for (int i=0; i<RAMSize; i+=4096)
  212.         mmap(good_address_map + i, 4096, PROT_READ, MAP_FIXED | MAP_PRIVATE, good_address_fd, 0);
  213.     for (int i=0; i<0x80000; i+=4096)
  214.         mmap(good_address_map + i + 0x00400000, 4096, PROT_READ, MAP_FIXED | MAP_PRIVATE, good_address_fd, 0);
  215. #else
  216.     RAMBaseHost = new uint8[RAMSize];
  217.     ROMBaseHost = new uint8[0x100000];
  218. #endif
  219.  
  220.     // Get rom file path from preferences
  221.     const char *rom_path = PrefsFindString("rom");
  222.  
  223.     // Load Mac ROM
  224.     int rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME, O_RDONLY);
  225.     if (rom_fd < 0) {
  226.         ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
  227.         QuitEmulator();
  228.     }
  229.     printf(GetString(STR_READING_ROM_FILE));
  230.     ROMSize = lseek(rom_fd, 0, SEEK_END);
  231.     if (ROMSize != 64*1024 && ROMSize != 128*1024 && ROMSize != 256*1024 && ROMSize != 512*1024 && ROMSize != 1024*1024) {
  232.         ErrorAlert(GetString(STR_ROM_SIZE_ERR));
  233.         close(rom_fd);
  234.         QuitEmulator();
  235.     }
  236.     lseek(rom_fd, 0, SEEK_SET);
  237.     if (read(rom_fd, ROMBaseHost, ROMSize) != (ssize_t)ROMSize) {
  238.         ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
  239.         close(rom_fd);
  240.         QuitEmulator();
  241.     }
  242.  
  243.     // Initialize everything
  244.     if (!InitAll())
  245.         QuitEmulator();
  246.  
  247.     // Start XPRAM watchdog thread
  248.     xpram_thread_active = (pthread_create(&xpram_thread, NULL, xpram_func, NULL) == 0);
  249.  
  250. #if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
  251.     // Start 60Hz timer
  252.     sigemptyset(&timer_sa.sa_mask);
  253.     timer_sa.sa_flags = SA_SIGINFO | SA_RESTART;
  254.     timer_sa.sa_sigaction = one_tick;
  255.     if (sigaction(SIG_TIMER, &timer_sa, NULL) < 0) {
  256.         printf("FATAL: cannot set up timer signal handler\n");
  257.         QuitEmulator();
  258.     }
  259.     struct sigevent timer_event;
  260.     timer_event.sigev_notify = SIGEV_SIGNAL;
  261.     timer_event.sigev_signo = SIG_TIMER;
  262.     if (timer_create(CLOCK_REALTIME, &timer_event, &timer) < 0) {
  263.         printf("FATAL: cannot create timer\n");
  264.         QuitEmulator();
  265.     }
  266.     struct itimerspec req;
  267.     req.it_value.tv_sec = 0;
  268.     req.it_value.tv_nsec = 16625000;
  269.     req.it_interval.tv_sec = 0;
  270.     req.it_interval.tv_nsec = 16625000;
  271.     if (timer_settime(timer, 0, &req, NULL) < 0) {
  272.         printf("FATAL: cannot start timer\n");
  273.         QuitEmulator();
  274.     }
  275.  
  276. #else
  277.  
  278.     // Start 60Hz thread
  279.     pthread_attr_init(&tick_thread_attr);
  280. #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
  281.     if (geteuid() == 0) {
  282.         pthread_attr_setinheritsched(&tick_thread_attr, PTHREAD_EXPLICIT_SCHED);
  283.         pthread_attr_setschedpolicy(&tick_thread_attr, SCHED_FIFO);
  284.         struct sched_param fifo_param;
  285.         fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2;
  286.         pthread_attr_setschedparam(&tick_thread_attr, &fifo_param);
  287.     }
  288. #endif
  289.     tick_thread_active = (pthread_create(&tick_thread, &tick_thread_attr, tick_func, NULL) == 0);
  290.     if (!tick_thread_active) {
  291.         printf("FATAL: cannot create tick thread\n");
  292.         QuitEmulator();
  293.     }
  294. #endif
  295.  
  296. #if ENABLE_MON
  297.     // Setup SIGINT handler to enter mon
  298.     sigemptyset(&sigint_sa.sa_mask);
  299.     sigint_sa.sa_flags = 0;
  300.     sigint_sa.sa_handler = sigint_handler;
  301.     sigaction(SIGINT, &sigint_sa, NULL);
  302. #endif
  303.  
  304.     // Start 68k and jump to ROM boot routine
  305.     Start680x0();
  306.  
  307.     QuitEmulator();
  308.     return 0;
  309. }
  310.  
  311.  
  312. /*
  313.  *  Quit emulator
  314.  */
  315.  
  316. void QuitEmulator(void)
  317. {
  318.     // Exit 680x0 emulation
  319.     Exit680x0();
  320.  
  321. #if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
  322.     // Stop 60Hz timer
  323.     timer_delete(timer);
  324. #else
  325.     // Stop 60Hz thread
  326.     if (tick_thread_active) {
  327.         tick_thread_cancel = true;
  328. #ifdef HAVE_PTHREAD_CANCEL
  329.         pthread_cancel(tick_thread);
  330. #endif
  331.         pthread_join(tick_thread, NULL);
  332.     }
  333. #endif
  334.  
  335.     // Stop XPRAM watchdog thread
  336.     if (xpram_thread_active) {
  337.         xpram_thread_cancel = true;
  338. #ifdef HAVE_PTHREAD_CANCEL
  339.         pthread_cancel(xpram_thread);
  340. #endif
  341.         pthread_join(xpram_thread, NULL);
  342.     }
  343.  
  344.     // Deinitialize everything
  345.     ExitAll();
  346.  
  347.     // Delete ROM area
  348.     delete[] ROMBaseHost;
  349.  
  350.     // Delete RAM area
  351.     delete[] RAMBaseHost;
  352.  
  353.     // Exit system routines
  354.     SysExit();
  355.  
  356.     // Exit preferences
  357.     PrefsExit();
  358.  
  359.     // Close X11 server connection
  360.     if (x_display)
  361.         XCloseDisplay(x_display);
  362.  
  363.     exit(0);
  364. }
  365.  
  366.  
  367. /*
  368.  *  Code was patched, flush caches if neccessary (i.e. when using a real 680x0
  369.  *  or a dynamically recompiling emulator)
  370.  */
  371.  
  372. #if EMULATED_68K
  373. void FlushCodeCache(void *start, uint32 size)
  374. {
  375. }
  376. #endif
  377.  
  378.  
  379. /*
  380.  *  SIGINT handler, enters mon
  381.  */
  382.  
  383. #if ENABLE_MON
  384. extern void m68k_dumpstate(uaecptr *nextpc);
  385. static void sigint_handler(...)
  386. {
  387.     uaecptr nextpc;
  388.     m68k_dumpstate(&nextpc);
  389.     char *arg[2] = {"rmon", NULL};
  390.     mon(1, arg);
  391.     QuitEmulator();
  392. }
  393. #endif
  394.  
  395.  
  396. /*
  397.  *  Interrupt flags (must be handled atomically!)
  398.  */
  399.  
  400. uint32 InterruptFlags = 0;
  401.  
  402. void SetInterruptFlag(uint32 flag)
  403. {
  404.     pthread_mutex_lock(&intflag_lock);
  405.     InterruptFlags |= flag;
  406.     pthread_mutex_unlock(&intflag_lock);
  407. }
  408.  
  409. void ClearInterruptFlag(uint32 flag)
  410. {
  411.     pthread_mutex_lock(&intflag_lock);
  412.     InterruptFlags &= ~flag;
  413.     pthread_mutex_unlock(&intflag_lock);
  414. }
  415.  
  416.  
  417. /*
  418.  *  60Hz thread (really 60.15Hz)
  419.  */
  420.  
  421. static void one_tick(...)
  422. {
  423.     static int tick_counter = 0;
  424.  
  425.     // Pseudo Mac 1Hz interrupt, update local time
  426.     if (++tick_counter > 60) {
  427.         tick_counter = 0;
  428.         WriteMacInt32(0x20c, TimerDateTime());
  429.     }
  430.  
  431.     // Trigger 60Hz interrupt
  432.     if (ROMVersion != ROM_VERSION_CLASSIC || HasMacStarted()) {
  433.         SetInterruptFlag(INTFLAG_60HZ);
  434.         TriggerInterrupt();
  435.     }
  436. }
  437.  
  438. static void *tick_func(void *arg)
  439. {
  440.     while (!tick_thread_cancel) {
  441.  
  442.         // Wait
  443. #ifdef HAVE_NANOSLEEP
  444.         struct timespec req = {0, 16625000};
  445.         nanosleep(&req, NULL);
  446. #else
  447.         usleep(16625);
  448. #endif
  449.  
  450.         // Action
  451.         one_tick();
  452.     }
  453.     return NULL;
  454. }
  455.  
  456.  
  457. /*
  458.  *  XPRAM watchdog thread (saves XPRAM every minute)
  459.  */
  460.  
  461. void *xpram_func(void *arg)
  462. {
  463.     uint8 last_xpram[256];
  464.     memcpy(last_xpram, XPRAM, 256);
  465.  
  466.     while (!xpram_thread_cancel) {
  467.         for (int i=0; i<60 && !xpram_thread_cancel; i++) {
  468. #ifdef HAVE_NANOSLEEP
  469.             struct timespec req = {1, 0};
  470.             nanosleep(&req, NULL);
  471. #else
  472.             usleep(1000000);
  473. #endif
  474.         }
  475.         if (memcmp(last_xpram, XPRAM, 256)) {
  476.             memcpy(last_xpram, XPRAM, 256);
  477.             SaveXPRAM();
  478.         }
  479.     }
  480.     return NULL;
  481. }
  482.  
  483.  
  484. /*
  485.  *  Display alert
  486.  */
  487.  
  488. #if ENABLE_GTK
  489. static void dl_destroyed(void)
  490. {
  491.     gtk_main_quit();
  492. }
  493.  
  494. static void dl_quit(GtkWidget *dialog)
  495. {
  496.     gtk_widget_destroy(dialog);
  497. }
  498.  
  499. void display_alert(int title_id, int prefix_id, int button_id, const char *text)
  500. {
  501.     char str[256];
  502.     sprintf(str, GetString(prefix_id), text);
  503.  
  504.     GtkWidget *dialog = gtk_dialog_new();
  505.     gtk_window_set_title(GTK_WINDOW(dialog), GetString(title_id));
  506.     gtk_container_border_width(GTK_CONTAINER(dialog), 5);
  507.     gtk_widget_set_uposition(GTK_WIDGET(dialog), 100, 150);
  508.     gtk_signal_connect(GTK_OBJECT(dialog), "destroy", GTK_SIGNAL_FUNC(dl_destroyed), NULL);
  509.  
  510.     GtkWidget *label = gtk_label_new(str);
  511.     gtk_widget_show(label);
  512.     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, TRUE, TRUE, 0);
  513.  
  514.     GtkWidget *button = gtk_button_new_with_label(GetString(button_id));
  515.     gtk_widget_show(button);
  516.     gtk_signal_connect_object(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(dl_quit), GTK_OBJECT(dialog));
  517.     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button, FALSE, FALSE, 0);
  518.     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
  519.     gtk_widget_grab_default(button);
  520.     gtk_widget_show(dialog);
  521.  
  522.     gtk_main();
  523. }
  524. #endif
  525.  
  526.  
  527. /*
  528.  *  Display error alert
  529.  */
  530.  
  531. void ErrorAlert(const char *text)
  532. {
  533. #if ENABLE_GTK
  534.     if (PrefsFindBool("nogui") || x_display == NULL) {
  535.         printf(GetString(STR_SHELL_ERROR_PREFIX), text);
  536.         return;
  537.     }
  538.     VideoQuitFullScreen();
  539.     display_alert(STR_ERROR_ALERT_TITLE, STR_GUI_ERROR_PREFIX, STR_QUIT_BUTTON, text);
  540. #else
  541.     printf(GetString(STR_SHELL_ERROR_PREFIX), text);
  542. #endif
  543. }
  544.  
  545.  
  546. /*
  547.  *  Display warning alert
  548.  */
  549.  
  550. void WarningAlert(const char *text)
  551. {
  552. #if ENABLE_GTK
  553.     if (PrefsFindBool("nogui") || x_display == NULL) {
  554.         printf(GetString(STR_SHELL_WARNING_PREFIX), text);
  555.         return;
  556.     }
  557.     display_alert(STR_WARNING_ALERT_TITLE, STR_GUI_WARNING_PREFIX, STR_OK_BUTTON, text);
  558. #else
  559.     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
  560. #endif
  561. }
  562.  
  563.  
  564. /*
  565.  *  Display choice alert
  566.  */
  567.  
  568. bool ChoiceAlert(const char *text, const char *pos, const char *neg)
  569. {
  570.     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
  571.     return false;    //!!
  572. }
  573.