ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/main_macosx.mm
Revision: 1.3
Committed: 2002-10-29T14:27:00Z (21 years, 7 months ago) by nigel
Branch: MAIN
Changes since 1.2: +3 -3 lines
Log Message:
Eliminate warning

File Contents

# Content
1 /*
2 * $Id: main_macosx.mm,v 1.2 2002/05/25 23:58:51 nigel Exp $
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 void ErrorAlert(const char *text)
487 {
488 NSString *title = [NSString stringWithCString:
489 GetString(STR_ERROR_ALERT_TITLE) ];
490 NSString *error = [NSString stringWithCString: text];
491 NSString *button = [NSString stringWithCString: GetString(STR_QUIT_BUTTON) ];
492
493 // If we have a full screen mode, quit it here?
494
495 NSLog(error);
496 NSRunCriticalAlertPanel(title, error, button, nil, nil);
497 }
498
499
500 /*
501 * Display warning alert
502 */
503
504 void WarningAlert(const char *text)
505 {
506 NSString *title = [NSString stringWithCString:
507 GetString(STR_WARNING_ALERT_TITLE) ];
508 NSString *warning = [NSString stringWithCString: text];
509 NSString *button = [NSString stringWithCString: GetString(STR_OK_BUTTON) ];
510
511 NSLog(warning);
512 NSRunAlertPanel(title, warning, button, nil, nil);
513 }
514
515
516 /*
517 * Display choice alert
518 */
519
520 bool ChoiceAlert(const char *text, const char *pos, const char *neg)
521 {
522 NSString *title = [NSString stringWithCString:
523 GetString(STR_WARNING_ALERT_TITLE) ];
524 NSString *warning = [NSString stringWithCString: text];
525 NSString *yes = [NSString stringWithCString: pos];
526 NSString *no = [NSString stringWithCString: neg];
527
528 NSLog(warning);
529 return NSRunInformationalAlertPanel(title, warning, yes, no, nil);
530 }