ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/main_macosx.mm
(Generate patch)

Comparing BasiliskII/src/MacOSX/main_macosx.mm (file contents):
Revision 1.8 by nigel, 2003-04-02T00:50:40Z vs.
Revision 1.23 by asvitkine, 2011-03-11T16:43:09Z

# Line 5 | Line 5
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
8 > *  Basilisk II (C) 1997-2008 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
# Line 21 | Line 21
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
24 >
25 > #import <AppKit/AppKit.h>
26 > #undef check
27 >
28 > #define PTHREADS        // Why is this here?
29   #include "sysdeps.h"
30  
31   #ifdef HAVE_PTHREADS
# Line 36 | Line 40
40   using std::string;
41  
42   #include "cpu_emulation.h"
43 < #include "macos_util_macosx.h"
44 < #include "main.h"
43 > #include "sys.h"
44 > #include "rom_patches.h"
45 > #include "xpram.h"
46 > #include "video.h"
47   #include "prefs.h"
48   #include "prefs_editor.h"
49 < #include "rom_patches.h"
44 < #include "sigsegv.h"
45 < #include "sys.h"
49 > #include "macos_util_macosx.h"
50   #include "user_strings.h"
51   #include "version.h"
52 < #include "video.h"
52 > #include "main.h"
53   #include "vm_alloc.h"
54 < #include "xpram.h"
54 > #include "sigsegv.h"
55  
56   #if USE_JIT
57 < extern void (*flush_icache)(int); // from compemu_support.cpp
57 > extern void flush_icache_range(uint8 *start, uint32 size); // from compemu_support.cpp
58   #endif
59  
60   #ifdef ENABLE_MON
# Line 61 | Line 65 | extern void (*flush_icache)(int); // fro
65   #include "debug.h"
66  
67  
64 #import <AppKit/AppKit.h>
65
68   #include "main_macosx.h"                // To bridge between main() and misc. classes
69  
70  
# Line 71 | Line 73 | const char ROM_FILE_NAME[] = "ROM";
73   const int SCRATCH_MEM_SIZE = 0x10000;   // Size of scratch memory area
74  
75  
76 + static char *bundle = NULL;             // If in an OS X application bundle, its path
77 +
78 +
79   // CPU and FPU type, addressing mode
80   int CPUType;
81   bool CPUIs68060;
# Line 108 | Line 113 | static bool lm_area_mapped = false;    // F
113  
114  
115   /*
116 + *  Helpers to map memory that can be accessed from the Mac side
117 + */
118 +
119 + // NOTE: VM_MAP_32BIT is only used when compiling a 64-bit JIT on specific platforms
120 + void *vm_acquire_mac(size_t size)
121 + {
122 +        return vm_acquire(size, VM_MAP_DEFAULT | VM_MAP_32BIT);
123 + }
124 +
125 + static int vm_acquire_mac_fixed(void *addr, size_t size)
126 + {
127 +        return vm_acquire_fixed(addr, size, VM_MAP_DEFAULT | VM_MAP_32BIT);
128 + }
129 +
130 +
131 + /*
132 + *  SIGSEGV handler
133 + */
134 +
135 + static sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip)
136 + {
137 +        const uintptr fault_address = (uintptr)sigsegv_get_fault_address(sip);
138 + #if ENABLE_VOSF
139 +        // Handle screen fault
140 +        extern bool Screen_fault_handler(sigsegv_info_t *sip);
141 +        if (Screen_fault_handler(sip))
142 +                return SIGSEGV_RETURN_SUCCESS;
143 + #endif
144 +
145 + #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
146 +        // Ignore writes to ROM
147 +        if (((uintptr)fault_address - (uintptr)ROMBaseHost) < ROMSize)
148 +                return SIGSEGV_RETURN_SKIP_INSTRUCTION;
149 +
150 +        // Ignore all other faults, if requested
151 +        if (PrefsFindBool("ignoresegv"))
152 +                return SIGSEGV_RETURN_SKIP_INSTRUCTION;
153 + #endif
154 +
155 +        return SIGSEGV_RETURN_FAILURE;
156 + }
157 +
158 + /*
159   *  Dump state when everything went wrong after a SEGV
160   */
161  
162 < static void sigsegv_dump_state(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
162 > static void sigsegv_dump_state(sigsegv_info_t *sip)
163   {
164 +        const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
165 +        const sigsegv_address_t fault_instruction = sigsegv_get_fault_instruction_address(sip);
166          fprintf(stderr, "Caught SIGSEGV at address %p", fault_address);
167 <        if (fault_instruction != SIGSEGV_INVALID_PC)
167 >        if (fault_instruction != SIGSEGV_INVALID_ADDRESS)
168                  fprintf(stderr, " [IP=%p]", fault_instruction);
169          fprintf(stderr, "\n");
170          uaecptr nextpc;
# Line 128 | Line 178 | static void sigsegv_dump_state(sigsegv_a
178   #ifdef ENABLE_MON
179          char *arg[4] = {"mon", "-m", "-r", NULL};
180          mon(3, arg);
131        QuitEmulator();
181   #endif
182 +        QuitEmulator();
183 + }
184 +
185 +
186 + /*
187 + * Screen fault handler
188 + */
189 +
190 + bool Screen_fault_handler(sigsegv_info_t *sip)
191 + {
192 +        return true;
193   }
194  
195  
# Line 139 | Line 199 | static void sigsegv_dump_state(sigsegv_a
199  
200   static void usage(const char *prg_name)
201   {
202 <        printf("Usage: %s [OPTION...]\n", prg_name);
203 <        printf("\nUnix options:\n");
204 <        printf("  --help\n    display this usage message\n");
205 <        printf("  --config FILE\n    read/write configuration from/to FILE\n");
206 <        printf("  --break ADDRESS\n    set ROM breakpoint\n");
207 <        printf("  --rominfo\n    dump ROM information\n");
208 <        LoadPrefs(); // read the prefs file so PrefsPrintUsage() will print the correct default values
202 >        printf(
203 >                "Usage: %s [OPTION...]\n"
204 >                "\nUnix options:\n"
205 >                "  --config FILE\n    read/write configuration from/to FILE\n"
206 >                "  --break ADDRESS\n    set ROM breakpoint\n"
207 >                "  --rominfo\n    dump ROM information\n", prg_name
208 >        );
209 >        LoadPrefs(NULL); // read the prefs file so PrefsPrintUsage() will print the correct default values
210          PrefsPrintUsage();
211          exit(0);
212   }
213  
214   int main(int argc, char **argv)
215   {
216 +        const char *vmdir = NULL;
217 +        char str[256];
218 +
219          // Initialize variables
220          RAMBaseHost = NULL;
221          ROMBaseHost = NULL;
# Line 162 | Line 226 | int main(int argc, char **argv)
226          printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
227          printf(" %s\n", GetString(STR_ABOUT_TEXT2));
228  
165        // Read preferences
166        PrefsInit(argc, argv);
167
229          // Parse command line arguments
230          for (int i=1; i<argc; i++) {
231                  if (strcmp(argv[i], "--help") == 0) {
232                          usage(argv[0]);
233                  } else if (strncmp(argv[i], "-psn_", 5) == 0) {// OS X process identifier
234 <                        i++;
234 >                        argv[i++] = NULL;
235                  } else if (strcmp(argv[i], "--break") == 0) {
236 <                        i++;
237 <                        if (i < argc)
236 >                        argv[i++] = NULL;
237 >                        if (i < argc) {
238                                  ROMBreakpoint = strtol(argv[i], NULL, 0);
239 +                                argv[i] = NULL;
240 +                        }
241                  } else if (strcmp(argv[i], "--config") == 0) {
242                          argv[i++] = NULL;
243                          if (i < argc) {
# Line 183 | Line 246 | int main(int argc, char **argv)
246                                  argv[i] = NULL;
247                          }
248                  } else if (strcmp(argv[i], "--rominfo") == 0) {
249 +                        argv[i] = NULL;
250                          PrintROMInfo = true;
251 <                } else if (argv[i][0] == '-') {
251 >                }
252 >        }
253 >
254 >        // Remove processed arguments
255 >        for (int i=1; i<argc; i++) {
256 >                int k;
257 >                for (k=i; k<argc; k++)
258 >                        if (argv[k] != NULL)
259 >                                break;
260 >                if (k > i) {
261 >                        k -= i;
262 >                        for (int j=i+k; j<argc; j++)
263 >                                argv[j-k] = argv[j];
264 >                        argc -= k;
265 >                }
266 >        }
267 >
268 >        // Read preferences
269 >        PrefsInit(vmdir, argc, argv);
270 >
271 >        // Any command line arguments left?
272 >        for (int i=1; i<argc; i++) {
273 >                if (argv[i][0] == '-') {
274                          fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
275                          usage(argv[0]);
276                  }
# Line 193 | Line 279 | int main(int argc, char **argv)
279          // Init system routines
280          SysInit();
281  
282 +        // Set the current directory somewhere useful.
283 +        // Handy for storing the ROM file
284 +        bundle = strstr(argv[0], "BasiliskII.app/Contents/MacOS/BasiliskII");
285 +        if (bundle)
286 +        {
287 +                while (*bundle != '/')
288 +                        ++bundle;
289 +
290 +                *bundle = 0;  // Throw away Contents/... on end of argv[0]
291 +                bundle = argv[0];
292 +
293 +                chdir(bundle);
294 +        }
295 +
296          // Open display, attach to window server,
297          // load pre-instantiated classes from MainMenu.nib, start run loop
298          int i = NSApplicationMain(argc, (const char **)argv);
# Line 211 | Line 311 | int main(int argc, char **argv)
311  
312   bool InitEmulator (void)
313   {
314 +        const char *vmdir = NULL;
315          char str[256];
316  
317  
318 <        // Register request to ignore segmentation faults
319 < #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
320 <        if (PrefsFindBool("ignoresegv"))
321 <                sigsegv_set_ignore_state(true);
322 < #endif
318 >        // Install the handler for SIGSEGV
319 >        if (!sigsegv_install_handler(sigsegv_handler)) {
320 >                sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGSEGV", strerror(errno));
321 >                ErrorAlert(str);
322 >                QuitEmulator();
323 >        }
324  
325          // Register dump state function when we got mad after a segfault
326          sigsegv_set_dump_state(sigsegv_dump_state);
# Line 229 | Line 331 | bool InitEmulator (void)
331                  WarningAlert(GetString(STR_SMALL_RAM_WARN));
332                  RAMSize = 1024*1024;
333          }
334 +        if (RAMSize > 1023*1024*1024)                                           // Cap to 1023MB (APD crashes at 1GB)
335 +                RAMSize = 1023*1024*1024;
336  
337   #if REAL_ADDRESSING || DIRECT_ADDRESSING
338          RAMSize = RAMSize & -getpagesize();                                     // Round down to page boundary
# Line 240 | Line 344 | bool InitEmulator (void)
344   #if REAL_ADDRESSING
345          // Flag: RAM and ROM are contigously allocated from address 0
346          bool memory_mapped_from_zero = false;
347 <        
348 <        // Under Solaris/SPARC and NetBSD/m68k, Basilisk II is known to crash
349 <        // when trying to map a too big chunk of memory starting at address 0
350 < #if defined(OS_solaris) || defined(OS_netbsd)
351 <        const bool can_map_all_memory = false;
248 < #else
347 >
348 >        // Make sure to map RAM & ROM at address 0 only on platforms that
349 >        // supports linker scripts to relocate the Basilisk II executable
350 >        // above 0x70000000
351 > #if HAVE_LINKER_SCRIPT
352          const bool can_map_all_memory = true;
353 + #else
354 +        const bool can_map_all_memory = false;
355   #endif
356          
357          // Try to allocate all memory from 0x0000, if it is not known to crash
358 <        if (can_map_all_memory && (vm_acquire_fixed(0, RAMSize + 0x100000) == 0)) {
358 >        if (can_map_all_memory && (vm_acquire_mac_fixed(0, RAMSize + 0x100000) == 0)) {
359                  D(bug("Could allocate RAM and ROM from 0x0000\n"));
360                  memory_mapped_from_zero = true;
361          }
362          
363 + #ifndef PAGEZERO_HACK
364          // Otherwise, just create the Low Memory area (0x0000..0x2000)
365 <        else if (vm_acquire_fixed(0, 0x2000) == 0) {
365 >        else if (vm_acquire_mac_fixed(0, 0x2000) == 0) {
366                  D(bug("Could allocate the Low Memory globals\n"));
367                  lm_area_mapped = true;
368          }
# Line 267 | Line 373 | bool InitEmulator (void)
373                  ErrorAlert(str);
374                  QuitEmulator();
375          }
376 + #endif
377   #else
378          *str = 0;               // Eliminate unused variable warning
379 < #endif
379 > #endif /* REAL_ADDRESSING */
380  
381          // Create areas for Mac RAM and ROM
382   #if REAL_ADDRESSING
# Line 280 | Line 387 | bool InitEmulator (void)
387          else
388   #endif
389          {
390 <                RAMBaseHost = (uint8 *)vm_acquire(RAMSize);
391 <                ROMBaseHost = (uint8 *)vm_acquire(0x100000);
285 <                if (RAMBaseHost == VM_MAP_FAILED || ROMBaseHost == VM_MAP_FAILED) {
390 >                uint8 *ram_rom_area = (uint8 *)vm_acquire_mac(RAMSize + 0x100000);
391 >                if (ram_rom_area == VM_MAP_FAILED) {
392                          ErrorAlert(STR_NO_MEM_ERR);
393                          QuitEmulator();
394                  }
395 +                RAMBaseHost = ram_rom_area;
396 +                ROMBaseHost = RAMBaseHost + RAMSize;
397          }
398  
399   #if USE_SCRATCHMEM_SUBTERFUGE
400          // Allocate scratch memory
401 <        ScratchMem = (uint8 *)vm_acquire(SCRATCH_MEM_SIZE);
401 >        ScratchMem = (uint8 *)vm_acquire_mac(SCRATCH_MEM_SIZE);
402          if (ScratchMem == VM_MAP_FAILED) {
403                  ErrorAlert(STR_NO_MEM_ERR);
404                  QuitEmulator();
# Line 305 | Line 413 | bool InitEmulator (void)
413          ROMBaseMac = Host2MacAddr(ROMBaseHost);
414   #endif
415   #if REAL_ADDRESSING
416 <        RAMBaseMac = (uint32)RAMBaseHost;
417 <        ROMBaseMac = (uint32)ROMBaseHost;
416 >        RAMBaseMac = Host2MacAddr(RAMBaseHost);
417 >        ROMBaseMac = Host2MacAddr(ROMBaseHost);
418   #endif
419          D(bug("Mac RAM starts at %p (%08x)\n", RAMBaseHost, RAMBaseMac));
420          D(bug("Mac ROM starts at %p (%08x)\n", ROMBaseHost, ROMBaseMac));
# Line 314 | Line 422 | bool InitEmulator (void)
422          // Get rom file path from preferences
423          const char *rom_path = PrefsFindString("rom");
424          if ( ! rom_path )
425 +          if ( bundle )
426 +                WarningAlert("No rom pathname set. Trying BasiliskII.app/ROM");
427 +          else
428                  WarningAlert("No rom pathname set. Trying ./ROM");
429  
430          // Load Mac ROM
# Line 338 | Line 449 | bool InitEmulator (void)
449  
450  
451          // Initialize everything
452 <        if (!InitAll())
452 >        if (!InitAll(vmdir))
453                  QuitEmulator();
454          D(bug("Initialization complete\n"));
455  
# Line 374 | Line 485 | void QuitEmuNoExit()
485  
486          // Free ROM/RAM areas
487          if (RAMBaseHost != VM_MAP_FAILED) {
488 <                vm_release(RAMBaseHost, RAMSize);
488 >                vm_release(RAMBaseHost, RAMSize + 0x100000);
489                  RAMBaseHost = NULL;
379        }
380        if (ROMBaseHost != VM_MAP_FAILED) {
381                vm_release(ROMBaseHost, 0x100000);
490                  ROMBaseHost = NULL;
491          }
492  
# Line 408 | Line 516 | void QuitEmuNoExit()
516  
517   void QuitEmulator(void)
518   {
411        extern  NSApplication *NSApp;
412
413
519          QuitEmuNoExit();
520  
521          // Stop run loop?
# Line 428 | Line 533 | void QuitEmulator(void)
533   void FlushCodeCache(void *start, uint32 size)
534   {
535   #if USE_JIT
536 <    if (UseJIT)
537 <                flush_icache(-1);
536 >        if (UseJIT)
537 >                flush_icache_range((uint8 *)start, size);
538   #endif
539   }
540  
# Line 452 | Line 557 | static void sigint_handler(...)
557   #endif
558  
559  
560 + #ifdef HAVE_PTHREADS
561 + /*
562 + *  Pthread configuration
563 + */
564 +
565 + void Set_pthread_attr(pthread_attr_t *attr, int priority)
566 + {
567 +        pthread_attr_init(attr);
568 + #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
569 +        // Some of these only work for superuser
570 +        if (geteuid() == 0) {
571 +                pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
572 +                pthread_attr_setschedpolicy(attr, SCHED_FIFO);
573 +                struct sched_param fifo_param;
574 +                fifo_param.sched_priority = ((sched_get_priority_min(SCHED_FIFO)
575 +                                                                         + sched_get_priority_max(SCHED_FIFO))
576 +                                                                         / 2 + priority);
577 +                pthread_attr_setschedparam(attr, &fifo_param);
578 +        }
579 +        if (pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM) != 0) {
580 + #ifdef PTHREAD_SCOPE_BOUND_NP
581 +            // If system scope is not available (eg. we're not running
582 +            // with CAP_SCHED_MGT capability on an SGI box), try bound
583 +            // scope.  It exposes pthread scheduling to the kernel,
584 +            // without setting realtime priority.
585 +            pthread_attr_setscope(attr, PTHREAD_SCOPE_BOUND_NP);
586 + #endif
587 +        }
588 + #endif
589 + }
590 + #endif // HAVE_PTHREADS
591 +
592 +
593   /*
594   *  Mutexes
595   */
# Line 459 | Line 597 | static void sigint_handler(...)
597   #ifdef HAVE_PTHREADS
598  
599   struct B2_mutex {
600 <        B2_mutex() { pthread_mutex_init(&m, NULL); }
601 <        ~B2_mutex() { pthread_mutex_unlock(&m); pthread_mutex_destroy(&m); }
600 >        B2_mutex() {
601 >                pthread_mutexattr_t attr;
602 >                pthread_mutexattr_init(&attr);
603 >                // Initialize the mutex for priority inheritance --
604 >                // required for accurate timing.
605 > #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
606 >                pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
607 > #endif
608 > #if defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE) && defined(PTHREAD_MUTEX_NORMAL)
609 >                pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
610 > #endif
611 > #ifdef HAVE_PTHREAD_MUTEXATTR_SETPSHARED
612 >                pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
613 > #endif
614 >                pthread_mutex_init(&m, &attr);
615 >                pthread_mutexattr_destroy(&attr);
616 >        }
617 >        ~B2_mutex() {
618 >                pthread_mutex_trylock(&m);      // Make sure it's locked before
619 >                pthread_mutex_unlock(&m);       // unlocking it.
620 >                pthread_mutex_destroy(&m);
621 >        }
622          pthread_mutex_t m;
623   };
624  
# Line 543 | Line 701 | void ErrorAlert(const char *text)
701          NSString *error  = [NSString stringWithCString: text];
702          NSString *button = [NSString stringWithCString: GetString(STR_QUIT_BUTTON) ];
703  
546 //      If we have a full screen mode, quit it here?
547
704          NSLog(error);
705 +        if ( PrefsFindBool("nogui") )
706 +                return;
707 +        VideoQuitFullScreen();
708          NSRunCriticalAlertPanel(title, error, button, nil, nil);
709   }
710  
# Line 562 | Line 721 | void WarningAlert(const char *text)
721          NSString *button  = [NSString stringWithCString: GetString(STR_OK_BUTTON) ];
722  
723          NSLog(warning);
724 +        if ( PrefsFindBool("nogui") )
725 +                return;
726 +        VideoQuitFullScreen();
727          NSRunAlertPanel(title, warning, button, nil, nil);
728   }
729  
# Line 578 | Line 740 | bool ChoiceAlert(const char *text, const
740          NSString *yes     = [NSString stringWithCString: pos];
741          NSString *no      = [NSString stringWithCString: neg];
742  
581        NSLog(warning);
743          return NSRunInformationalAlertPanel(title, warning, yes, no, nil);
744   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines