ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/main_unix.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/main_unix.cpp (file contents):
Revision 1.16 by cebix, 2000-07-22T18:12:34Z vs.
Revision 1.46 by gbeauche, 2002-05-12T11:10:50Z

# Line 1 | Line 1
1   /*
2   *  main_unix.cpp - Startup code for Unix
3   *
4 < *  Basilisk II (C) 1997-2000 Christian Bauer
4 > *  Basilisk II (C) 1997-2002 Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 30 | Line 30
30   # include <pthread.h>
31   #endif
32  
33 < #if defined(USE_MAPPED_MEMORY) || REAL_ADDRESSING
33 > #if REAL_ADDRESSING || DIRECT_ADDRESSING
34   # include <sys/mman.h>
35   #endif
36  
# Line 50 | Line 50 | struct sigstate {
50  
51   #ifdef ENABLE_GTK
52   # include <gtk/gtk.h>
53 + # include <gdk/gdk.h>
54 + # ifdef HAVE_GNOMEUI
55 + #  include <gnome.h>
56 + # endif
57   #endif
58  
59   #ifdef ENABLE_XF86_DGA
# Line 70 | Line 74 | struct sigstate {
74   #include "user_strings.h"
75   #include "version.h"
76   #include "main.h"
77 + #include "vm_alloc.h"
78 + #include "sigsegv.h"
79  
80   #ifdef ENABLE_MON
81   # include "mon.h"
# Line 107 | Line 113 | bool TwentyFourBitAddressing;
113   char *x_display_name = NULL;                                            // X11 display name
114   Display *x_display = NULL;                                                      // X11 display handle
115  
116 < static int zero_fd = -1;                                                        // FD of /dev/zero
111 < static uint8 last_xpram[256];                                           // Buffer for monitoring XPRAM changes
116 > static uint8 last_xpram[XPRAM_SIZE];                            // Buffer for monitoring XPRAM changes
117  
118   #ifdef HAVE_PTHREADS
119   static pthread_t emul_thread;                                           // Handle of MacOS emulation thread (main thread)
# Line 122 | Line 127 | static volatile bool tick_thread_cancel
127   static pthread_t tick_thread;                                           // 60Hz thread
128   static pthread_attr_t tick_thread_attr;                         // 60Hz thread attributes
129  
125 #if EMULATED_68K
130   static pthread_mutex_t intflag_lock = PTHREAD_MUTEX_INITIALIZER;        // Mutex to protect InterruptFlags
131 < #endif
131 > #define LOCK_INTFLAGS pthread_mutex_lock(&intflag_lock)
132 > #define UNLOCK_INTFLAGS pthread_mutex_unlock(&intflag_lock)
133 >
134 > #else
135 >
136 > #define LOCK_INTFLAGS
137 > #define UNLOCK_INTFLAGS
138 >
139   #endif
140  
141   #if !EMULATED_68K
# Line 133 | Line 144 | static struct sigaction sigirq_sa;     // Vi
144   static struct sigaction sigill_sa;      // Illegal instruction
145   static void *sig_stack = NULL;          // Stack for signal handlers
146   uint16 EmulatedSR;                                      // Emulated bits of SR (supervisor bit and interrupt mask)
147 < uint32 ScratchMem = NULL;                       // Scratch memory for Mac ROM writes
147 > #endif
148 >
149 > #if USE_SCRATCHMEM_SUBTERFUGE
150 > uint8 *ScratchMem = NULL;                       // Scratch memory for Mac ROM writes
151   #endif
152  
153   static struct sigaction timer_sa;       // sigaction used for timer
# Line 152 | Line 166 | static void sigint_handler(...);
166   static bool lm_area_mapped = false;     // Flag: Low Memory area mmap()ped
167   #endif
168  
155 #ifdef USE_MAPPED_MEMORY
156 extern char *address_space, *good_address_map;
157 #endif
158
169  
170   // Prototypes
171   static void *xpram_func(void *arg);
# Line 190 | Line 200 | char *strdup(const char *s)
200   *  Main program
201   */
202  
203 + static void usage(const char *prg_name)
204 + {
205 +        printf("Usage: %s [OPTION...]\n", prg_name);
206 +        printf("\nUnix options:\n");
207 +        printf("  --display STRING\n    X display to use\n");
208 +        printf("  --break ADDRESS\n    set ROM breakpoint\n");
209 +        printf("  --rominfo\n    dump ROM information\n");
210 +        PrefsPrintUsage();
211 +        exit(0);
212 + }
213 +
214   int main(int argc, char **argv)
215   {
216          char str[256];
# Line 204 | Line 225 | int main(int argc, char **argv)
225          printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
226          printf(" %s\n", GetString(STR_ABOUT_TEXT2));
227  
228 <        // Parse arguments
228 > #ifdef ENABLE_GTK
229 > #ifdef HAVE_GNOMEUI
230 >        // Init GNOME/GTK
231 >        char version[16];
232 >        sprintf(version, "%d.%d", VERSION_MAJOR, VERSION_MINOR);
233 >        gnome_init("Basilisk II", version, argc, argv);
234 > #else
235 >        // Init GTK
236 >        gtk_set_locale();
237 >        gtk_init(&argc, &argv);
238 > #endif
239 >        x_display_name = gdk_get_display(); // gtk_init() handles and removes the "--display" argument
240 > #endif
241 >
242 >        // Read preferences
243 >        PrefsInit(argc, argv);
244 >
245 >        // Parse command line arguments
246          for (int i=1; i<argc; i++) {
247 <                if (strcmp(argv[i], "-display") == 0 && ++i < argc)
248 <                        x_display_name = argv[i];
249 <                else if (strcmp(argv[i], "-break") == 0 && ++i < argc)
250 <                        ROMBreakpoint = strtol(argv[i], NULL, 0);
251 <                else if (strcmp(argv[i], "-rominfo") == 0)
247 >                if (strcmp(argv[i], "--help") == 0) {
248 >                        usage(argv[0]);
249 >                } else if (strcmp(argv[i], "--display") == 0) {
250 >                        i++;
251 >                        if (i < argc)
252 >                                x_display_name = strdup(argv[i]);
253 >                } else if (strcmp(argv[i], "--break") == 0) {
254 >                        i++;
255 >                        if (i < argc)
256 >                                ROMBreakpoint = strtol(argv[i], NULL, 0);
257 >                } else if (strcmp(argv[i], "--rominfo") == 0) {
258                          PrintROMInfo = true;
259 +                } else if (argv[i][0] == '-') {
260 +                        fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
261 +                        usage(argv[0]);
262 +                }
263          }
264  
265          // Open display
# Line 228 | Line 276 | int main(int argc, char **argv)
276          XF86DGAForkApp(DefaultScreen(x_display));
277   #endif
278  
231 #ifdef ENABLE_GTK
232        // Init GTK
233        gtk_set_locale();
234        gtk_init(&argc, &argv);
235 #endif
236
237        // Read preferences
238        PrefsInit();
239
279          // Init system routines
280          SysInit();
281  
# Line 245 | Line 284 | int main(int argc, char **argv)
284                  if (!PrefsEditor())
285                          QuitEmulator();
286  
287 <        // Open /dev/zero
288 <        zero_fd = open("/dev/zero", O_RDWR);
289 <        if (zero_fd < 0) {
290 <                sprintf(str, GetString(STR_NO_DEV_ZERO_ERR), strerror(errno));
291 <                ErrorAlert(str);
253 <                QuitEmulator();
254 <        }
287 >        // Register request to ignore segmentation faults
288 > #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
289 >        if (PrefsFindBool("ignoresegv"))
290 >          sigsegv_set_ignore_state(true);
291 > #endif
292  
293          // Read RAM size
294          RAMSize = PrefsFindInt32("ramsize") & 0xfff00000;       // Round down to 1MB boundary
# Line 260 | Line 297 | int main(int argc, char **argv)
297                  RAMSize = 1024*1024;
298          }
299  
300 + #if REAL_ADDRESSING || DIRECT_ADDRESSING
301 +        RAMSize = RAMSize & -getpagesize();                                     // Round down to page boundary
302 + #endif
303 +        
304 +        // Initialize VM system
305 +        vm_init();
306 +
307   #if REAL_ADDRESSING
308 <        // Create Low Memory area (0x0000..0x2000)
309 <        if (mmap((char *)0x0000, 0x2000, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, zero_fd, 0) == (void *)-1) {
308 >        // Flag: RAM and ROM are contigously allocated from address 0
309 >        bool memory_mapped_from_zero = false;
310 >        
311 >        // Under Solaris/SPARC and NetBSD/m68k, Basilisk II is known to crash
312 >        // when trying to map a too big chunk of memory starting at address 0
313 > #if defined(OS_solaris) || defined(OS_netbsd)
314 >        const bool can_map_all_memory = false;
315 > #else
316 >        const bool can_map_all_memory = true;
317 > #endif
318 >        
319 >        // Try to allocate all memory from 0x0000, if it is not known to crash
320 >        if (can_map_all_memory && (vm_acquire_fixed(0, RAMSize + 0x100000) == 0)) {
321 >                D(bug("Could allocate RAM and ROM from 0x0000\n"));
322 >                memory_mapped_from_zero = true;
323 >        }
324 >        
325 >        // Otherwise, just create the Low Memory area (0x0000..0x2000)
326 >        else if (vm_acquire_fixed(0, 0x2000) == 0) {
327 >                D(bug("Could allocate the Low Memory globals\n"));
328 >                lm_area_mapped = true;
329 >        }
330 >        
331 >        // Exit on failure
332 >        else {
333                  sprintf(str, GetString(STR_LOW_MEM_MMAP_ERR), strerror(errno));
334                  ErrorAlert(str);
335                  QuitEmulator();
336          }
270        lm_area_mapped = true;
337   #endif
338  
339 < #if !EMULATED_68K
339 >        // Create areas for Mac RAM and ROM
340 > #if REAL_ADDRESSING
341 >        if (memory_mapped_from_zero) {
342 >                RAMBaseHost = (uint8 *)0;
343 >                ROMBaseHost = RAMBaseHost + RAMSize;
344 >        }
345 >        else
346 > #endif
347 >        {
348 >                RAMBaseHost = (uint8 *)vm_acquire(RAMSize);
349 >                ROMBaseHost = (uint8 *)vm_acquire(0x100000);
350 >                if (RAMBaseHost == VM_MAP_FAILED || ROMBaseHost == VM_MAP_FAILED) {
351 >                        ErrorAlert(STR_NO_MEM_ERR);
352 >                        QuitEmulator();
353 >                }
354 >        }
355 >
356 > #if USE_SCRATCHMEM_SUBTERFUGE
357          // Allocate scratch memory
358 <        ScratchMem = (uint32)malloc(SCRATCH_MEM_SIZE);
359 <        if (ScratchMem == NULL) {
360 <                ErrorAlert(GetString(STR_NO_MEM_ERR));
358 >        ScratchMem = (uint8 *)vm_acquire(SCRATCH_MEM_SIZE);
359 >        if (ScratchMem == VM_MAP_FAILED) {
360 >                ErrorAlert(STR_NO_MEM_ERR);
361                  QuitEmulator();
362          }
363          ScratchMem += SCRATCH_MEM_SIZE/2;       // ScratchMem points to middle of block
364   #endif
365  
366 <        // Create areas for Mac RAM and ROM
367 < #if defined(USE_MAPPED_MEMORY)
368 <    good_address_map = (char *)mmap(NULL, 1<<24, PROT_READ, MAP_PRIVATE, zero_fd, 0);
369 <    address_space = (char *)mmap(NULL, 1<<24, PROT_READ | PROT_WRITE, MAP_PRIVATE, zero_fd, 0);
370 <    if ((int)address_space < 0 || (int)good_address_map < 0) {
288 <                ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
289 <                QuitEmulator();
290 <    }
291 <    RAMBaseHost = (uint8 *)mmap(address_space, RAMSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, zero_fd, 0);
292 <    ROMBaseHost = (uint8 *)mmap(address_space + 0x00400000, 0x80000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, zero_fd, 0);
293 <        char *nam = tmpnam(NULL);
294 <    int good_address_fd = open(nam, O_CREAT | O_RDWR, 0600);
295 <        char buffer[4096];
296 <    memset(buffer, 1, sizeof(buffer));
297 <    write(good_address_fd, buffer, sizeof(buffer));
298 <    unlink(nam);
299 <    for (int i=0; i<RAMSize; i+=4096)
300 <        mmap(good_address_map + i, 4096, PROT_READ, MAP_FIXED | MAP_PRIVATE, good_address_fd, 0);
301 <    for (int i=0; i<0x80000; i+=4096)
302 <        mmap(good_address_map + i + 0x00400000, 4096, PROT_READ, MAP_FIXED | MAP_PRIVATE, good_address_fd, 0);
303 < #else
304 <        RAMBaseHost = new uint8[RAMSize];
305 <        ROMBaseHost = new uint8[0x100000];
366 > #if DIRECT_ADDRESSING
367 >        // RAMBaseMac shall always be zero
368 >        MEMBaseDiff = (uintptr)RAMBaseHost;
369 >        RAMBaseMac = 0;
370 >        ROMBaseMac = Host2MacAddr(ROMBaseHost);
371   #endif
372 < #if REAL_ADDRESSING && !EMULATED_68K
372 > #if REAL_ADDRESSING
373          RAMBaseMac = (uint32)RAMBaseHost;
374          ROMBaseMac = (uint32)ROMBaseHost;
375   #endif
376          D(bug("Mac RAM starts at %p (%08x)\n", RAMBaseHost, RAMBaseMac));
377          D(bug("Mac ROM starts at %p (%08x)\n", ROMBaseHost, ROMBaseMac));
378 <
378 >        
379          // Get rom file path from preferences
380          const char *rom_path = PrefsFindString("rom");
381  
382          // Load Mac ROM
383          int rom_fd = open(rom_path ? rom_path : ROM_FILE_NAME, O_RDONLY);
384          if (rom_fd < 0) {
385 <                ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
385 >                ErrorAlert(STR_NO_ROM_FILE_ERR);
386                  QuitEmulator();
387          }
388          printf(GetString(STR_READING_ROM_FILE));
389          ROMSize = lseek(rom_fd, 0, SEEK_END);
390          if (ROMSize != 64*1024 && ROMSize != 128*1024 && ROMSize != 256*1024 && ROMSize != 512*1024 && ROMSize != 1024*1024) {
391 <                ErrorAlert(GetString(STR_ROM_SIZE_ERR));
391 >                ErrorAlert(STR_ROM_SIZE_ERR);
392                  close(rom_fd);
393                  QuitEmulator();
394          }
395          lseek(rom_fd, 0, SEEK_SET);
396          if (read(rom_fd, ROMBaseHost, ROMSize) != (ssize_t)ROMSize) {
397 <                ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
397 >                ErrorAlert(STR_ROM_FILE_READ_ERR);
398                  close(rom_fd);
399                  QuitEmulator();
400          }
# Line 359 | Line 424 | int main(int argc, char **argv)
424                  printf("WARNING: Cannot detect CPU type, assuming 68020\n");
425                  CPUType = 2;
426          }
427 <        FPUType = 0;    //!!
427 >        FPUType = 1;    // NetBSD has an FPU emulation, so the FPU ought to be available at all times
428          TwentyFourBitAddressing = false;
429   #endif
430  
# Line 381 | Line 446 | int main(int argc, char **argv)
446          sig_stack = malloc(SIG_STACK_SIZE);
447          D(bug("Signal stack at %p\n", sig_stack));
448          if (sig_stack == NULL) {
449 <                ErrorAlert(GetString(STR_NOT_ENOUGH_MEMORY_ERR));
449 >                ErrorAlert(STR_NOT_ENOUGH_MEMORY_ERR);
450                  QuitEmulator();
451          }
452          stack_t new_stack;
# Line 422 | Line 487 | int main(int argc, char **argv)
487   #ifdef ENABLE_MON
488          // Setup SIGINT handler to enter mon
489          sigemptyset(&sigint_sa.sa_mask);
490 <        sigint_sa.sa_handler = sigint_handler;
490 >        sigint_sa.sa_handler = (void (*)(int))sigint_handler;
491          sigint_sa.sa_flags = 0;
492          sigaction(SIGINT, &sigint_sa, NULL);
493   #endif
494  
495 < #if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
495 > #if defined(HAVE_PTHREADS)
496 >
497 >        // POSIX threads available, start 60Hz thread
498 >        Set_pthread_attr(&tick_thread_attr, 0);
499 >        tick_thread_active = (pthread_create(&tick_thread, &tick_thread_attr, tick_func, NULL) == 0);
500 >        if (!tick_thread_active) {
501 >                sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno));
502 >                ErrorAlert(str);
503 >                QuitEmulator();
504 >        }
505 >        D(bug("60Hz thread started\n"));
506 >
507 > #elif defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
508  
509          // POSIX.4 timers and real-time signals available, start 60Hz timer
510          sigemptyset(&timer_sa.sa_mask);
511 <        timer_sa.sa_sigaction = one_tick;
511 >        timer_sa.sa_sigaction = (void (*)(int, siginfo_t *, void *))one_tick;
512          timer_sa.sa_flags = SA_SIGINFO | SA_RESTART;
513          if (sigaction(SIG_TIMER, &timer_sa, NULL) < 0) {
514                  sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIG_TIMER", strerror(errno));
# Line 458 | Line 535 | int main(int argc, char **argv)
535          }
536          D(bug("60Hz timer started\n"));
537  
461 #elif defined(HAVE_PTHREADS)
462
463        // POSIX threads available, start 60Hz thread
464        pthread_attr_init(&tick_thread_attr);
465 #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
466        if (geteuid() == 0) {
467                pthread_attr_setinheritsched(&tick_thread_attr, PTHREAD_EXPLICIT_SCHED);
468                pthread_attr_setschedpolicy(&tick_thread_attr, SCHED_FIFO);
469                struct sched_param fifo_param;
470                fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2;
471                pthread_attr_setschedparam(&tick_thread_attr, &fifo_param);
472        }
473 #endif
474        tick_thread_active = (pthread_create(&tick_thread, &tick_thread_attr, tick_func, NULL) == 0);
475        if (!tick_thread_active) {
476                sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno));
477                ErrorAlert(str);
478                QuitEmulator();
479        }
480        D(bug("60Hz thread started\n"));
481
538   #else
539  
540          // Start 60Hz timer
# Line 500 | Line 556 | int main(int argc, char **argv)
556  
557   #ifdef HAVE_PTHREADS
558          // Start XPRAM watchdog thread
559 <        memcpy(last_xpram, XPRAM, 256);
559 >        memcpy(last_xpram, XPRAM, XPRAM_SIZE);
560          xpram_thread_active = (pthread_create(&xpram_thread, NULL, xpram_func, NULL) == 0);
561          D(bug("XPRAM thread started\n"));
562   #endif
# Line 527 | Line 583 | void QuitEmulator(void)
583          Exit680x0();
584   #endif
585  
586 < #if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
531 <        // Stop 60Hz timer
532 <        timer_delete(timer);
533 < #elif defined(HAVE_PTHREADS)
586 > #if defined(HAVE_PTHREADS)
587          // Stop 60Hz thread
588          if (tick_thread_active) {
589                  tick_thread_cancel = true;
# Line 539 | Line 592 | void QuitEmulator(void)
592   #endif
593                  pthread_join(tick_thread, NULL);
594          }
595 + #elif defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
596 +        // Stop 60Hz timer
597 +        timer_delete(timer);
598   #else
599          struct itimerval req;
600          req.it_interval.tv_sec = req.it_value.tv_sec = 0;
# Line 560 | Line 616 | void QuitEmulator(void)
616          // Deinitialize everything
617          ExitAll();
618  
619 <        // Delete ROM area
620 <        delete[] ROMBaseHost;
621 <
622 <        // Delete RAM area
623 <        delete[] RAMBaseHost;
619 >        // Free ROM/RAM areas
620 >        if (RAMBaseHost != VM_MAP_FAILED) {
621 >                vm_release(RAMBaseHost, RAMSize);
622 >                RAMBaseHost = NULL;
623 >        }
624 >        if (ROMBaseHost != VM_MAP_FAILED) {
625 >                vm_release(ROMBaseHost, 0x100000);
626 >                ROMBaseHost = NULL;
627 >        }
628  
629 < #if !EMULATED_68K
629 > #if USE_SCRATCHMEM_SUBTERFUGE
630          // Delete scratch memory area
631 <        if (ScratchMem)
632 <                free((void *)(ScratchMem - SCRATCH_MEM_SIZE/2));
631 >        if (ScratchMem != (uint8 *)VM_MAP_FAILED) {
632 >                vm_release((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE);
633 >                ScratchMem = NULL;
634 >        }
635   #endif
636  
637   #if REAL_ADDRESSING
638          // Delete Low Memory area
639          if (lm_area_mapped)
640 <                munmap((char *)0x0000, 0x2000);
640 >                vm_release(0, 0x2000);
641   #endif
642 <
643 <        // Close /dev/zero
644 <        if (zero_fd > 0)
583 <                close(zero_fd);
642 >        
643 >        // Exit VM wrappers
644 >        vm_exit();
645  
646          // Exit system routines
647          SysExit();
# Line 620 | Line 681 | static void sigint_handler(...)
681          uaecptr nextpc;
682          extern void m68k_dumpstate(uaecptr *nextpc);
683          m68k_dumpstate(&nextpc);
684 < #else
685 <        char *arg[2] = {"rmon", NULL};
686 <        mon(1, arg);
684 > #endif
685 >        VideoQuitFullScreen();
686 >        char *arg[4] = {"mon", "-m", "-r", NULL};
687 >        mon(3, arg);
688          QuitEmulator();
689 + }
690   #endif
691 +
692 +
693 + #ifdef HAVE_PTHREADS
694 + /*
695 + *  Pthread configuration
696 + */
697 +
698 + void Set_pthread_attr(pthread_attr_t *attr, int priority)
699 + {
700 +        pthread_attr_init(attr);
701 + #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
702 +        // Some of these only work for superuser
703 +        if (geteuid() == 0) {
704 +                pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED);
705 +                pthread_attr_setschedpolicy(attr, SCHED_FIFO);
706 +                struct sched_param fifo_param;
707 +                fifo_param.sched_priority = ((sched_get_priority_min(SCHED_FIFO) +
708 +                                              sched_get_priority_max(SCHED_FIFO)) / 2 +
709 +                                             priority);
710 +                pthread_attr_setschedparam(attr, &fifo_param);
711 +        }
712 +        if (pthread_attr_setscope(attr, PTHREAD_SCOPE_SYSTEM) != 0) {
713 + #ifdef PTHREAD_SCOPE_BOUND_NP
714 +            // If system scope is not available (eg. we're not running
715 +            // with CAP_SCHED_MGT capability on an SGI box), try bound
716 +            // scope.  It exposes pthread scheduling to the kernel,
717 +            // without setting realtime priority.
718 +            pthread_attr_setscope(attr, PTHREAD_SCOPE_BOUND_NP);
719 + #endif
720 +        }
721 + #endif
722 + }
723 + #endif // HAVE_PTHREADS
724 +
725 +
726 + /*
727 + *  Mutexes
728 + */
729 +
730 + #ifdef HAVE_PTHREADS
731 +
732 + struct B2_mutex {
733 +        B2_mutex() {
734 +            pthread_mutexattr_t attr;
735 +            pthread_mutexattr_init(&attr);
736 +            // Initialize the mutex for priority inheritance --
737 +            // required for accurate timing.
738 + #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
739 +            pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
740 + #endif
741 + #if defined(HAVE_PTHREAD_MUTEXATTR_SETTYPE) && defined(PTHREAD_MUTEX_NORMAL)
742 +            pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
743 + #endif
744 +            pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
745 +            pthread_mutex_init(&m, &attr);
746 +            pthread_mutexattr_destroy(&attr);
747 +        }
748 +        ~B2_mutex() { pthread_mutex_unlock(&m); pthread_mutex_destroy(&m); }
749 +        pthread_mutex_t m;
750 + };
751 +
752 + B2_mutex *B2_create_mutex(void)
753 + {
754 +        return new B2_mutex;
755 + }
756 +
757 + void B2_lock_mutex(B2_mutex *mutex)
758 + {
759 +        pthread_mutex_lock(&mutex->m);
760   }
761 +
762 + void B2_unlock_mutex(B2_mutex *mutex)
763 + {
764 +        pthread_mutex_unlock(&mutex->m);
765 + }
766 +
767 + void B2_delete_mutex(B2_mutex *mutex)
768 + {
769 +        delete mutex;
770 + }
771 +
772 + #else
773 +
774 + struct B2_mutex {
775 +        int dummy;
776 + };
777 +
778 + B2_mutex *B2_create_mutex(void)
779 + {
780 +        return new B2_mutex;
781 + }
782 +
783 + void B2_lock_mutex(B2_mutex *mutex)
784 + {
785 + }
786 +
787 + void B2_unlock_mutex(B2_mutex *mutex)
788 + {
789 + }
790 +
791 + void B2_delete_mutex(B2_mutex *mutex)
792 + {
793 +        delete mutex;
794 + }
795 +
796   #endif
797  
798  
# Line 638 | Line 805 | uint32 InterruptFlags = 0;
805   #if EMULATED_68K
806   void SetInterruptFlag(uint32 flag)
807   {
808 < #ifdef HAVE_PTHREADS
642 <        pthread_mutex_lock(&intflag_lock);
808 >        LOCK_INTFLAGS;
809          InterruptFlags |= flag;
810 <        pthread_mutex_unlock(&intflag_lock);
645 < #else
646 <        InterruptFlags |= flag;         // Pray that this is an atomic operation...
647 < #endif
810 >        UNLOCK_INTFLAGS;
811   }
812  
813   void ClearInterruptFlag(uint32 flag)
814   {
815 < #ifdef HAVE_PTHREADS
653 <        pthread_mutex_lock(&intflag_lock);
815 >        LOCK_INTFLAGS;
816          InterruptFlags &= ~flag;
817 <        pthread_mutex_unlock(&intflag_lock);
656 < #else
657 <        InterruptFlags &= ~flag;
658 < #endif
817 >        UNLOCK_INTFLAGS;
818   }
819   #endif
820  
# Line 668 | Line 827 | void TriggerInterrupt(void)
827          raise(SIG_IRQ);
828   #endif
829   }
830 +
831 + void TriggerNMI(void)
832 + {
833 +        // not yet supported
834 + }
835   #endif
836  
837  
# Line 677 | Line 841 | void TriggerInterrupt(void)
841  
842   static void xpram_watchdog(void)
843   {
844 <        if (memcmp(last_xpram, XPRAM, 256)) {
845 <                memcpy(last_xpram, XPRAM, 256);
844 >        if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
845 >                memcpy(last_xpram, XPRAM, XPRAM_SIZE);
846                  SaveXPRAM();
847          }
848   }
# Line 688 | Line 852 | static void *xpram_func(void *arg)
852   {
853          while (!xpram_thread_cancel) {
854                  for (int i=0; i<60 && !xpram_thread_cancel; i++)
855 <                        Delay_usec(1000000);
855 >                        Delay_usec(999999);             // Only wait 1 second so we quit promptly when xpram_thread_cancel becomes true
856                  xpram_watchdog();
857          }
858          return NULL;
# Line 705 | Line 869 | static void one_second(void)
869          // Pseudo Mac 1Hz interrupt, update local time
870          WriteMacInt32(0x20c, TimerDateTime());
871  
872 <        SetInterruptFlag(INTFLAG_60HZ);
872 >        SetInterruptFlag(INTFLAG_1HZ);
873          TriggerInterrupt();
874  
875   #ifndef HAVE_PTHREADS
# Line 726 | Line 890 | static void one_tick(...)
890          }
891  
892   #ifndef HAVE_PTHREADS
893 <        // No threads available, perform video refresh from here
893 >        // No threads available, perform video refresh and networking from here
894          VideoRefresh();
895 +        SetInterruptFlag(INTFLAG_ETHER);
896   #endif
897  
898          // Trigger 60Hz interrupt
# Line 740 | Line 905 | static void one_tick(...)
905   #ifdef HAVE_PTHREADS
906   static void *tick_func(void *arg)
907   {
908 +        uint64 start = GetTicks_usec();
909 +        int64 ticks = 0;
910          uint64 next = GetTicks_usec();
911          while (!tick_thread_cancel) {
912                  one_tick();
# Line 749 | Line 916 | static void *tick_func(void *arg)
916                          Delay_usec(delay);
917                  else if (delay < -16625)
918                          next = GetTicks_usec();
919 +                ticks++;
920          }
921 +        uint64 end = GetTicks_usec();
922 +        D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
923          return NULL;
924   }
925   #endif
926  
927  
758 /*
759 *  Get current value of microsecond timer
760 */
761
762 uint64 GetTicks_usec(void)
763 {
764 #ifdef HAVE_CLOCK_GETTIME
765        struct timespec t;
766        clock_gettime(CLOCK_REALTIME, &t);
767        return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000;
768 #else
769        struct timeval t;
770        gettimeofday(&t, NULL);
771        return (uint64)t.tv_sec * 1000000 + t.tv_usec;
772 #endif
773 }
774
775
776 /*
777 *  Delay by specified number of microseconds (<1 second)
778 *  (adapted from SDL_Delay() source)
779 */
780
781 void Delay_usec(uint32 usec)
782 {
783        int was_error;
784 #ifndef __linux__       // Non-Linux implementations need to calculate time left
785        uint64 then, now, elapsed;
786 #endif
787        struct timeval tv;
788
789        // Set the timeout interval - Linux only needs to do this once
790 #ifdef __linux__
791        tv.tv_sec = 0;
792        tv.tv_usec = usec;
793 #else
794        then = GetTicks_usec();
795 #endif
796        do {
797                errno = 0;
798 #ifndef __linux__
799                /* Calculate the time interval left (in case of interrupt) */
800                now = GetTicks_usec();
801                elapsed = now - then;
802                then = now;
803                if (elapsed >= usec)
804                        break;
805                usec -= elapsed;
806                tv.tv_sec = 0;
807                tv.tv_usec = usec;
808 #endif
809                was_error = select(0, NULL, NULL, NULL, &tv);
810        } while (was_error && (errno == EINTR));
811 }
812
813
928   #if !EMULATED_68K
929   /*
930   *  Virtual 68k interrupt handler
# Line 861 | Line 975 | static void sigill_handler(int sig, int
975  
976   #define STORE_SR(v) \
977          scp->sc_ps = (v) & 0xff; \
978 <        EmulatedSR = (v) & 0x2700; \
978 >        EmulatedSR = (v) & 0xe700; \
979          if (((v) & 0x0700) == 0 && InterruptFlags) \
980                  TriggerInterrupt();
981  
# Line 924 | Line 1038 | static void sigill_handler(int sig, int
1038                  case 0x007c: {  // ori #xxxx,sr
1039                          uint16 sr = GET_SR | pc[1];
1040                          scp->sc_ps = sr & 0xff;         // oring bits into the sr can't enable interrupts, so we don't need to call STORE_SR
1041 <                        EmulatedSR = sr & 0x2700;
1041 >                        EmulatedSR = sr & 0xe700;
1042                          INC_PC(4);
1043                          break;
1044                  }
# Line 1001 | Line 1115 | static void sigill_handler(int sig, int
1115                  }
1116  
1117                  case 0xf327:    // fsave -(sp)
1118 <                        goto ill;       //!!
1118 >                        regs->a[7] -= 4;
1119 >                        WriteMacInt32(regs->a[7], 0x41000000);  // Idle frame
1120 >                        scp->sc_sp = regs->a[7];
1121 >                        INC_PC(2);
1122 >                        break;
1123  
1124                  case 0xf35f:    // frestore (sp)+
1125 <                        goto ill;       //!!
1125 >                        regs->a[7] += 4;
1126 >                        scp->sc_sp = regs->a[7];
1127 >                        INC_PC(2);
1128 >                        break;
1129  
1130 <                case 0x4e73: {  // rte (only handles format 0)
1130 >                case 0x4e73: {  // rte
1131                          uint32 a7 = regs->a[7];
1132                          uint16 sr = ReadMacInt16(a7);
1133                          a7 += 2;
1134                          scp->sc_ps = sr & 0xff;
1135 <                        EmulatedSR = sr & 0x2700;
1135 >                        EmulatedSR = sr & 0xe700;
1136                          scp->sc_pc = ReadMacInt32(a7);
1137 <                        a7 += 6;
1138 <                        scp->sc_sp = regs->a[7] = a7;
1137 >                        a7 += 4;
1138 >                        uint16 format = ReadMacInt16(a7) >> 12;
1139 >                        a7 += 2;
1140 >                        static const int frame_adj[16] = {
1141 >                                0, 0, 4, 4, 8, 0, 0, 52, 50, 12, 24, 84, 16, 0, 0, 0
1142 >                        };
1143 >                        scp->sc_sp = regs->a[7] = a7 + frame_adj[format];
1144                          break;
1145                  }
1146  
1147                  case 0x4e7a:    // movec cr,x
1148                          switch (pc[1]) {
1023                                case 0x8801:    // movec vbr,a0
1024                                        regs->a[0] = 0;
1025                                        break;
1026                                case 0x9801:    // movec vbr,a1
1027                                        regs->a[1] = 0;
1028                                        break;
1149                                  case 0x0002:    // movec cacr,d0
1150                                          regs->d[0] = 0x3111;
1151                                          break;
# Line 1033 | Line 1153 | static void sigill_handler(int sig, int
1153                                          regs->d[1] = 0x3111;
1154                                          break;
1155                                  case 0x0003:    // movec tc,d0
1156 +                                case 0x0004:    // movec itt0,d0
1157 +                                case 0x0005:    // movec itt1,d0
1158 +                                case 0x0006:    // movec dtt0,d0
1159 +                                case 0x0007:    // movec dtt1,d0
1160 +                                case 0x0806:    // movec urp,d0
1161 +                                case 0x0807:    // movec srp,d0
1162                                          regs->d[0] = 0;
1163                                          break;
1164 +                                case 0x1000:    // movec sfc,d1
1165 +                                case 0x1001:    // movec dfc,d1
1166                                  case 0x1003:    // movec tc,d1
1167 +                                case 0x1801:    // movec vbr,d1
1168                                          regs->d[1] = 0;
1169                                          break;
1170 +                                case 0x8801:    // movec vbr,a0
1171 +                                        regs->a[0] = 0;
1172 +                                        break;
1173 +                                case 0x9801:    // movec vbr,a1
1174 +                                        regs->a[1] = 0;
1175 +                                        break;
1176                                  default:
1177                                          goto ill;
1178                          }
# Line 1046 | Line 1181 | static void sigill_handler(int sig, int
1181  
1182                  case 0x4e7b:    // movec x,cr
1183                          switch (pc[1]) {
1184 +                                case 0x1000:    // movec d1,sfc
1185 +                                case 0x1001:    // movec d1,dfc
1186                                  case 0x0801:    // movec d0,vbr
1187 +                                case 0x1801:    // movec d1,vbr
1188                                          break;
1189                                  case 0x0002:    // movec d0,cacr
1190                                  case 0x1002:    // movec d1,cacr
# Line 1080 | Line 1218 | ill:           printf("SIGILL num %d, code %d\n",
1218                          for (int i=0; i<8; i++)
1219                                  printf("  a%d %08x\n", i, state->ss_frame.f_regs[i+8]);
1220  
1221 +                        VideoQuitFullScreen();
1222   #ifdef ENABLE_MON
1223 <                        char *arg[2] = {"rmon", NULL};
1224 <                        mon(1, arg);
1223 >                        char *arg[4] = {"mon", "-m", "-r", NULL};
1224 >                        mon(3, arg);
1225   #endif
1226                          QuitEmulator();
1227                          break;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines