ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/main_unix.cpp
Revision: 1.11
Committed: 2000-04-10T18:53:02Z (24 years, 7 months ago) by cebix
Branch: MAIN
Changes since 1.10: +1 -1 lines
Log Message:
- updated copyright info: 1999->2000

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * main_unix.cpp - Startup code for Unix
3     *
4 cebix 1.11 * Basilisk II (C) 1997-2000 Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22    
23     #include <stdio.h>
24     #include <stdlib.h>
25     #include <pthread.h>
26     #include <signal.h>
27    
28     #include "cpu_emulation.h"
29     #include "sys.h"
30 cebix 1.3 #include "rom_patches.h"
31 cebix 1.1 #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 cebix 1.3 #define DEBUG 0
42 cebix 1.1 #include "debug.h"
43    
44    
45     #include <X11/Xlib.h>
46    
47     #if ENABLE_GTK
48     #include <gtk/gtk.h>
49     #endif
50    
51 cebix 1.5 #if ENABLE_XF86_DGA
52 cebix 1.1 #include <X11/Xlib.h>
53     #include <X11/Xutil.h>
54     #include <X11/extensions/xf86dga.h>
55     #endif
56    
57 cebix 1.4 #if ENABLE_MON
58     #include "mon.h"
59     #endif
60    
61 cebix 1.9 #ifdef USE_MAPPED_MEMORY
62     #include <sys/mman.h>
63     extern char *address_space, *good_address_map;
64     #endif
65    
66 cebix 1.1
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 cebix 1.4 #if ENABLE_MON
100     static struct sigaction sigint_sa; // sigaction for SIGINT handler
101     static void sigint_handler(...);
102     #endif
103    
104 cebix 1.1
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 cebix 1.4 else if (strcmp(argv[i], "-break") == 0 && ++i < argc)
150     ROMBreakpoint = strtol(argv[i], NULL, 0);
151 cebix 1.6 else if (strcmp(argv[i], "-rominfo") == 0)
152     PrintROMInfo = true;
153 cebix 1.1 }
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 cebix 1.7 #if ENABLE_XF86_DGA && !ENABLE_MON
165 cebix 1.1 // Fork out, so we can return from fullscreen mode when things get ugly
166 cebix 1.2 XF86DGAForkApp(DefaultScreen(x_display));
167 cebix 1.1 #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 cebix 1.9 // Read RAM size
187 cebix 1.1 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 cebix 1.9
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 cebix 1.1 RAMBaseHost = new uint8[RAMSize];
217     ROMBaseHost = new uint8[0x100000];
218 cebix 1.9 #endif
219 cebix 1.1
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 cebix 1.3 // Initialize everything
244     if (!InitAll())
245 cebix 1.1 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 cebix 1.10 if (timer_settime(timer, 0, &req, NULL) < 0) {
272 cebix 1.1 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 cebix 1.4 #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 cebix 1.1 // 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 cebix 1.3 // Deinitialize everything
345     ExitAll();
346 cebix 1.1
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 cebix 1.4 }
376     #endif
377    
378    
379     /*
380     * SIGINT handler, enters mon
381     */
382    
383     #if ENABLE_MON
384 cebix 1.8 extern void m68k_dumpstate(uaecptr *nextpc);
385 cebix 1.4 static void sigint_handler(...)
386     {
387 cebix 1.8 uaecptr nextpc;
388     m68k_dumpstate(&nextpc);
389 cebix 1.4 char *arg[2] = {"rmon", NULL};
390     mon(1, arg);
391     QuitEmulator();
392 cebix 1.1 }
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     }