ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Windows/main_windows.cpp
Revision: 1.13
Committed: 2006-05-14T15:58:11Z (18 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.12: +5 -20 lines
Log Message:
Move up NATMEM_OFFSET to 0x11000000. This is arbitrarily determined to be
the base of the largest free block. Turns out SDL libraries are loaded around
0x10000000 so we have some luck here.

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * main_windows.cpp - Emulation core, Windows implementation
3     *
4 gbeauche 1.7 * SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig
5 gbeauche 1.1 *
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
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include <errno.h>
22     #include <stdio.h>
23     #include <stdlib.h>
24     #include <string.h>
25    
26     #include <SDL.h>
27    
28     #include "sysdeps.h"
29     #include "main.h"
30     #include "version.h"
31     #include "prefs.h"
32     #include "prefs_editor.h"
33     #include "cpu_emulation.h"
34     #include "emul_op.h"
35     #include "xlowmem.h"
36     #include "xpram.h"
37     #include "timer.h"
38     #include "adb.h"
39     #include "video.h"
40     #include "sys.h"
41     #include "macos_util.h"
42     #include "rom_patches.h"
43     #include "user_strings.h"
44     #include "vm_alloc.h"
45     #include "sigsegv.h"
46 gbeauche 1.3 #include "util_windows.h"
47 gbeauche 1.11 #include "kernel_windows.h"
48 gbeauche 1.1
49     #define DEBUG 0
50     #include "debug.h"
51    
52     #ifdef ENABLE_MON
53     #include "mon.h"
54     #endif
55    
56    
57     // Constants
58     const char ROM_FILE_NAME[] = "ROM";
59     const char ROM_FILE_NAME2[] = "Mac OS ROM";
60    
61     const uint32 SIG_STACK_SIZE = 0x10000; // Size of signal stack
62    
63    
64     // Global variables (exported)
65     uint32 RAMBase; // Base address of Mac RAM
66     uint32 RAMSize; // Size of Mac RAM
67     uint32 KernelDataAddr; // Address of Kernel Data
68     uint32 BootGlobsAddr; // Address of BootGlobs structure at top of Mac RAM
69     uint32 DRCacheAddr; // Address of DR Cache
70     uint32 PVR; // Theoretical PVR
71     int64 CPUClockSpeed; // Processor clock speed (Hz)
72     int64 BusClockSpeed; // Bus clock speed (Hz)
73     int64 TimebaseSpeed; // Timebase clock speed (Hz)
74     uint8 *RAMBaseHost; // Base address of Mac RAM (host address space)
75     uint8 *ROMBaseHost; // Base address of Mac ROM (host address space)
76 gbeauche 1.9 DWORD win_os; // Windows OS id
77     DWORD win_os_major; // Windows OS version major
78 gbeauche 1.1
79    
80     // Global variables
81     static int kernel_area = -1; // SHM ID of Kernel Data area
82     static bool rom_area_mapped = false; // Flag: Mac ROM mmap()ped
83     static bool ram_area_mapped = false; // Flag: Mac RAM mmap()ped
84     static bool dr_cache_area_mapped = false; // Flag: Mac DR Cache mmap()ped
85     static bool dr_emulator_area_mapped = false;// Flag: Mac DR Emulator mmap()ped
86     static KernelData *kernel_data; // Pointer to Kernel Data
87     static EmulatorData *emulator_data;
88    
89     static uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes
90     static bool nvram_thread_active = false; // Flag: NVRAM watchdog installed
91     static volatile bool nvram_thread_cancel; // Flag: Cancel NVRAM thread
92 gbeauche 1.3 static HANDLE nvram_thread = NULL; // NVRAM watchdog
93 gbeauche 1.1 static bool tick_thread_active = false; // Flag: MacOS thread installed
94     static volatile bool tick_thread_cancel; // Flag: Cancel 60Hz thread
95 gbeauche 1.3 static HANDLE tick_thread = NULL; // 60Hz thread
96     static HANDLE emul_thread = NULL; // MacOS thread
97 gbeauche 1.1 static uintptr sig_stack = 0; // Stack for PowerPC interrupt routine
98    
99     uint32 SheepMem::page_size; // Size of a native page
100     uintptr SheepMem::zero_page = 0; // Address of ro page filled in with zeros
101     uintptr SheepMem::base = 0x60000000; // Address of SheepShaver data
102     uintptr SheepMem::proc; // Bottom address of SheepShave procedures
103     uintptr SheepMem::data; // Top of SheepShaver data (stack like storage)
104    
105    
106     // Prototypes
107     static bool kernel_data_init(void);
108     static void kernel_data_exit(void);
109     static void Quit(void);
110 gbeauche 1.3 static DWORD WINAPI nvram_func(void *arg);
111     static DWORD WINAPI tick_func(void *arg);
112 gbeauche 1.1
113     static void jump_to_rom(uint32 entry);
114     extern void emul_ppc(uint32 start);
115     extern void init_emul_ppc(void);
116     extern void exit_emul_ppc(void);
117     sigsegv_return_t sigsegv_handler(sigsegv_address_t, sigsegv_address_t);
118    
119    
120     /*
121     * Return signal stack base
122     */
123    
124     uintptr SignalStackBase(void)
125     {
126     return sig_stack + SIG_STACK_SIZE;
127     }
128    
129    
130     /*
131     * Memory management helpers
132     */
133    
134     static inline int vm_mac_acquire(uint32 addr, uint32 size)
135     {
136     return vm_acquire_fixed(Mac2HostAddr(addr), size);
137     }
138    
139     static inline int vm_mac_release(uint32 addr, uint32 size)
140     {
141     return vm_release(Mac2HostAddr(addr), size);
142     }
143    
144    
145     /*
146     * Main program
147     */
148    
149     static void usage(const char *prg_name)
150     {
151     printf("Usage: %s [OPTION...]\n", prg_name);
152     printf("\nUnix options:\n");
153     printf(" --display STRING\n X display to use\n");
154     PrefsPrintUsage();
155     exit(0);
156     }
157    
158     int main(int argc, char **argv)
159     {
160     char str[256];
161     int16 i16;
162     HANDLE rom_fh;
163     const char *rom_path;
164     uint32 rom_size;
165     DWORD actual;
166     uint8 *rom_tmp;
167    
168     // Initialize variables
169     RAMBase = 0;
170    
171     // Print some info
172     printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
173     printf(" %s\n", GetString(STR_ABOUT_TEXT2));
174    
175     // Read preferences
176     PrefsInit(argc, argv);
177    
178     // Parse command line arguments
179     for (int i=1; i<argc; i++) {
180     if (strcmp(argv[i], "--help") == 0) {
181     usage(argv[0]);
182     } else if (argv[i][0] == '-') {
183     fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
184     usage(argv[0]);
185     }
186     }
187    
188 gbeauche 1.9 // Check we are using a Windows NT kernel >= 4.0
189     OSVERSIONINFO osvi;
190     ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
191     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
192     if (!GetVersionEx(&osvi)) {
193     ErrorAlert("Could not determine OS type");
194     QuitEmulator();
195     }
196     win_os = osvi.dwPlatformId;
197     win_os_major = osvi.dwMajorVersion;
198     if (win_os != VER_PLATFORM_WIN32_NT || win_os_major < 4) {
199     ErrorAlert(GetString(STR_NO_WIN32_NT_4));
200     QuitEmulator();
201     }
202    
203     // Check that drivers are installed
204     if (!check_drivers())
205     QuitEmulator();
206    
207 gbeauche 1.11 // Load win32 libraries
208     KernelInit();
209    
210 gbeauche 1.10 // FIXME: default to DIB driver
211     if (getenv("SDL_VIDEODRIVER") == NULL)
212     putenv("SDL_VIDEODRIVER=windib");
213    
214 gbeauche 1.1 // Initialize SDL system
215     int sdl_flags = 0;
216     #ifdef USE_SDL_VIDEO
217     sdl_flags |= SDL_INIT_VIDEO;
218     #endif
219     #ifdef USE_SDL_AUDIO
220     sdl_flags |= SDL_INIT_AUDIO;
221     #endif
222     assert(sdl_flags != 0);
223     if (SDL_Init(sdl_flags) == -1) {
224     char str[256];
225     sprintf(str, "Could not initialize SDL: %s.\n", SDL_GetError());
226     ErrorAlert(str);
227     goto quit;
228     }
229     atexit(SDL_Quit);
230    
231     #ifdef ENABLE_MON
232     // Initialize mon
233     mon_init();
234     #endif
235    
236     // Install SIGSEGV handler for CPU emulator
237     if (!sigsegv_install_handler(sigsegv_handler)) {
238     sprintf(str, GetString(STR_SIGSEGV_INSTALL_ERR), strerror(errno));
239     ErrorAlert(str);
240     goto quit;
241     }
242    
243     // Initialize VM system
244     vm_init();
245    
246     // Get system info
247     PVR = 0x00040000; // Default: 604
248     CPUClockSpeed = 100000000; // Default: 100MHz
249     BusClockSpeed = 100000000; // Default: 100MHz
250     TimebaseSpeed = 25000000; // Default: 25MHz
251     PVR = 0x000c0000; // Default: 7400 (with AltiVec)
252     D(bug("PVR: %08x (assumed)\n", PVR));
253    
254     // Init system routines
255     SysInit();
256    
257     // Show preferences editor
258     if (!PrefsFindBool("nogui"))
259     if (!PrefsEditor())
260     goto quit;
261    
262     // Create areas for Kernel Data
263     if (!kernel_data_init())
264     goto quit;
265     kernel_data = (KernelData *)Mac2HostAddr(KERNEL_DATA_BASE);
266     emulator_data = &kernel_data->ed;
267     KernelDataAddr = KERNEL_DATA_BASE;
268     D(bug("Kernel Data at %p (%08x)\n", kernel_data, KERNEL_DATA_BASE));
269     D(bug("Emulator Data at %p (%08x)\n", emulator_data, KERNEL_DATA_BASE + offsetof(KernelData, ed)));
270    
271     // Create area for DR Cache
272     if (vm_mac_acquire(DR_EMULATOR_BASE, DR_EMULATOR_SIZE) < 0) {
273     sprintf(str, GetString(STR_DR_EMULATOR_MMAP_ERR), strerror(errno));
274     ErrorAlert(str);
275     goto quit;
276     }
277     dr_emulator_area_mapped = true;
278     if (vm_mac_acquire(DR_CACHE_BASE, DR_CACHE_SIZE) < 0) {
279     sprintf(str, GetString(STR_DR_CACHE_MMAP_ERR), strerror(errno));
280     ErrorAlert(str);
281     goto quit;
282     }
283     dr_cache_area_mapped = true;
284     DRCacheAddr = (uint32)Mac2HostAddr(DR_CACHE_BASE);
285     D(bug("DR Cache at %p (%08x)\n", DRCacheAddr, DR_CACHE_BASE));
286    
287     // Create area for SheepShaver data
288     if (!SheepMem::Init()) {
289     sprintf(str, GetString(STR_SHEEP_MEM_MMAP_ERR), strerror(errno));
290     ErrorAlert(str);
291     goto quit;
292     }
293    
294     // Create area for Mac ROM
295     if (vm_mac_acquire(ROM_BASE, ROM_AREA_SIZE) < 0) {
296     sprintf(str, GetString(STR_ROM_MMAP_ERR), strerror(errno));
297     ErrorAlert(str);
298     goto quit;
299     }
300     ROMBaseHost = Mac2HostAddr(ROM_BASE);
301     rom_area_mapped = true;
302     D(bug("ROM area at %p (%08x)\n", ROMBaseHost, ROM_BASE));
303    
304     // Create area for Mac RAM
305     RAMSize = PrefsFindInt32("ramsize");
306     if (RAMSize < 8*1024*1024) {
307     WarningAlert(GetString(STR_SMALL_RAM_WARN));
308     RAMSize = 8*1024*1024;
309     }
310 gbeauche 1.13 RAMBase = 0;
311     if (vm_mac_acquire(RAMBase, RAMSize) < 0) {
312 gbeauche 1.1 sprintf(str, GetString(STR_RAM_MMAP_ERR), strerror(errno));
313     ErrorAlert(str);
314     goto quit;
315     }
316 gbeauche 1.13 RAMBaseHost = Mac2HostAddr(RAMBase);
317 gbeauche 1.1 ram_area_mapped = true;
318     D(bug("RAM area at %p (%08x)\n", RAMBaseHost, RAMBase));
319    
320     if (RAMBase > ROM_BASE) {
321     ErrorAlert(GetString(STR_RAM_HIGHER_THAN_ROM_ERR));
322     goto quit;
323     }
324    
325     // Load Mac ROM
326     rom_path = PrefsFindString("rom");
327     rom_fh = CreateFile(rom_path ? rom_path : ROM_FILE_NAME,
328     GENERIC_READ, 0, NULL, OPEN_EXISTING,
329     FILE_ATTRIBUTE_NORMAL, NULL);
330    
331     if (rom_fh == INVALID_HANDLE_VALUE) {
332     rom_fh = CreateFile(rom_path ? rom_path : ROM_FILE_NAME2,
333     GENERIC_READ, 0, NULL, OPEN_EXISTING,
334     FILE_ATTRIBUTE_NORMAL, NULL);
335    
336     if (rom_fh == INVALID_HANDLE_VALUE) {
337     ErrorAlert(GetString(STR_NO_ROM_FILE_ERR));
338     goto quit;
339     }
340     }
341     printf(GetString(STR_READING_ROM_FILE));
342     rom_size = GetFileSize(rom_fh, NULL);
343     rom_tmp = new uint8[ROM_SIZE];
344     ReadFile(rom_fh, (void *)rom_tmp, ROM_SIZE, &actual, NULL);
345     CloseHandle(rom_fh);
346    
347     // Decode Mac ROM
348     if (!DecodeROM(rom_tmp, actual)) {
349     if (rom_size != 4*1024*1024) {
350     ErrorAlert(GetString(STR_ROM_SIZE_ERR));
351     goto quit;
352     } else {
353     ErrorAlert(GetString(STR_ROM_FILE_READ_ERR));
354     goto quit;
355     }
356     }
357     delete[] rom_tmp;
358 gbeauche 1.8
359     // Initialize native timers
360     timer_init();
361 gbeauche 1.1
362 gbeauche 1.6 // Initialize everything
363     if (!InitAll())
364 gbeauche 1.1 goto quit;
365 gbeauche 1.6 D(bug("Initialization complete\n"));
366 gbeauche 1.1
367     // Write protect ROM
368 gbeauche 1.6 vm_protect(ROMBaseHost, ROM_AREA_SIZE, VM_PAGE_READ);
369 gbeauche 1.1
370     // Start 60Hz thread
371     tick_thread_cancel = false;
372 gbeauche 1.3 tick_thread_active = ((tick_thread = create_thread(tick_func)) != NULL);
373     SetThreadPriority(tick_thread, THREAD_PRIORITY_ABOVE_NORMAL);
374 gbeauche 1.1 D(bug("Tick thread installed (%ld)\n", tick_thread));
375    
376     // Start NVRAM watchdog thread
377     memcpy(last_xpram, XPRAM, XPRAM_SIZE);
378     nvram_thread_cancel = false;
379 gbeauche 1.3 nvram_thread_active = ((nvram_thread = create_thread(nvram_func, NULL)) != NULL);
380     SetThreadPriority(nvram_thread, THREAD_PRIORITY_BELOW_NORMAL);
381 gbeauche 1.1 D(bug("NVRAM thread installed (%ld)\n", nvram_thread));
382    
383 gbeauche 1.3 // Get my thread ID and jump to ROM boot routine
384     emul_thread = GetCurrentThread();
385 gbeauche 1.1 D(bug("Jumping to ROM\n"));
386     jump_to_rom(ROM_BASE + 0x310000);
387     D(bug("Returned from ROM\n"));
388    
389     quit:
390     Quit();
391     return 0;
392     }
393    
394    
395     /*
396     * Cleanup and quit
397     */
398    
399     static void Quit(void)
400     {
401     // Exit PowerPC emulation
402     exit_emul_ppc();
403    
404     // Stop 60Hz thread
405     if (tick_thread_active) {
406     tick_thread_cancel = true;
407 gbeauche 1.3 wait_thread(tick_thread);
408 gbeauche 1.1 }
409    
410     // Stop NVRAM watchdog thread
411     if (nvram_thread_active) {
412     nvram_thread_cancel = true;
413 gbeauche 1.3 wait_thread(nvram_thread);
414 gbeauche 1.1 }
415    
416 gbeauche 1.6 // Deinitialize everything
417     ExitAll();
418 gbeauche 1.1
419     // Delete SheepShaver globals
420     SheepMem::Exit();
421    
422     // Delete RAM area
423     if (ram_area_mapped)
424 gbeauche 1.13 vm_mac_release(RAMBase, RAMSize);
425 gbeauche 1.1
426     // Delete ROM area
427     if (rom_area_mapped)
428     vm_mac_release(ROM_BASE, ROM_AREA_SIZE);
429    
430     // Delete DR cache areas
431     if (dr_emulator_area_mapped)
432     vm_mac_release(DR_EMULATOR_BASE, DR_EMULATOR_SIZE);
433     if (dr_cache_area_mapped)
434     vm_mac_release(DR_CACHE_BASE, DR_CACHE_SIZE);
435    
436     // Delete Kernel Data area
437     kernel_data_exit();
438    
439     // Exit system routines
440     SysExit();
441    
442     // Exit preferences
443     PrefsExit();
444    
445 gbeauche 1.11 // Release win32 libraries
446     KernelExit();
447    
448 gbeauche 1.1 #ifdef ENABLE_MON
449     // Exit mon
450     mon_exit();
451     #endif
452    
453     exit(0);
454     }
455    
456    
457     /*
458     * Initialize Kernel Data segments
459     */
460    
461     static HANDLE kernel_handle; // Shared memory handle for Kernel Data
462     static DWORD allocation_granule; // Minimum size of allocateable are (64K)
463     static DWORD kernel_area_size; // Size of Kernel Data area
464    
465     static bool kernel_data_init(void)
466     {
467     char str[256];
468     SYSTEM_INFO si;
469     GetSystemInfo(&si);
470     allocation_granule = si.dwAllocationGranularity;
471     kernel_area_size = (KERNEL_AREA_SIZE + allocation_granule - 1) & -allocation_granule;
472    
473     char rcs[10];
474     LPVOID kernel_addr;
475     kernel_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, kernel_area_size, NULL);
476     if (kernel_handle == NULL) {
477     sprintf(rcs, "%d", GetLastError());
478     sprintf(str, GetString(STR_KD_SHMGET_ERR), rcs);
479     ErrorAlert(str);
480     return false;
481     }
482     kernel_addr = (LPVOID)Mac2HostAddr(KERNEL_DATA_BASE & -allocation_granule);
483     if (MapViewOfFileEx(kernel_handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kernel_area_size, kernel_addr) != kernel_addr) {
484     sprintf(rcs, "%d", GetLastError());
485     sprintf(str, GetString(STR_KD_SHMAT_ERR), rcs);
486     ErrorAlert(str);
487     return false;
488     }
489     kernel_addr = (LPVOID)Mac2HostAddr(KERNEL_DATA2_BASE & -allocation_granule);
490     if (MapViewOfFileEx(kernel_handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kernel_area_size, kernel_addr) != kernel_addr) {
491     sprintf(rcs, "%d", GetLastError());
492     sprintf(str, GetString(STR_KD2_SHMAT_ERR), rcs);
493     ErrorAlert(str);
494     return false;
495     }
496     return true;
497     }
498    
499    
500     /*
501     * Deallocate Kernel Data segments
502     */
503    
504     static void kernel_data_exit(void)
505     {
506     if (kernel_handle) {
507     UnmapViewOfFile(Mac2HostAddr(KERNEL_DATA_BASE & -allocation_granule));
508     UnmapViewOfFile(Mac2HostAddr(KERNEL_DATA2_BASE & -allocation_granule));
509     CloseHandle(kernel_handle);
510     }
511     }
512    
513    
514     /*
515     * Jump into Mac ROM, start 680x0 emulator
516     */
517    
518     void jump_to_rom(uint32 entry)
519     {
520     init_emul_ppc();
521     emul_ppc(entry);
522     }
523    
524    
525     /*
526     * Quit emulator (cause return from jump_to_rom)
527     */
528    
529     void QuitEmulator(void)
530     {
531     Quit();
532     }
533    
534    
535     /*
536     * Pause/resume emulator
537     */
538    
539     void PauseEmulator(void)
540     {
541 gbeauche 1.3 SuspendThread(emul_thread);
542 gbeauche 1.1 }
543    
544     void ResumeEmulator(void)
545     {
546 gbeauche 1.3 ResumeThread(emul_thread);
547 gbeauche 1.1 }
548    
549    
550     /*
551     * Dump 68k registers
552     */
553    
554     void Dump68kRegs(M68kRegisters *r)
555     {
556     // Display 68k registers
557     for (int i=0; i<8; i++) {
558     printf("d%d: %08x", i, r->d[i]);
559     if (i == 3 || i == 7)
560     printf("\n");
561     else
562     printf(", ");
563     }
564     for (int i=0; i<8; i++) {
565     printf("a%d: %08x", i, r->a[i]);
566     if (i == 3 || i == 7)
567     printf("\n");
568     else
569     printf(", ");
570     }
571     }
572    
573    
574     /*
575     * Make code executable
576     */
577    
578     void MakeExecutable(int dummy, uint32 start, uint32 length)
579     {
580     if ((start >= ROM_BASE) && (start < (ROM_BASE + ROM_SIZE)))
581     return;
582     FlushCodeCache(start, start + length);
583     }
584    
585    
586     /*
587     * NVRAM watchdog thread (saves NVRAM every minute)
588     */
589    
590     static void nvram_watchdog(void)
591     {
592     if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
593     memcpy(last_xpram, XPRAM, XPRAM_SIZE);
594     SaveXPRAM();
595     }
596     }
597    
598 gbeauche 1.3 static DWORD nvram_func(void *arg)
599 gbeauche 1.1 {
600     while (!nvram_thread_cancel) {
601     for (int i=0; i<60 && !nvram_thread_cancel; i++)
602     Delay_usec(999999); // Only wait 1 second so we quit promptly when nvram_thread_cancel becomes true
603     nvram_watchdog();
604     }
605     return 0;
606     }
607    
608    
609     /*
610     * 60Hz thread (really 60.15Hz)
611     */
612    
613 gbeauche 1.3 static DWORD tick_func(void *arg)
614 gbeauche 1.1 {
615     int tick_counter = 0;
616     uint64 start = GetTicks_usec();
617     int64 ticks = 0;
618     uint64 next = GetTicks_usec();
619    
620     while (!tick_thread_cancel) {
621    
622     // Wait
623     next += 16625;
624     int64 delay = next - GetTicks_usec();
625     if (delay > 0)
626     Delay_usec(delay);
627     else if (delay < -16625)
628     next = GetTicks_usec();
629     ticks++;
630    
631     // Pseudo Mac 1Hz interrupt, update local time
632     if (++tick_counter > 60) {
633     tick_counter = 0;
634     WriteMacInt32(0x20c, TimerDateTime());
635     }
636    
637     // Trigger 60Hz interrupt
638     if (ReadMacInt32(XLM_IRQ_NEST) == 0) {
639     SetInterruptFlag(INTFLAG_VIA);
640     TriggerInterrupt();
641     }
642     }
643    
644     uint64 end = GetTicks_usec();
645 gbeauche 1.13 D(bug("%lu ticks in %lu usec = %f ticks/sec\n", (unsigned long)ticks, (unsigned long)(end - start), ticks * 1000000.0 / (end - start)));
646 gbeauche 1.1 return 0;
647     }
648    
649    
650     /*
651     * Mutexes
652     */
653    
654     struct B2_mutex {
655 gbeauche 1.4 mutex_t m;
656 gbeauche 1.1 };
657    
658     B2_mutex *B2_create_mutex(void)
659     {
660     return new B2_mutex;
661     }
662    
663     void B2_lock_mutex(B2_mutex *mutex)
664     {
665 gbeauche 1.4 mutex->m.lock();
666 gbeauche 1.1 }
667    
668     void B2_unlock_mutex(B2_mutex *mutex)
669     {
670 gbeauche 1.4 mutex->m.unlock();
671 gbeauche 1.1 }
672    
673     void B2_delete_mutex(B2_mutex *mutex)
674     {
675     delete mutex;
676     }
677    
678    
679     /*
680     * Interrupt flags (must be handled atomically!)
681     */
682    
683     volatile uint32 InterruptFlags = 0;
684 gbeauche 1.4 static mutex_t intflags_mutex;
685 gbeauche 1.1
686     void SetInterruptFlag(uint32 flag)
687     {
688 gbeauche 1.4 intflags_mutex.lock();
689     InterruptFlags |= flag;
690     intflags_mutex.unlock();
691 gbeauche 1.1 }
692    
693     void ClearInterruptFlag(uint32 flag)
694     {
695 gbeauche 1.4 intflags_mutex.lock();
696     InterruptFlags &= ~flag;
697     intflags_mutex.unlock();
698 gbeauche 1.1 }
699    
700    
701     /*
702     * Disable interrupts
703     */
704    
705     void DisableInterrupt(void)
706     {
707     WriteMacInt32(XLM_IRQ_NEST, int32(ReadMacInt32(XLM_IRQ_NEST)) + 1);
708     }
709    
710    
711     /*
712     * Enable interrupts
713     */
714    
715     void EnableInterrupt(void)
716     {
717     WriteMacInt32(XLM_IRQ_NEST, int32(ReadMacInt32(XLM_IRQ_NEST)) - 1);
718     }
719    
720    
721     /*
722     * Helpers to share 32-bit addressable data with MacOS
723     */
724    
725     bool SheepMem::Init(void)
726     {
727     // Size of a native page
728 gbeauche 1.5 page_size = vm_get_page_size();
729 gbeauche 1.1
730     // Allocate SheepShaver globals
731     proc = base;
732     if (vm_mac_acquire(base, size) < 0)
733     return false;
734    
735     // Allocate page with all bits set to 0, right in the middle
736     // This is also used to catch undesired overlaps between proc and data areas
737     zero_page = proc + (size / 2);
738     Mac_memset(zero_page, 0, page_size);
739     if (vm_protect(Mac2HostAddr(zero_page), page_size, VM_PAGE_READ) < 0)
740     return false;
741    
742     // Allocate alternate stack for PowerPC interrupt routine
743     sig_stack = base + size;
744     if (vm_mac_acquire(sig_stack, SIG_STACK_SIZE) < 0)
745     return false;
746    
747     data = base + size;
748     return true;
749     }
750    
751     void SheepMem::Exit(void)
752     {
753     if (data) {
754     // Delete SheepShaver globals
755     vm_mac_release(base, size);
756    
757     // Delete alternate stack for PowerPC interrupt routine
758     vm_mac_release(sig_stack, SIG_STACK_SIZE);
759     }
760     }
761    
762    
763     /*
764     * Get the main window handle
765     */
766    
767     #ifdef USE_SDL_VIDEO
768     #include <SDL_syswm.h>
769 gbeauche 1.12 HWND GetMainWindowHandle(void)
770 gbeauche 1.1 {
771     SDL_SysWMinfo wmInfo;
772 gbeauche 1.12 SDL_VERSION(&wmInfo.version);
773 gbeauche 1.1 return SDL_GetWMInfo(&wmInfo) ? wmInfo.window : NULL;
774     }
775     #endif
776    
777    
778     /*
779     * Display alert
780     */
781    
782     static void display_alert(int title_id, const char *text, int flags)
783     {
784     HWND hMainWnd = GetMainWindowHandle();
785     MessageBox(hMainWnd, text, GetString(title_id), MB_OK | flags);
786     }
787    
788    
789     /*
790     * Display error alert
791     */
792    
793     void ErrorAlert(const char *text)
794     {
795     if (PrefsFindBool("nogui"))
796     return;
797    
798     VideoQuitFullScreen();
799     display_alert(STR_ERROR_ALERT_TITLE, text, MB_ICONSTOP);
800     }
801    
802    
803     /*
804     * Display warning alert
805     */
806    
807     void WarningAlert(const char *text)
808     {
809     if (PrefsFindBool("nogui"))
810     return;
811    
812     display_alert(STR_WARNING_ALERT_TITLE, text, MB_ICONINFORMATION);
813     }
814    
815    
816     /*
817     * Display choice alert
818     */
819    
820     bool ChoiceAlert(const char *text, const char *pos, const char *neg)
821     {
822     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
823     return false; //!!
824     }