ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/main_macosx.mm
Revision: 1.8
Committed: 2003-04-02T00:50:40Z (21 years, 7 months ago) by nigel
Branch: MAIN
Changes since 1.7: +56 -8 lines
Log Message:
Arg processing for prefs file path, include some extra stuff
(SEGV and JIT) from latest unix version of file

File Contents

# User Rev Content
1 nigel 1.1 /*
2 nigel 1.8 * $Id: main_macosx.mm,v 1.7 2003/03/26 00:26:38 nigel Exp $
3 nigel 1.1 *
4     * main_macosx.mm - Startup code for MacOS X
5     * Based (in a small way) on the default main.m,
6     and on Basilisk's main_unix.cpp
7     *
8     * Basilisk II (C) 1997-2002 Christian Bauer
9     *
10     * This program is free software; you can redistribute it and/or modify
11     * it under the terms of the GNU General Public License as published by
12     * the Free Software Foundation; either version 2 of the License, or
13     * (at your option) any later version.
14     *
15     * This program is distributed in the hope that it will be useful,
16     * but WITHOUT ANY WARRANTY; without even the implied warranty of
17     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18     * GNU General Public License for more details.
19     *
20     * You should have received a copy of the GNU General Public License
21     * along with this program; if not, write to the Free Software
22     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23     */
24     #define PTHREADS
25     #include "sysdeps.h"
26    
27     #ifdef HAVE_PTHREADS
28     # include <pthread.h>
29     #endif
30    
31     #if REAL_ADDRESSING || DIRECT_ADDRESSING
32     # include <sys/mman.h>
33     #endif
34    
35 nigel 1.8 #include <string>
36     using std::string;
37    
38 nigel 1.1 #include "cpu_emulation.h"
39     #include "macos_util_macosx.h"
40     #include "main.h"
41     #include "prefs.h"
42     #include "prefs_editor.h"
43     #include "rom_patches.h"
44 nigel 1.8 #include "sigsegv.h"
45 nigel 1.1 #include "sys.h"
46     #include "user_strings.h"
47     #include "version.h"
48     #include "video.h"
49     #include "vm_alloc.h"
50     #include "xpram.h"
51    
52 nigel 1.8 #if USE_JIT
53     extern void (*flush_icache)(int); // from compemu_support.cpp
54     #endif
55    
56 nigel 1.1 #ifdef ENABLE_MON
57     # include "mon.h"
58     #endif
59    
60     #define DEBUG 0
61     #include "debug.h"
62    
63    
64     #import <AppKit/AppKit.h>
65    
66     #include "main_macosx.h" // To bridge between main() and misc. classes
67    
68    
69     // Constants
70     const char ROM_FILE_NAME[] = "ROM";
71     const int SCRATCH_MEM_SIZE = 0x10000; // Size of scratch memory area
72    
73    
74     // CPU and FPU type, addressing mode
75     int CPUType;
76     bool CPUIs68060;
77     int FPUType;
78     bool TwentyFourBitAddressing;
79    
80    
81     // Global variables
82    
83     #ifdef HAVE_PTHREADS
84    
85     static pthread_mutex_t intflag_lock = PTHREAD_MUTEX_INITIALIZER; // Mutex to protect InterruptFlags
86     #define LOCK_INTFLAGS pthread_mutex_lock(&intflag_lock)
87     #define UNLOCK_INTFLAGS pthread_mutex_unlock(&intflag_lock)
88    
89     #else
90    
91     #define LOCK_INTFLAGS
92     #define UNLOCK_INTFLAGS
93    
94     #endif
95    
96     #if USE_SCRATCHMEM_SUBTERFUGE
97     uint8 *ScratchMem = NULL; // Scratch memory for Mac ROM writes
98     #endif
99    
100 nigel 1.3 #ifdef ENABLE_MON
101 nigel 1.1 static struct sigaction sigint_sa; // sigaction for SIGINT handler
102     static void sigint_handler(...);
103 nigel 1.3 #endif
104 nigel 1.1
105     #if REAL_ADDRESSING
106     static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped
107     #endif
108    
109    
110 nigel 1.8 /*
111     * Dump state when everything went wrong after a SEGV
112     */
113    
114     static void sigsegv_dump_state(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
115     {
116     fprintf(stderr, "Caught SIGSEGV at address %p", fault_address);
117     if (fault_instruction != SIGSEGV_INVALID_PC)
118     fprintf(stderr, " [IP=%p]", fault_instruction);
119     fprintf(stderr, "\n");
120     uaecptr nextpc;
121     extern void m68k_dumpstate(uaecptr *nextpc);
122     m68k_dumpstate(&nextpc);
123     #if USE_JIT && JIT_DEBUG
124     extern void compiler_dumpstate(void);
125     compiler_dumpstate();
126     #endif
127     VideoQuitFullScreen();
128     #ifdef ENABLE_MON
129     char *arg[4] = {"mon", "-m", "-r", NULL};
130     mon(3, arg);
131     QuitEmulator();
132     #endif
133     }
134    
135 nigel 1.1
136     /*
137     * Main program
138     */
139    
140     static void usage(const char *prg_name)
141     {
142     printf("Usage: %s [OPTION...]\n", prg_name);
143     printf("\nUnix options:\n");
144     printf(" --help\n display this usage message\n");
145 nigel 1.8 printf(" --config FILE\n read/write configuration from/to FILE\n");
146 nigel 1.1 printf(" --break ADDRESS\n set ROM breakpoint\n");
147     printf(" --rominfo\n dump ROM information\n");
148 nigel 1.8 LoadPrefs(); // read the prefs file so PrefsPrintUsage() will print the correct default values
149 nigel 1.1 PrefsPrintUsage();
150     exit(0);
151     }
152    
153     int main(int argc, char **argv)
154     {
155     // Initialize variables
156     RAMBaseHost = NULL;
157     ROMBaseHost = NULL;
158     srand(time(NULL));
159     tzset();
160    
161     // Print some info
162     printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
163     printf(" %s\n", GetString(STR_ABOUT_TEXT2));
164    
165     // Read preferences
166     PrefsInit(argc, argv);
167    
168     // Parse command line arguments
169     for (int i=1; i<argc; i++) {
170     if (strcmp(argv[i], "--help") == 0) {
171     usage(argv[0]);
172     } else if (strncmp(argv[i], "-psn_", 5) == 0) {// OS X process identifier
173     i++;
174     } else if (strcmp(argv[i], "--break") == 0) {
175     i++;
176     if (i < argc)
177     ROMBreakpoint = strtol(argv[i], NULL, 0);
178 nigel 1.8 } else if (strcmp(argv[i], "--config") == 0) {
179     argv[i++] = NULL;
180     if (i < argc) {
181     extern string UserPrefsPath; // from prefs_unix.cpp
182     UserPrefsPath = argv[i];
183     argv[i] = NULL;
184     }
185 nigel 1.1 } else if (strcmp(argv[i], "--rominfo") == 0) {
186     PrintROMInfo = true;
187     } else if (argv[i][0] == '-') {
188     fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
189     usage(argv[0]);
190     }
191     }
192    
193     // Init system routines
194     SysInit();
195    
196     // Open display, attach to window server,
197     // load pre-instantiated classes from MainMenu.nib, start run loop
198     int i = NSApplicationMain(argc, (const char **)argv);
199     // We currently never get past here, because QuitEmulator() does an exit()
200    
201     // Exit system routines
202     SysExit();
203    
204     // Exit preferences
205     PrefsExit();
206    
207     return i;
208     }
209    
210 nigel 1.7 #define QuitEmulator() { QuitEmuNoExit() ; return NO; }
211 nigel 1.1
212     bool InitEmulator (void)
213     {
214     char str[256];
215    
216    
217 nigel 1.8 // Register request to ignore segmentation faults
218     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
219     if (PrefsFindBool("ignoresegv"))
220     sigsegv_set_ignore_state(true);
221     #endif
222    
223     // Register dump state function when we got mad after a segfault
224     sigsegv_set_dump_state(sigsegv_dump_state);
225    
226 nigel 1.1 // Read RAM size
227     RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary
228     if (RAMSize < 1024*1024) {
229     WarningAlert(GetString(STR_SMALL_RAM_WARN));
230     RAMSize = 1024*1024;
231     }
232    
233     #if REAL_ADDRESSING || DIRECT_ADDRESSING
234     RAMSize = RAMSize & -getpagesize(); // Round down to page boundary
235     #endif
236    
237     // Initialize VM system
238     vm_init();
239    
240     #if REAL_ADDRESSING
241     // Flag: RAM and ROM are contigously allocated from address 0
242     bool memory_mapped_from_zero = false;
243    
244     // Under Solaris/SPARC and NetBSD/m68k, Basilisk II is known to crash
245     // when trying to map a too big chunk of memory starting at address 0
246     #if defined(OS_solaris) || defined(OS_netbsd)
247     const bool can_map_all_memory = false;
248     #else
249     const bool can_map_all_memory = true;
250     #endif
251    
252     // Try to allocate all memory from 0x0000, if it is not known to crash
253     if (can_map_all_memory && (vm_acquire_fixed(0, RAMSize + 0x100000) == 0)) {
254     D(bug("Could allocate RAM and ROM from 0x0000\n"));
255     memory_mapped_from_zero = true;
256     }
257    
258     // Otherwise, just create the Low Memory area (0x0000..0x2000)
259     else if (vm_acquire_fixed(0, 0x2000) == 0) {
260     D(bug("Could allocate the Low Memory globals\n"));
261     lm_area_mapped = true;
262     }
263    
264     // Exit on failure
265     else {
266     sprintf(str, GetString(STR_LOW_MEM_MMAP_ERR), strerror(errno));
267     ErrorAlert(str);
268     QuitEmulator();
269     }
270 nigel 1.4 #else
271     *str = 0; // Eliminate unused variable warning
272 nigel 1.1 #endif
273    
274     // Create areas for Mac RAM and ROM
275     #if REAL_ADDRESSING
276     if (memory_mapped_from_zero) {
277     RAMBaseHost = (uint8 *)0;
278     ROMBaseHost = RAMBaseHost + RAMSize;
279     }
280     else
281     #endif
282     {
283     RAMBaseHost = (uint8 *)vm_acquire(RAMSize);
284     ROMBaseHost = (uint8 *)vm_acquire(0x100000);
285     if (RAMBaseHost == VM_MAP_FAILED || ROMBaseHost == VM_MAP_FAILED) {
286     ErrorAlert(STR_NO_MEM_ERR);
287     QuitEmulator();
288     }
289     }
290    
291     #if USE_SCRATCHMEM_SUBTERFUGE
292     // Allocate scratch memory
293     ScratchMem = (uint8 *)vm_acquire(SCRATCH_MEM_SIZE);
294     if (ScratchMem == VM_MAP_FAILED) {
295     ErrorAlert(STR_NO_MEM_ERR);
296     QuitEmulator();
297     }
298     ScratchMem += SCRATCH_MEM_SIZE/2; // ScratchMem points to middle of block
299     #endif
300    
301     #if DIRECT_ADDRESSING
302     // RAMBaseMac shall always be zero
303     MEMBaseDiff = (uintptr)RAMBaseHost;
304     RAMBaseMac = 0;
305     ROMBaseMac = Host2MacAddr(ROMBaseHost);
306     #endif
307     #if REAL_ADDRESSING
308     RAMBaseMac = (uint32)RAMBaseHost;
309     ROMBaseMac = (uint32)ROMBaseHost;
310     #endif
311     D(bug("Mac RAM starts at %p (%08x)\n", RAMBaseHost, RAMBaseMac));
312     D(bug("Mac ROM starts at %p (%08x)\n", ROMBaseHost, ROMBaseMac));
313    
314     // Get rom file path from preferences
315     const char *rom_path = PrefsFindString("rom");
316 nigel 1.6 if ( ! rom_path )
317     WarningAlert("No rom pathname set. Trying ./ROM");
318 nigel 1.1
319     // Load Mac ROM
320     int rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME, O_RDONLY);
321     if (rom_fd < 0) {
322     ErrorAlert(STR_NO_ROM_FILE_ERR);
323     QuitEmulator();
324     }
325     printf(GetString(STR_READING_ROM_FILE));
326     ROMSize = lseek(rom_fd, 0, SEEK_END);
327     if (ROMSize != 64*1024 && ROMSize != 128*1024 && ROMSize != 256*1024 && ROMSize != 512*1024 && ROMSize != 1024*1024) {
328     ErrorAlert(STR_ROM_SIZE_ERR);
329     close(rom_fd);
330     QuitEmulator();
331     }
332     lseek(rom_fd, 0, SEEK_SET);
333     if (read(rom_fd, ROMBaseHost, ROMSize) != (ssize_t)ROMSize) {
334     ErrorAlert(STR_ROM_FILE_READ_ERR);
335     close(rom_fd);
336     QuitEmulator();
337     }
338    
339    
340     // Initialize everything
341     if (!InitAll())
342     QuitEmulator();
343     D(bug("Initialization complete\n"));
344    
345    
346     #ifdef ENABLE_MON
347     // Setup SIGINT handler to enter mon
348     sigemptyset(&sigint_sa.sa_mask);
349     sigint_sa.sa_handler = (void (*)(int))sigint_handler;
350     sigint_sa.sa_flags = 0;
351     sigaction(SIGINT, &sigint_sa, NULL);
352     #endif
353    
354    
355     return YES;
356     }
357    
358     #undef QuitEmulator()
359    
360    
361     /*
362     * Quit emulator
363     */
364    
365     void QuitEmuNoExit()
366     {
367     D(bug("QuitEmulator\n"));
368    
369     // Exit 680x0 emulation
370     Exit680x0();
371    
372     // Deinitialize everything
373     ExitAll();
374    
375     // Free ROM/RAM areas
376     if (RAMBaseHost != VM_MAP_FAILED) {
377     vm_release(RAMBaseHost, RAMSize);
378     RAMBaseHost = NULL;
379     }
380     if (ROMBaseHost != VM_MAP_FAILED) {
381     vm_release(ROMBaseHost, 0x100000);
382     ROMBaseHost = NULL;
383     }
384    
385     #if USE_SCRATCHMEM_SUBTERFUGE
386     // Delete scratch memory area
387     if (ScratchMem != (uint8 *)VM_MAP_FAILED) {
388     vm_release((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE);
389     ScratchMem = NULL;
390     }
391     #endif
392    
393     #if REAL_ADDRESSING
394     // Delete Low Memory area
395     if (lm_area_mapped)
396     vm_release(0, 0x2000);
397     #endif
398    
399     // Exit VM wrappers
400     vm_exit();
401    
402     // Exit system routines
403     SysExit();
404    
405     // Exit preferences
406     PrefsExit();
407     }
408    
409     void QuitEmulator(void)
410     {
411 nigel 1.6 extern NSApplication *NSApp;
412    
413    
414 nigel 1.1 QuitEmuNoExit();
415 nigel 1.6
416     // Stop run loop?
417     [NSApp terminate: nil];
418    
419 nigel 1.1 exit(0);
420     }
421    
422    
423     /*
424     * Code was patched, flush caches if neccessary (i.e. when using a real 680x0
425     * or a dynamically recompiling emulator)
426     */
427    
428     void FlushCodeCache(void *start, uint32 size)
429     {
430 nigel 1.8 #if USE_JIT
431     if (UseJIT)
432     flush_icache(-1);
433     #endif
434 nigel 1.1 }
435    
436    
437     /*
438     * SIGINT handler, enters mon
439     */
440    
441     #ifdef ENABLE_MON
442     static void sigint_handler(...)
443     {
444     uaecptr nextpc;
445     extern void m68k_dumpstate(uaecptr *nextpc);
446     m68k_dumpstate(&nextpc);
447     VideoQuitFullScreen();
448     char *arg[4] = {"mon", "-m", "-r", NULL};
449     mon(3, arg);
450     QuitEmulator();
451     }
452     #endif
453    
454    
455     /*
456     * Mutexes
457     */
458    
459     #ifdef HAVE_PTHREADS
460    
461     struct B2_mutex {
462     B2_mutex() { pthread_mutex_init(&m, NULL); }
463     ~B2_mutex() { pthread_mutex_unlock(&m); pthread_mutex_destroy(&m); }
464     pthread_mutex_t m;
465     };
466    
467     B2_mutex *B2_create_mutex(void)
468     {
469     return new B2_mutex;
470     }
471    
472     void B2_lock_mutex(B2_mutex *mutex)
473     {
474     pthread_mutex_lock(&mutex->m);
475     }
476    
477     void B2_unlock_mutex(B2_mutex *mutex)
478     {
479     pthread_mutex_unlock(&mutex->m);
480     }
481    
482     void B2_delete_mutex(B2_mutex *mutex)
483     {
484     delete mutex;
485     }
486    
487     #else
488    
489     struct B2_mutex {
490     int dummy;
491     };
492    
493     B2_mutex *B2_create_mutex(void)
494     {
495     return new B2_mutex;
496     }
497    
498     void B2_lock_mutex(B2_mutex *mutex)
499     {
500     }
501    
502     void B2_unlock_mutex(B2_mutex *mutex)
503     {
504     }
505    
506     void B2_delete_mutex(B2_mutex *mutex)
507     {
508     delete mutex;
509     }
510    
511     #endif
512    
513    
514     /*
515     * Interrupt flags (must be handled atomically!)
516     */
517    
518     uint32 InterruptFlags = 0;
519    
520     void SetInterruptFlag(uint32 flag)
521     {
522     LOCK_INTFLAGS;
523     InterruptFlags |= flag;
524     UNLOCK_INTFLAGS;
525     }
526    
527     void ClearInterruptFlag(uint32 flag)
528     {
529     LOCK_INTFLAGS;
530     InterruptFlags &= ~flag;
531     UNLOCK_INTFLAGS;
532     }
533    
534    
535     /*
536     * Display error alert
537     */
538    
539     void ErrorAlert(const char *text)
540     {
541     NSString *title = [NSString stringWithCString:
542     GetString(STR_ERROR_ALERT_TITLE) ];
543     NSString *error = [NSString stringWithCString: text];
544     NSString *button = [NSString stringWithCString: GetString(STR_QUIT_BUTTON) ];
545    
546     // If we have a full screen mode, quit it here?
547    
548     NSLog(error);
549     NSRunCriticalAlertPanel(title, error, button, nil, nil);
550     }
551    
552    
553     /*
554     * Display warning alert
555     */
556    
557     void WarningAlert(const char *text)
558     {
559     NSString *title = [NSString stringWithCString:
560     GetString(STR_WARNING_ALERT_TITLE) ];
561     NSString *warning = [NSString stringWithCString: text];
562     NSString *button = [NSString stringWithCString: GetString(STR_OK_BUTTON) ];
563    
564     NSLog(warning);
565     NSRunAlertPanel(title, warning, button, nil, nil);
566     }
567    
568    
569     /*
570     * Display choice alert
571     */
572    
573     bool ChoiceAlert(const char *text, const char *pos, const char *neg)
574     {
575     NSString *title = [NSString stringWithCString:
576     GetString(STR_WARNING_ALERT_TITLE) ];
577     NSString *warning = [NSString stringWithCString: text];
578     NSString *yes = [NSString stringWithCString: pos];
579     NSString *no = [NSString stringWithCString: neg];
580    
581     NSLog(warning);
582     return NSRunInformationalAlertPanel(title, warning, yes, no, nil);
583     }