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

# 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_XF86_DGA
52 #include <X11/Xlib.h>
53 #include <X11/Xutil.h>
54 #include <X11/extensions/xf86dga.h>
55 #endif
56
57 #if ENABLE_MON
58 #include "mon.h"
59 #endif
60
61
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 #if ENABLE_MON
95 static struct sigaction sigint_sa; // sigaction for SIGINT handler
96 static void sigint_handler(...);
97 #endif
98
99
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 else if (strcmp(argv[i], "-break") == 0 && ++i < argc)
145 ROMBreakpoint = strtol(argv[i], NULL, 0);
146 else if (strcmp(argv[i], "-rominfo") == 0)
147 PrintROMInfo = true;
148 }
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 #if ENABLE_XF86_DGA && !ENABLE_MON
160 // Fork out, so we can return from fullscreen mode when things get ugly
161 XF86DGAForkApp(DefaultScreen(x_display));
162 #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 // Initialize everything
216 if (!InitAll())
217 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 #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 // 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 // Deinitialize everything
317 ExitAll();
318
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 }
348 #endif
349
350
351 /*
352 * SIGINT handler, enters mon
353 */
354
355 #if ENABLE_MON
356 extern void m68k_dumpstate(uaecptr *nextpc);
357 static void sigint_handler(...)
358 {
359 uaecptr nextpc;
360 m68k_dumpstate(&nextpc);
361 char *arg[2] = {"rmon", NULL};
362 mon(1, arg);
363 QuitEmulator();
364 }
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 }