ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/main_unix.cpp
Revision: 1.1
Committed: 1999-10-03T14:16:25Z (24 years, 9 months ago) by cebix
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

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