ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/main_macosx.mm
Revision: 1.1
Committed: 2002-03-16T04:00:24Z (22 years, 2 months ago) by nigel
Branch: MAIN
CVS Tags: nigel-build-10
Log Message:
Initial revision of Mac OS X port code. Uses Objective-C++. Needs Mac OS 10.1

File Contents

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