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 (24 years, 8 months 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

# Content
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_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 XF86DGAForkApp(DefaultScreen(x_display));
149 #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 // Initialize everything
203 if (!InitAll())
204 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 // Deinitialize everything
296 ExitAll();
297
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 }