ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Windows/main_windows.cpp
Revision: 1.11
Committed: 2005-11-27T22:29:32Z (19 years ago) by gbeauche
Branch: MAIN
Changes since 1.10: +7 -0 lines
Log Message:
Ethernet and Serial support (merge from Basilisk II tree)

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