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.2 by nigel, 2002-05-25T23:58:51Z vs.
Revision 1.20 by nigel, 2008-02-04T01:00:53Z

# 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 32 | Line 36
36   # include <sys/mman.h>
37   #endif
38  
39 + #include <string>
40 + using std::string;
41 +
42   #include "cpu_emulation.h"
43   #include "macos_util_macosx.h"
44   #include "main.h"
45   #include "prefs.h"
46   #include "prefs_editor.h"
47   #include "rom_patches.h"
48 + #include "sigsegv.h"
49   #include "sys.h"
42 #include "timer.h"
50   #include "user_strings.h"
51   #include "version.h"
52   #include "video.h"
53   #include "vm_alloc.h"
54   #include "xpram.h"
55  
56 + #if USE_JIT
57 + extern void flush_icache_range(uint8 *start, uint32 size);  // from compemu_support.cpp
58 + #endif
59 +
60   #ifdef ENABLE_MON
61   # include "mon.h"
62   #endif
# Line 54 | Line 65
65   #include "debug.h"
66  
67  
57 #import <AppKit/AppKit.h>
58
68   #include "main_macosx.h"                // To bridge between main() and misc. classes
69  
70  
71   // Constants
72   const char ROM_FILE_NAME[] = "ROM";
64 const int SIG_STACK_SIZE = SIGSTKSZ;    // Size of signal stack
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 91 | Line 102 | static pthread_mutex_t intflag_lock = PT
102   uint8 *ScratchMem = NULL;                       // Scratch memory for Mac ROM writes
103   #endif
104  
105 < #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
105 > #ifdef ENABLE_MON
106   static struct sigaction sigint_sa;      // sigaction for SIGINT handler
107   static void sigint_handler(...);
108 < //#endif
108 > #endif
109  
110   #if REAL_ADDRESSING
111   static bool lm_area_mapped = false;     // Flag: Low Memory area mmap()ped
112   #endif
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 + /*
160 + *  Dump state when everything went wrong after a SEGV
161 + */
162 +
163 + static void sigsegv_dump_state(sigsegv_info_t *sip)
164 + {
165 +        const sigsegv_address_t fault_address = sigsegv_get_fault_address(sip);
166 +        const sigsegv_address_t fault_instruction = sigsegv_get_fault_instruction_address(sip);
167 +        fprintf(stderr, "Caught SIGSEGV at address %p", fault_address);
168 +        if (fault_instruction != SIGSEGV_INVALID_ADDRESS)
169 +                fprintf(stderr, " [IP=%p]", fault_instruction);
170 +        fprintf(stderr, "\n");
171 +        uaecptr nextpc;
172 +        extern void m68k_dumpstate(uaecptr *nextpc);
173 +        m68k_dumpstate(&nextpc);
174 + #if USE_JIT && JIT_DEBUG
175 +        extern void compiler_dumpstate(void);
176 +        compiler_dumpstate();
177 + #endif
178 +        VideoQuitFullScreen();
179 + #ifdef ENABLE_MON
180 +        char *arg[4] = {"mon", "-m", "-r", NULL};
181 +        mon(3, arg);
182 + #endif
183 +        QuitEmulator();
184 + }
185 +
186 +
187 + /*
188 + * Screen fault handler
189 + */
190 +
191 + bool Screen_fault_handler(sigsegv_info_t *sip)
192 + {
193 +        return true;
194 + }
195 +
196  
197   /*
198   *  Main program
# Line 116 | Line 203 | static void usage(const char *prg_name)
203          printf("Usage: %s [OPTION...]\n", prg_name);
204          printf("\nUnix options:\n");
205          printf("  --help\n    display this usage message\n");
206 +        printf("  --config FILE\n    read/write configuration from/to FILE\n");
207          printf("  --break ADDRESS\n    set ROM breakpoint\n");
208          printf("  --rominfo\n    dump ROM information\n");
209 +        LoadPrefs(); // read the prefs file so PrefsPrintUsage() will print the correct default values
210          PrefsPrintUsage();
211          exit(0);
212   }
# Line 134 | Line 223 | int main(int argc, char **argv)
223          printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
224          printf(" %s\n", GetString(STR_ABOUT_TEXT2));
225  
137        // Read preferences
138        PrefsInit(argc, argv);
139
226          // Parse command line arguments
227          for (int i=1; i<argc; i++) {
228                  if (strcmp(argv[i], "--help") == 0) {
# Line 147 | Line 233 | int main(int argc, char **argv)
233                          i++;
234                          if (i < argc)
235                                  ROMBreakpoint = strtol(argv[i], NULL, 0);
236 +                } else if (strcmp(argv[i], "--config") == 0) {
237 +                        argv[i++] = NULL;
238 +                        if (i < argc) {
239 +                                extern string UserPrefsPath; // from prefs_unix.cpp
240 +                                UserPrefsPath = argv[i];
241 +                                argv[i] = NULL;
242 +                        }
243                  } else if (strcmp(argv[i], "--rominfo") == 0) {
244                          PrintROMInfo = true;
245                  } else if (argv[i][0] == '-') {
# Line 155 | Line 248 | int main(int argc, char **argv)
248                  }
249          }
250  
251 +        // Read preferences
252 +        PrefsInit(argc, argv);
253 +
254          // Init system routines
255          SysInit();
256  
257 +        // Set the current directory somewhere useful.
258 +        // Handy for storing the ROM file
259 +        bundle = strstr(argv[0], "BasiliskII.app/Contents/MacOS/BasiliskII");
260 +        if (bundle)
261 +        {
262 +                while (*bundle != '/')
263 +                        ++bundle;
264 +
265 +                *bundle = 0;  // Throw away Contents/... on end of argv[0]
266 +                bundle = argv[0];
267 +
268 +                chdir(bundle);
269 +        }
270 +
271          // Open display, attach to window server,
272          // load pre-instantiated classes from MainMenu.nib, start run loop
273          int i = NSApplicationMain(argc, (const char **)argv);
# Line 172 | Line 282 | int main(int argc, char **argv)
282          return i;
283   }
284  
285 < #define QuitEmulator()  QuitEmuNoExit() ; return NO;
285 > #define QuitEmulator()  { QuitEmuNoExit() ; return NO; }
286  
287   bool InitEmulator (void)
288   {
289          char str[256];
290  
291  
292 +        // Install the handler for SIGSEGV
293 +        if (!sigsegv_install_handler(sigsegv_handler)) {
294 +                sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGSEGV", strerror(errno));
295 +                ErrorAlert(str);
296 +                QuitEmulator();
297 +        }
298 +
299 +        // Register dump state function when we got mad after a segfault
300 +        sigsegv_set_dump_state(sigsegv_dump_state);
301 +
302          // Read RAM size
303          RAMSize = PrefsFindInt32("ramsize") & 0xfff00000;       // Round down to 1MB boundary
304          if (RAMSize < 1024*1024) {
305                  WarningAlert(GetString(STR_SMALL_RAM_WARN));
306                  RAMSize = 1024*1024;
307          }
308 +        if (RAMSize > 1023*1024*1024)                                           // Cap to 1023MB (APD crashes at 1GB)
309 +                RAMSize = 1023*1024*1024;
310  
311   #if REAL_ADDRESSING || DIRECT_ADDRESSING
312          RAMSize = RAMSize & -getpagesize();                                     // Round down to page boundary
# Line 196 | Line 318 | bool InitEmulator (void)
318   #if REAL_ADDRESSING
319          // Flag: RAM and ROM are contigously allocated from address 0
320          bool memory_mapped_from_zero = false;
321 <        
322 <        // Under Solaris/SPARC and NetBSD/m68k, Basilisk II is known to crash
323 <        // when trying to map a too big chunk of memory starting at address 0
324 < #if defined(OS_solaris) || defined(OS_netbsd)
325 <        const bool can_map_all_memory = false;
204 < #else
321 >
322 >        // Make sure to map RAM & ROM at address 0 only on platforms that
323 >        // supports linker scripts to relocate the Basilisk II executable
324 >        // above 0x70000000
325 > #if HAVE_LINKER_SCRIPT
326          const bool can_map_all_memory = true;
327 + #else
328 +        const bool can_map_all_memory = false;
329   #endif
330          
331          // Try to allocate all memory from 0x0000, if it is not known to crash
332 <        if (can_map_all_memory && (vm_acquire_fixed(0, RAMSize + 0x100000) == 0)) {
332 >        if (can_map_all_memory && (vm_acquire_mac_fixed(0, RAMSize + 0x100000) == 0)) {
333                  D(bug("Could allocate RAM and ROM from 0x0000\n"));
334                  memory_mapped_from_zero = true;
335          }
336          
337 + #ifndef PAGEZERO_HACK
338          // Otherwise, just create the Low Memory area (0x0000..0x2000)
339 <        else if (vm_acquire_fixed(0, 0x2000) == 0) {
339 >        else if (vm_acquire_mac_fixed(0, 0x2000) == 0) {
340                  D(bug("Could allocate the Low Memory globals\n"));
341                  lm_area_mapped = true;
342          }
# Line 224 | Line 348 | bool InitEmulator (void)
348                  QuitEmulator();
349          }
350   #endif
351 + #else
352 +        *str = 0;               // Eliminate unused variable warning
353 + #endif /* REAL_ADDRESSING */
354  
355          // Create areas for Mac RAM and ROM
356   #if REAL_ADDRESSING
# Line 234 | Line 361 | bool InitEmulator (void)
361          else
362   #endif
363          {
364 <                RAMBaseHost = (uint8 *)vm_acquire(RAMSize);
365 <                ROMBaseHost = (uint8 *)vm_acquire(0x100000);
239 <                if (RAMBaseHost == VM_MAP_FAILED || ROMBaseHost == VM_MAP_FAILED) {
364 >                uint8 *ram_rom_area = (uint8 *)vm_acquire_mac(RAMSize + 0x100000);
365 >                if (ram_rom_area == VM_MAP_FAILED) {
366                          ErrorAlert(STR_NO_MEM_ERR);
367                          QuitEmulator();
368                  }
369 +                RAMBaseHost = ram_rom_area;
370 +                ROMBaseHost = RAMBaseHost + RAMSize;
371          }
372  
373   #if USE_SCRATCHMEM_SUBTERFUGE
374          // Allocate scratch memory
375 <        ScratchMem = (uint8 *)vm_acquire(SCRATCH_MEM_SIZE);
375 >        ScratchMem = (uint8 *)vm_acquire_mac(SCRATCH_MEM_SIZE);
376          if (ScratchMem == VM_MAP_FAILED) {
377                  ErrorAlert(STR_NO_MEM_ERR);
378                  QuitEmulator();
# Line 259 | Line 387 | bool InitEmulator (void)
387          ROMBaseMac = Host2MacAddr(ROMBaseHost);
388   #endif
389   #if REAL_ADDRESSING
390 <        RAMBaseMac = (uint32)RAMBaseHost;
391 <        ROMBaseMac = (uint32)ROMBaseHost;
390 >        RAMBaseMac = Host2MacAddr(RAMBaseHost);
391 >        ROMBaseMac = Host2MacAddr(ROMBaseHost);
392   #endif
393          D(bug("Mac RAM starts at %p (%08x)\n", RAMBaseHost, RAMBaseMac));
394          D(bug("Mac ROM starts at %p (%08x)\n", ROMBaseHost, ROMBaseMac));
395          
396          // Get rom file path from preferences
397          const char *rom_path = PrefsFindString("rom");
398 +        if ( ! rom_path )
399 +          if ( bundle )
400 +                WarningAlert("No rom pathname set. Trying BasiliskII.app/ROM");
401 +          else
402 +                WarningAlert("No rom pathname set. Trying ./ROM");
403  
404          // Load Mac ROM
405          int rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME, O_RDONLY);
# Line 316 | Line 449 | bool InitEmulator (void)
449  
450   void QuitEmuNoExit()
451   {
319        extern  NSApplication *NSApp;
320
321
452          D(bug("QuitEmulator\n"));
453  
454          // Exit 680x0 emulation
# Line 329 | Line 459 | void QuitEmuNoExit()
459  
460          // Free ROM/RAM areas
461          if (RAMBaseHost != VM_MAP_FAILED) {
462 <                vm_release(RAMBaseHost, RAMSize);
462 >                vm_release(RAMBaseHost, RAMSize + 0x100000);
463                  RAMBaseHost = NULL;
334        }
335        if (ROMBaseHost != VM_MAP_FAILED) {
336                vm_release(ROMBaseHost, 0x100000);
464                  ROMBaseHost = NULL;
465          }
466  
# Line 359 | Line 486 | void QuitEmuNoExit()
486  
487          // Exit preferences
488          PrefsExit();
362
363        // Stop run loop
364        [NSApp terminate: nil];
489   }
490  
491   void QuitEmulator(void)
492   {
493          QuitEmuNoExit();
494 +
495 +        // Stop run loop?
496 +        [NSApp terminate: nil];
497 +
498          exit(0);
499   }
500  
# Line 378 | Line 506 | void QuitEmulator(void)
506  
507   void FlushCodeCache(void *start, uint32 size)
508   {
509 + #if USE_JIT
510 +        if (UseJIT)
511 +                flush_icache_range((uint8 *)start, size);
512 + #endif
513   }
514  
515  
# Line 399 | Line 531 | static void sigint_handler(...)
531   #endif
532  
533  
534 + #ifdef HAVE_PTHREADS
535 + /*
536 + *  Pthread configuration
537 + */
538 +
539 + void Set_pthread_attr(pthread_attr_t *attr, int priority)
540 + {
541 +        pthread_attr_init(attr);
542 + #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
543 +        // Some of these only work for superuser
544 +        if (geteuid() == 0) {
545 +                pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
546 +                pthread_attr_setschedpolicy(attr, SCHED_FIFO);
547 +                struct sched_param fifo_param;
548 +                fifo_param.sched_priority = ((sched_get_priority_min(SCHED_FIFO)
549 +                                                                         + sched_get_priority_max(SCHED_FIFO))
550 +                                                                         / 2 + priority);
551 +                pthread_attr_setschedparam(attr, &fifo_param);
552 +        }
553 +        if (pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM) != 0) {
554 + #ifdef PTHREAD_SCOPE_BOUND_NP
555 +            // If system scope is not available (eg. we're not running
556 +            // with CAP_SCHED_MGT capability on an SGI box), try bound
557 +            // scope.  It exposes pthread scheduling to the kernel,
558 +            // without setting realtime priority.
559 +            pthread_attr_setscope(attr, PTHREAD_SCOPE_BOUND_NP);
560 + #endif
561 +        }
562 + #endif
563 + }
564 + #endif // HAVE_PTHREADS
565 +
566 +
567   /*
568   *  Mutexes
569   */
# Line 406 | Line 571 | static void sigint_handler(...)
571   #ifdef HAVE_PTHREADS
572  
573   struct B2_mutex {
574 <        B2_mutex() { pthread_mutex_init(&m, NULL); }
575 <        ~B2_mutex() { pthread_mutex_unlock(&m); pthread_mutex_destroy(&m); }
574 >        B2_mutex() {
575 >                pthread_mutexattr_t attr;
576 >                pthread_mutexattr_init(&attr);
577 >                // Initialize the mutex for priority inheritance --
578 >                // required for accurate timing.
579 > #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
580 >                pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
581 > #endif
582 > #if defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE) && defined(PTHREAD_MUTEX_NORMAL)
583 >                pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
584 > #endif
585 > #ifdef HAVE_PTHREAD_MUTEXATTR_SETPSHARED
586 >                pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
587 > #endif
588 >                pthread_mutex_init(&m, &attr);
589 >                pthread_mutexattr_destroy(&attr);
590 >        }
591 >        ~B2_mutex() {
592 >                pthread_mutex_trylock(&m);      // Make sure it's locked before
593 >                pthread_mutex_unlock(&m);       // unlocking it.
594 >                pthread_mutex_destroy(&m);
595 >        }
596          pthread_mutex_t m;
597   };
598  
# Line 490 | Line 675 | void ErrorAlert(const char *text)
675          NSString *error  = [NSString stringWithCString: text];
676          NSString *button = [NSString stringWithCString: GetString(STR_QUIT_BUTTON) ];
677  
493 //      If we have a full screen mode, quit it here?
494
678          NSLog(error);
679 +        if ( PrefsFindBool("nogui") )
680 +                return;
681 +        VideoQuitFullScreen();
682          NSRunCriticalAlertPanel(title, error, button, nil, nil);
683   }
684  
# Line 509 | Line 695 | void WarningAlert(const char *text)
695          NSString *button  = [NSString stringWithCString: GetString(STR_OK_BUTTON) ];
696  
697          NSLog(warning);
698 +        if ( PrefsFindBool("nogui") )
699 +                return;
700 +        VideoQuitFullScreen();
701          NSRunAlertPanel(title, warning, button, nil, nil);
702   }
703  
# Line 525 | Line 714 | bool ChoiceAlert(const char *text, const
714          NSString *yes     = [NSString stringWithCString: pos];
715          NSString *no      = [NSString stringWithCString: neg];
716  
528        NSLog(warning);
717          return NSRunInformationalAlertPanel(title, warning, yes, no, nil);
718   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines