ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/main_unix.cpp
Revision: 1.3
Committed: 1999-10-19T17:41:35Z (25 years ago) by cebix
Branch: MAIN
CVS Tags: snapshot-21101999
Changes since 1.2: +6 -108 lines
Log Message:
- added external file system
- moved most init/deinit code to InitAll()/ExitAll() in main.cpp

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