ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/main_unix.cpp
Revision: 1.8
Committed: 1999-10-31T23:18:36Z (25 years ago) by cebix
Branch: MAIN
CVS Tags: snapshot-02111999
Changes since 1.7: +3 -0 lines
Log Message:
- removed MemoryDispatch() replacement; routine from ROM is now used if
  possible
- rom_patches.cpp: check for double PACK 4 resources; if only one is found,
  assume that the ROM requires an FPU and issue a warning if FPU emulation
  is turned off
- UAE CPU opcode routines no longer return the cycle count
- main_unix.cpp: pressing Ctrl-C dumps the UAE CPU state before entering mon
- sys_unix.cpp: under Linux, partition sizes are read with BLKGETSIZE instead
  of llseek()

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