ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/main_windows.cpp
Revision: 1.6
Committed: 2005-03-19T19:01:49Z (19 years, 2 months ago) by gbeauche
Branch: MAIN
Changes since 1.5: +5 -0 lines
Log Message:
Check that drivers are installed (e.g. CD-ROM driver)

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * main_windows.cpp - Startup code for Windows
3     *
4 gbeauche 1.5 * Basilisk II (C) 1997-2005 Christian Bauer
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 "sysdeps.h"
22    
23     #include <stdio.h>
24     #include <stdlib.h>
25     #include <signal.h>
26     #include <errno.h>
27    
28     #include <SDL.h>
29     #include <SDL_mutex.h>
30     #include <SDL_thread.h>
31    
32     #include <string>
33     using std::string;
34    
35     #include "cpu_emulation.h"
36     #include "sys.h"
37     #include "rom_patches.h"
38     #include "xpram.h"
39     #include "timer.h"
40     #include "video.h"
41 gbeauche 1.3 #include "cdrom.h"
42 gbeauche 1.1 #include "emul_op.h"
43     #include "prefs.h"
44     #include "prefs_editor.h"
45     #include "macos_util.h"
46     #include "user_strings.h"
47     #include "version.h"
48     #include "main.h"
49     #include "vm_alloc.h"
50     #include "sigsegv.h"
51 gbeauche 1.6 #include "util_windows.h"
52 gbeauche 1.4 #include "kernel_windows.h"
53 gbeauche 1.1
54     #if USE_JIT
55     extern void flush_icache_range(uint32 start, uint32 size); // from compemu_support.cpp
56     #endif
57    
58     #ifdef ENABLE_MON
59     # include "mon.h"
60     #endif
61    
62     #define DEBUG 0
63     #include "debug.h"
64    
65    
66     // Constants
67     const char ROM_FILE_NAME[] = "ROM";
68     const int SCRATCH_MEM_SIZE = 0x10000; // Size of scratch memory area
69    
70    
71     // CPU and FPU type, addressing mode
72     int CPUType;
73     bool CPUIs68060;
74     int FPUType;
75     bool TwentyFourBitAddressing;
76     bool ThirtyThreeBitAddressing = false;
77    
78    
79     // Global variables
80     static uint8 last_xpram[XPRAM_SIZE]; // Buffer for monitoring XPRAM changes
81    
82     static bool xpram_thread_active = false; // Flag: XPRAM watchdog installed
83     static volatile bool xpram_thread_cancel = false; // Flag: Cancel XPRAM thread
84     static SDL_Thread *xpram_thread = NULL; // XPRAM watchdog
85    
86     static bool tick_thread_active = false; // Flag: 60Hz thread installed
87     static volatile bool tick_thread_cancel = false; // Flag: Cancel 60Hz thread
88     static SDL_Thread *tick_thread; // 60Hz thread
89    
90     static SDL_mutex *intflag_lock = NULL; // Mutex to protect InterruptFlags
91     #define LOCK_INTFLAGS SDL_LockMutex(intflag_lock)
92     #define UNLOCK_INTFLAGS SDL_UnlockMutex(intflag_lock)
93    
94 gbeauche 1.4 DWORD win_os; // Windows OS id
95     DWORD win_os_major; // Windows OS version major
96    
97 gbeauche 1.1 #if USE_SCRATCHMEM_SUBTERFUGE
98     uint8 *ScratchMem = NULL; // Scratch memory for Mac ROM writes
99     #endif
100    
101     #if REAL_ADDRESSING
102     static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped
103     #endif
104    
105    
106     // Prototypes
107     static int xpram_func(void *arg);
108     static int tick_func(void *arg);
109     static void one_tick(...);
110    
111    
112     /*
113     * Ersatz functions
114     */
115    
116     extern "C" {
117    
118     #ifndef HAVE_STRDUP
119     char *strdup(const char *s)
120     {
121     char *n = (char *)malloc(strlen(s) + 1);
122     strcpy(n, s);
123     return n;
124     }
125     #endif
126    
127     }
128    
129    
130     /*
131     * Map memory that can be accessed from the Mac side
132     */
133    
134     void *vm_acquire_mac(size_t size)
135     {
136     void *m = vm_acquire(size, VM_MAP_DEFAULT | VM_MAP_33BIT);
137     if (m == NULL) {
138     ThirtyThreeBitAddressing = false;
139     m = vm_acquire(size);
140     }
141     return m;
142     }
143    
144    
145     /*
146     * SIGSEGV handler
147     */
148    
149     static sigsegv_return_t sigsegv_handler(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
150     {
151     #if ENABLE_VOSF
152     // Handle screen fault
153     extern bool Screen_fault_handler(sigsegv_address_t, sigsegv_address_t);
154     if (Screen_fault_handler(fault_address, fault_instruction))
155     return SIGSEGV_RETURN_SUCCESS;
156     #endif
157    
158     #ifdef HAVE_SIGSEGV_SKIP_INSTRUCTION
159     // Ignore writes to ROM
160     if (((uintptr)fault_address - (uintptr)ROMBaseHost) < ROMSize)
161     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
162    
163     // Ignore all other faults, if requested
164     if (PrefsFindBool("ignoresegv"))
165     return SIGSEGV_RETURN_SKIP_INSTRUCTION;
166     #endif
167    
168     return SIGSEGV_RETURN_FAILURE;
169     }
170    
171     /*
172     * Dump state when everything went wrong after a SEGV
173     */
174    
175     static void sigsegv_dump_state(sigsegv_address_t fault_address, sigsegv_address_t fault_instruction)
176     {
177     fprintf(stderr, "Caught SIGSEGV at address %p", fault_address);
178     if (fault_instruction != SIGSEGV_INVALID_PC)
179     fprintf(stderr, " [IP=%p]", fault_instruction);
180     fprintf(stderr, "\n");
181     uaecptr nextpc;
182     extern void m68k_dumpstate(uaecptr *nextpc);
183     m68k_dumpstate(&nextpc);
184     #if USE_JIT && JIT_DEBUG
185     extern void compiler_dumpstate(void);
186     compiler_dumpstate();
187     #endif
188     VideoQuitFullScreen();
189     #ifdef ENABLE_MON
190     char *arg[4] = {"mon", "-m", "-r", NULL};
191     mon(3, arg);
192     QuitEmulator();
193     #endif
194     }
195    
196    
197     /*
198     * Main program
199     */
200    
201     static void usage(const char *prg_name)
202     {
203     printf(
204     "Usage: %s [OPTION...]\n"
205     "\nUnix options:\n"
206     " --config FILE\n read/write configuration from/to FILE\n"
207     " --display STRING\n X display to use\n"
208     " --break ADDRESS\n set ROM breakpoint\n"
209     " --rominfo\n dump ROM information\n", prg_name
210     );
211     LoadPrefs(); // read the prefs file so PrefsPrintUsage() will print the correct default values
212     PrefsPrintUsage();
213     exit(0);
214     }
215    
216     int main(int argc, char **argv)
217     {
218     char str[256];
219 gbeauche 1.3 bool cd_boot = false;
220 gbeauche 1.1
221     // Initialize variables
222     RAMBaseHost = NULL;
223     ROMBaseHost = NULL;
224     srand(time(NULL));
225     tzset();
226    
227     // Print some info
228     printf(GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
229     printf(" %s\n", GetString(STR_ABOUT_TEXT2));
230    
231     // Parse command line arguments
232     for (int i=1; i<argc; i++) {
233     if (strcmp(argv[i], "--help") == 0) {
234     usage(argv[0]);
235     } else if (strcmp(argv[i], "--break") == 0) {
236     argv[i++] = NULL;
237     if (i < argc) {
238     ROMBreakpoint = strtol(argv[i], NULL, 0);
239     argv[i] = NULL;
240     }
241     } else if (strcmp(argv[i], "--config") == 0) {
242     argv[i++] = NULL;
243     if (i < argc) {
244     extern string UserPrefsPath; // from prefs_unix.cpp
245     UserPrefsPath = argv[i];
246     argv[i] = NULL;
247     }
248     } else if (strcmp(argv[i], "--rominfo") == 0) {
249     argv[i] = NULL;
250     PrintROMInfo = true;
251 gbeauche 1.3 } else if (strcmp(argv[i], "--cdboot") == 0) {
252     argv[i] = NULL;
253     cd_boot = true;
254 gbeauche 1.1 }
255     }
256    
257     // Remove processed arguments
258     for (int i=1; i<argc; i++) {
259     int k;
260     for (k=i; k<argc; k++)
261     if (argv[k] != NULL)
262     break;
263     if (k > i) {
264     k -= i;
265     for (int j=i+k; j<argc; j++)
266     argv[j-k] = argv[j];
267     argc -= k;
268     }
269     }
270    
271     // Read preferences
272     PrefsInit(argc, argv);
273    
274 gbeauche 1.3 // Boot MacOS from CD-ROM?
275     if (cd_boot)
276     PrefsReplaceInt32("bootdriver", CDROMRefNum);
277    
278 gbeauche 1.1 // Any command line arguments left?
279     for (int i=1; i<argc; i++) {
280     if (argv[i][0] == '-') {
281     fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
282     usage(argv[0]);
283     }
284     }
285    
286 gbeauche 1.2 // Check we are using a Windows NT kernel >= 4.0
287     OSVERSIONINFO osvi;
288     ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
289     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
290 gbeauche 1.4 if (!GetVersionEx(&osvi)) {
291     ErrorAlert("Could not determine OS type");
292     QuitEmulator();
293     }
294     win_os = osvi.dwPlatformId;
295     win_os_major = osvi.dwMajorVersion;
296     if (win_os != VER_PLATFORM_WIN32_NT || win_os_major < 4) {
297 gbeauche 1.2 ErrorAlert(STR_NO_WIN32_NT_4);
298     QuitEmulator();
299     }
300    
301 gbeauche 1.6 // Check that drivers are installed
302     if (!check_drivers())
303     QuitEmulator();
304    
305 gbeauche 1.4 // Load win32 libraries
306     KernelInit();
307    
308 gbeauche 1.1 // Initialize SDL system
309     int sdl_flags = 0;
310     #ifdef USE_SDL_VIDEO
311     sdl_flags |= SDL_INIT_VIDEO;
312     #endif
313     #ifdef USE_SDL_AUDIO
314     sdl_flags |= SDL_INIT_AUDIO;
315     #endif
316     assert(sdl_flags != 0);
317     if (SDL_Init(sdl_flags) == -1) {
318     char str[256];
319     sprintf(str, "Could not initialize SDL: %s.\n", SDL_GetError());
320     ErrorAlert(str);
321     QuitEmulator();
322     }
323     atexit(SDL_Quit);
324    
325     // Init system routines
326     SysInit();
327    
328     // Show preferences editor
329     if (!PrefsFindBool("nogui"))
330     if (!PrefsEditor())
331     QuitEmulator();
332    
333     // Install the handler for SIGSEGV
334     if (!sigsegv_install_handler(sigsegv_handler)) {
335     sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGSEGV", strerror(errno));
336     ErrorAlert(str);
337     QuitEmulator();
338     }
339    
340     // Register dump state function when we got mad after a segfault
341     sigsegv_set_dump_state(sigsegv_dump_state);
342    
343     // Read RAM size
344     RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary
345     if (RAMSize < 1024*1024) {
346     WarningAlert(GetString(STR_SMALL_RAM_WARN));
347     RAMSize = 1024*1024;
348     }
349    
350     // Initialize VM system
351     vm_init();
352    
353     // Create areas for Mac RAM and ROM
354     #ifdef USE_33BIT_ADDRESSING
355     // Speculatively enables 33-bit addressing
356     ThirtyThreeBitAddressing = true;
357     #endif
358     RAMBaseHost = (uint8 *)vm_acquire_mac(RAMSize);
359     ROMBaseHost = (uint8 *)vm_acquire_mac(0x100000);
360     if (RAMBaseHost == VM_MAP_FAILED || ROMBaseHost == VM_MAP_FAILED) {
361     ErrorAlert(STR_NO_MEM_ERR);
362     QuitEmulator();
363     }
364    
365     #if USE_SCRATCHMEM_SUBTERFUGE
366     // Allocate scratch memory
367     ScratchMem = (uint8 *)vm_acquire(SCRATCH_MEM_SIZE);
368     if (ScratchMem == VM_MAP_FAILED) {
369     ErrorAlert(STR_NO_MEM_ERR);
370     QuitEmulator();
371     }
372     ScratchMem += SCRATCH_MEM_SIZE/2; // ScratchMem points to middle of block
373     #endif
374    
375     #if DIRECT_ADDRESSING
376     // RAMBaseMac shall always be zero
377     MEMBaseDiff = (uintptr)RAMBaseHost;
378     RAMBaseMac = 0;
379     ROMBaseMac = Host2MacAddr(ROMBaseHost);
380     #endif
381     D(bug("Mac RAM starts at %p (%08x)\n", RAMBaseHost, RAMBaseMac));
382     D(bug("Mac ROM starts at %p (%08x)\n", ROMBaseHost, ROMBaseMac));
383    
384     // Get rom file path from preferences
385     const char *rom_path = PrefsFindString("rom");
386    
387     // Load Mac ROM
388     HANDLE rom_fh = CreateFile(rom_path ? rom_path : ROM_FILE_NAME,
389     GENERIC_READ,
390     0, NULL,
391     OPEN_EXISTING,
392     FILE_ATTRIBUTE_NORMAL,
393     NULL);
394     if (rom_fh == INVALID_HANDLE_VALUE) {
395     ErrorAlert(STR_NO_ROM_FILE_ERR);
396     QuitEmulator();
397     }
398     printf(GetString(STR_READING_ROM_FILE));
399     ROMSize = GetFileSize(rom_fh, NULL);
400     if (ROMSize != 64*1024 && ROMSize != 128*1024 && ROMSize != 256*1024 && ROMSize != 512*1024 && ROMSize != 1024*1024) {
401     ErrorAlert(STR_ROM_SIZE_ERR);
402     CloseHandle(rom_fh);
403     QuitEmulator();
404     }
405     DWORD bytes_read;
406     if (ReadFile(rom_fh, ROMBaseHost, ROMSize, &bytes_read, NULL) == 0 || bytes_read != ROMSize) {
407     ErrorAlert(STR_ROM_FILE_READ_ERR);
408     CloseHandle(rom_fh);
409     QuitEmulator();
410     }
411    
412     // Initialize native timers
413     timer_init();
414    
415     // Initialize everything
416     if (!InitAll())
417     QuitEmulator();
418     D(bug("Initialization complete\n"));
419    
420     // SDL threads available, start 60Hz thread
421     tick_thread_active = ((tick_thread = SDL_CreateThread(tick_func, NULL)) != NULL);
422     if (!tick_thread_active) {
423     sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno));
424     ErrorAlert(str);
425     QuitEmulator();
426     }
427     D(bug("60Hz thread started\n"));
428    
429     // Start XPRAM watchdog thread
430     memcpy(last_xpram, XPRAM, XPRAM_SIZE);
431     xpram_thread_active = ((xpram_thread = SDL_CreateThread(xpram_func, NULL)) != NULL);
432     D(bug("XPRAM thread started\n"));
433    
434     // Start 68k and jump to ROM boot routine
435     D(bug("Starting emulation...\n"));
436     Start680x0();
437    
438     QuitEmulator();
439     return 0;
440     }
441    
442    
443     /*
444     * Quit emulator
445     */
446    
447     void QuitEmulator(void)
448     {
449     D(bug("QuitEmulator\n"));
450    
451     // Exit 680x0 emulation
452     Exit680x0();
453    
454     // Stop 60Hz thread
455     if (tick_thread_active) {
456     tick_thread_cancel = true;
457     SDL_WaitThread(tick_thread, NULL);
458     }
459    
460     // Stop XPRAM watchdog thread
461     if (xpram_thread_active) {
462     xpram_thread_cancel = true;
463     SDL_WaitThread(xpram_thread, NULL);
464     }
465    
466     // Deinitialize everything
467     ExitAll();
468    
469     // Free ROM/RAM areas
470     if (RAMBaseHost != VM_MAP_FAILED) {
471     vm_release(RAMBaseHost, RAMSize);
472     RAMBaseHost = NULL;
473     }
474     if (ROMBaseHost != VM_MAP_FAILED) {
475     vm_release(ROMBaseHost, 0x100000);
476     ROMBaseHost = NULL;
477     }
478    
479     #if USE_SCRATCHMEM_SUBTERFUGE
480     // Delete scratch memory area
481     if (ScratchMem != (uint8 *)VM_MAP_FAILED) {
482     vm_release((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE);
483     ScratchMem = NULL;
484     }
485     #endif
486    
487     // Exit VM wrappers
488     vm_exit();
489    
490     // Exit system routines
491     SysExit();
492    
493     // Exit preferences
494     PrefsExit();
495    
496 gbeauche 1.4 // Release win32 libraries
497     KernelExit();
498    
499 gbeauche 1.1 exit(0);
500     }
501    
502    
503     /*
504     * Code was patched, flush caches if neccessary (i.e. when using a real 680x0
505     * or a dynamically recompiling emulator)
506     */
507    
508     void FlushCodeCache(void *start, uint32 size)
509     {
510     #if USE_JIT
511     if (UseJIT)
512     flush_icache_range((uintptr)start, size);
513     #endif
514     }
515    
516    
517     /*
518     * Mutexes
519     */
520    
521     struct B2_mutex {
522     B2_mutex() { m = SDL_CreateMutex(); }
523     ~B2_mutex() { if (m) SDL_DestroyMutex(m); }
524     SDL_mutex *m;
525     };
526    
527     B2_mutex *B2_create_mutex(void)
528     {
529     return new B2_mutex;
530     }
531    
532     void B2_lock_mutex(B2_mutex *mutex)
533     {
534     if (mutex)
535     SDL_LockMutex(mutex->m);
536     }
537    
538     void B2_unlock_mutex(B2_mutex *mutex)
539     {
540     if (mutex)
541     SDL_UnlockMutex(mutex->m);
542     }
543    
544     void B2_delete_mutex(B2_mutex *mutex)
545     {
546     delete mutex;
547     }
548    
549    
550     /*
551     * Interrupt flags (must be handled atomically!)
552     */
553    
554     uint32 InterruptFlags = 0;
555    
556     void SetInterruptFlag(uint32 flag)
557     {
558     LOCK_INTFLAGS;
559     InterruptFlags |= flag;
560     UNLOCK_INTFLAGS;
561     }
562    
563     void ClearInterruptFlag(uint32 flag)
564     {
565     LOCK_INTFLAGS;
566     InterruptFlags &= ~flag;
567     UNLOCK_INTFLAGS;
568     }
569    
570    
571     /*
572     * XPRAM watchdog thread (saves XPRAM every minute)
573     */
574    
575     static void xpram_watchdog(void)
576     {
577     if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
578     memcpy(last_xpram, XPRAM, XPRAM_SIZE);
579     SaveXPRAM();
580     }
581     }
582    
583     static int xpram_func(void *arg)
584     {
585     while (!xpram_thread_cancel) {
586     for (int i=0; i<60 && !xpram_thread_cancel; i++)
587     Delay_usec(999999); // Only wait 1 second so we quit promptly when xpram_thread_cancel becomes true
588     xpram_watchdog();
589     }
590     return 0;
591     }
592    
593    
594     /*
595     * 60Hz thread (really 60.15Hz)
596     */
597    
598     static void one_second(void)
599     {
600     // Pseudo Mac 1Hz interrupt, update local time
601     WriteMacInt32(0x20c, TimerDateTime());
602    
603     SetInterruptFlag(INTFLAG_1HZ);
604     TriggerInterrupt();
605     }
606    
607     static void one_tick(...)
608     {
609     static int tick_counter = 0;
610     if (++tick_counter > 60) {
611     tick_counter = 0;
612     one_second();
613     }
614    
615     // Trigger 60Hz interrupt
616     if (ROMVersion != ROM_VERSION_CLASSIC || HasMacStarted()) {
617     SetInterruptFlag(INTFLAG_60HZ);
618     TriggerInterrupt();
619     }
620     }
621    
622     static int tick_func(void *arg)
623     {
624     uint64 start = GetTicks_usec();
625     int64 ticks = 0;
626     uint64 next = GetTicks_usec();
627     while (!tick_thread_cancel) {
628     one_tick();
629     next += 16625;
630     int64 delay = next - GetTicks_usec();
631     if (delay > 0)
632     Delay_usec(delay);
633     else if (delay < -16625)
634     next = GetTicks_usec();
635     ticks++;
636     }
637     uint64 end = GetTicks_usec();
638     D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
639     return 0;
640     }
641    
642    
643     /*
644 gbeauche 1.2 * Get the main window handle
645 gbeauche 1.1 */
646    
647 gbeauche 1.2 #ifdef USE_SDL_VIDEO
648     #include <SDL_syswm.h>
649     static HWND GetMainWindowHandle(void)
650 gbeauche 1.1 {
651 gbeauche 1.2 SDL_SysWMinfo wmInfo;
652     wmInfo.version.major = SDL_MAJOR_VERSION;
653     wmInfo.version.minor = SDL_MINOR_VERSION;
654     wmInfo.version.patch = SDL_PATCHLEVEL;
655     return SDL_GetWMInfo(&wmInfo) ? wmInfo.window : NULL;
656 gbeauche 1.1 }
657 gbeauche 1.2 #endif
658 gbeauche 1.1
659    
660 gbeauche 1.2 /*
661     * Display alert
662     */
663    
664     static void display_alert(int title_id, const char *text, int flags)
665 gbeauche 1.1 {
666 gbeauche 1.2 HWND hMainWnd = GetMainWindowHandle();
667     MessageBox(hMainWnd, text, GetString(title_id), MB_OK | flags);
668 gbeauche 1.1 }
669    
670    
671     /*
672     * Display error alert
673     */
674    
675     void ErrorAlert(const char *text)
676     {
677 gbeauche 1.2 if (PrefsFindBool("nogui"))
678 gbeauche 1.1 return;
679 gbeauche 1.2
680 gbeauche 1.1 VideoQuitFullScreen();
681 gbeauche 1.2 display_alert(STR_ERROR_ALERT_TITLE, text, MB_ICONSTOP);
682 gbeauche 1.1 }
683    
684    
685     /*
686     * Display warning alert
687     */
688    
689     void WarningAlert(const char *text)
690     {
691 gbeauche 1.2 if (PrefsFindBool("nogui"))
692 gbeauche 1.1 return;
693 gbeauche 1.2
694     display_alert(STR_WARNING_ALERT_TITLE, text, MB_ICONINFORMATION);
695 gbeauche 1.1 }
696    
697    
698     /*
699     * Display choice alert
700     */
701    
702     bool ChoiceAlert(const char *text, const char *pos, const char *neg)
703     {
704     printf(GetString(STR_SHELL_WARNING_PREFIX), text);
705     return false; //!!
706     }