ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/main_unix.cpp
Revision: 1.1.1.1 (vendor branch)
Committed: 1999-10-03T14:16:25Z (24 years, 9 months ago) by cebix
Branch: cebix
CVS Tags: release-0_7-2, start
Changes since 1.1: +0 -0 lines
Log Message:
Imported sources

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 "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 }