ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/main_unix.cpp
Revision: 1.9
Committed: 1999-11-03T10:56:28Z (25 years ago) by cebix
Branch: MAIN
CVS Tags: snapshot-22121999
Changes since 1.8: +31 -3 lines
Log Message:
- imported UAE CPU 0.8.10 changes
- new utility functions Mac_memset, Mac2Host_memcpy, Host2Mac_memcpu and
  Mac2Mac_memcpy
- extfs.cpp: fixed bug in fs_rename() and fs_cat_move() (auxiliary IOParam
  block was not in Mac address space)
- some provisions for using UAE CPU compiler (doesn't work yet)

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