ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/main_windows.cpp
Revision: 1.7
Committed: 2005-11-22T06:26:35Z (18 years, 6 months ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-17
Changes since 1.6: +4 -0 lines
Log Message:
Windows HACK: default to the DIB driver as it looks smoother to me and
doesn't require locking the surfaces, which probably the cause of apparent
slowness when using the DirectX backend. This needs to be investigated more

File Contents

# Content
1 /*
2 * main_windows.cpp - Startup code for Windows
3 *
4 * Basilisk II (C) 1997-2005 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
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 #include "cdrom.h"
42 #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 #include "util_windows.h"
52 #include "kernel_windows.h"
53
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 DWORD win_os; // Windows OS id
95 DWORD win_os_major; // Windows OS version major
96
97 #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 bool cd_boot = false;
220
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 } else if (strcmp(argv[i], "--cdboot") == 0) {
252 argv[i] = NULL;
253 cd_boot = true;
254 }
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 // Boot MacOS from CD-ROM?
275 if (cd_boot)
276 PrefsReplaceInt32("bootdriver", CDROMRefNum);
277
278 // 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 // Check we are using a Windows NT kernel >= 4.0
287 OSVERSIONINFO osvi;
288 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
289 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
290 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 ErrorAlert(STR_NO_WIN32_NT_4);
298 QuitEmulator();
299 }
300
301 // Check that drivers are installed
302 if (!check_drivers())
303 QuitEmulator();
304
305 // Load win32 libraries
306 KernelInit();
307
308 // FIXME: default to DIB driver
309 if (getenv("SDL_VIDEODRIVER") == NULL)
310 putenv("SDL_VIDEODRIVER=windib");
311
312 // Initialize SDL system
313 int sdl_flags = 0;
314 #ifdef USE_SDL_VIDEO
315 sdl_flags |= SDL_INIT_VIDEO;
316 #endif
317 #ifdef USE_SDL_AUDIO
318 sdl_flags |= SDL_INIT_AUDIO;
319 #endif
320 assert(sdl_flags != 0);
321 if (SDL_Init(sdl_flags) == -1) {
322 char str[256];
323 sprintf(str, "Could not initialize SDL: %s.\n", SDL_GetError());
324 ErrorAlert(str);
325 QuitEmulator();
326 }
327 atexit(SDL_Quit);
328
329 // Init system routines
330 SysInit();
331
332 // Show preferences editor
333 if (!PrefsFindBool("nogui"))
334 if (!PrefsEditor())
335 QuitEmulator();
336
337 // Install the handler for SIGSEGV
338 if (!sigsegv_install_handler(sigsegv_handler)) {
339 sprintf(str, GetString(STR_SIG_INSTALL_ERR), "SIGSEGV", strerror(errno));
340 ErrorAlert(str);
341 QuitEmulator();
342 }
343
344 // Register dump state function when we got mad after a segfault
345 sigsegv_set_dump_state(sigsegv_dump_state);
346
347 // Read RAM size
348 RAMSize = PrefsFindInt32("ramsize") & 0xfff00000; // Round down to 1MB boundary
349 if (RAMSize < 1024*1024) {
350 WarningAlert(GetString(STR_SMALL_RAM_WARN));
351 RAMSize = 1024*1024;
352 }
353
354 // Initialize VM system
355 vm_init();
356
357 // Create areas for Mac RAM and ROM
358 #ifdef USE_33BIT_ADDRESSING
359 // Speculatively enables 33-bit addressing
360 ThirtyThreeBitAddressing = true;
361 #endif
362 RAMBaseHost = (uint8 *)vm_acquire_mac(RAMSize);
363 ROMBaseHost = (uint8 *)vm_acquire_mac(0x100000);
364 if (RAMBaseHost == VM_MAP_FAILED || ROMBaseHost == VM_MAP_FAILED) {
365 ErrorAlert(STR_NO_MEM_ERR);
366 QuitEmulator();
367 }
368
369 #if USE_SCRATCHMEM_SUBTERFUGE
370 // Allocate scratch memory
371 ScratchMem = (uint8 *)vm_acquire(SCRATCH_MEM_SIZE);
372 if (ScratchMem == VM_MAP_FAILED) {
373 ErrorAlert(STR_NO_MEM_ERR);
374 QuitEmulator();
375 }
376 ScratchMem += SCRATCH_MEM_SIZE/2; // ScratchMem points to middle of block
377 #endif
378
379 #if DIRECT_ADDRESSING
380 // RAMBaseMac shall always be zero
381 MEMBaseDiff = (uintptr)RAMBaseHost;
382 RAMBaseMac = 0;
383 ROMBaseMac = Host2MacAddr(ROMBaseHost);
384 #endif
385 D(bug("Mac RAM starts at %p (%08x)\n", RAMBaseHost, RAMBaseMac));
386 D(bug("Mac ROM starts at %p (%08x)\n", ROMBaseHost, ROMBaseMac));
387
388 // Get rom file path from preferences
389 const char *rom_path = PrefsFindString("rom");
390
391 // Load Mac ROM
392 HANDLE rom_fh = CreateFile(rom_path ? rom_path : ROM_FILE_NAME,
393 GENERIC_READ,
394 0, NULL,
395 OPEN_EXISTING,
396 FILE_ATTRIBUTE_NORMAL,
397 NULL);
398 if (rom_fh == INVALID_HANDLE_VALUE) {
399 ErrorAlert(STR_NO_ROM_FILE_ERR);
400 QuitEmulator();
401 }
402 printf(GetString(STR_READING_ROM_FILE));
403 ROMSize = GetFileSize(rom_fh, NULL);
404 if (ROMSize != 64*1024 && ROMSize != 128*1024 && ROMSize != 256*1024 && ROMSize != 512*1024 && ROMSize != 1024*1024) {
405 ErrorAlert(STR_ROM_SIZE_ERR);
406 CloseHandle(rom_fh);
407 QuitEmulator();
408 }
409 DWORD bytes_read;
410 if (ReadFile(rom_fh, ROMBaseHost, ROMSize, &bytes_read, NULL) == 0 || bytes_read != ROMSize) {
411 ErrorAlert(STR_ROM_FILE_READ_ERR);
412 CloseHandle(rom_fh);
413 QuitEmulator();
414 }
415
416 // Initialize native timers
417 timer_init();
418
419 // Initialize everything
420 if (!InitAll())
421 QuitEmulator();
422 D(bug("Initialization complete\n"));
423
424 // SDL threads available, start 60Hz thread
425 tick_thread_active = ((tick_thread = SDL_CreateThread(tick_func, NULL)) != NULL);
426 if (!tick_thread_active) {
427 sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno));
428 ErrorAlert(str);
429 QuitEmulator();
430 }
431 D(bug("60Hz thread started\n"));
432
433 // Start XPRAM watchdog thread
434 memcpy(last_xpram, XPRAM, XPRAM_SIZE);
435 xpram_thread_active = ((xpram_thread = SDL_CreateThread(xpram_func, NULL)) != NULL);
436 D(bug("XPRAM thread started\n"));
437
438 // Start 68k and jump to ROM boot routine
439 D(bug("Starting emulation...\n"));
440 Start680x0();
441
442 QuitEmulator();
443 return 0;
444 }
445
446
447 /*
448 * Quit emulator
449 */
450
451 void QuitEmulator(void)
452 {
453 D(bug("QuitEmulator\n"));
454
455 // Exit 680x0 emulation
456 Exit680x0();
457
458 // Stop 60Hz thread
459 if (tick_thread_active) {
460 tick_thread_cancel = true;
461 SDL_WaitThread(tick_thread, NULL);
462 }
463
464 // Stop XPRAM watchdog thread
465 if (xpram_thread_active) {
466 xpram_thread_cancel = true;
467 SDL_WaitThread(xpram_thread, NULL);
468 }
469
470 // Deinitialize everything
471 ExitAll();
472
473 // Free ROM/RAM areas
474 if (RAMBaseHost != VM_MAP_FAILED) {
475 vm_release(RAMBaseHost, RAMSize);
476 RAMBaseHost = NULL;
477 }
478 if (ROMBaseHost != VM_MAP_FAILED) {
479 vm_release(ROMBaseHost, 0x100000);
480 ROMBaseHost = NULL;
481 }
482
483 #if USE_SCRATCHMEM_SUBTERFUGE
484 // Delete scratch memory area
485 if (ScratchMem != (uint8 *)VM_MAP_FAILED) {
486 vm_release((void *)(ScratchMem - SCRATCH_MEM_SIZE/2), SCRATCH_MEM_SIZE);
487 ScratchMem = NULL;
488 }
489 #endif
490
491 // Exit VM wrappers
492 vm_exit();
493
494 // Exit system routines
495 SysExit();
496
497 // Exit preferences
498 PrefsExit();
499
500 // Release win32 libraries
501 KernelExit();
502
503 exit(0);
504 }
505
506
507 /*
508 * Code was patched, flush caches if neccessary (i.e. when using a real 680x0
509 * or a dynamically recompiling emulator)
510 */
511
512 void FlushCodeCache(void *start, uint32 size)
513 {
514 #if USE_JIT
515 if (UseJIT)
516 flush_icache_range((uintptr)start, size);
517 #endif
518 }
519
520
521 /*
522 * Mutexes
523 */
524
525 struct B2_mutex {
526 B2_mutex() { m = SDL_CreateMutex(); }
527 ~B2_mutex() { if (m) SDL_DestroyMutex(m); }
528 SDL_mutex *m;
529 };
530
531 B2_mutex *B2_create_mutex(void)
532 {
533 return new B2_mutex;
534 }
535
536 void B2_lock_mutex(B2_mutex *mutex)
537 {
538 if (mutex)
539 SDL_LockMutex(mutex->m);
540 }
541
542 void B2_unlock_mutex(B2_mutex *mutex)
543 {
544 if (mutex)
545 SDL_UnlockMutex(mutex->m);
546 }
547
548 void B2_delete_mutex(B2_mutex *mutex)
549 {
550 delete mutex;
551 }
552
553
554 /*
555 * Interrupt flags (must be handled atomically!)
556 */
557
558 uint32 InterruptFlags = 0;
559
560 void SetInterruptFlag(uint32 flag)
561 {
562 LOCK_INTFLAGS;
563 InterruptFlags |= flag;
564 UNLOCK_INTFLAGS;
565 }
566
567 void ClearInterruptFlag(uint32 flag)
568 {
569 LOCK_INTFLAGS;
570 InterruptFlags &= ~flag;
571 UNLOCK_INTFLAGS;
572 }
573
574
575 /*
576 * XPRAM watchdog thread (saves XPRAM every minute)
577 */
578
579 static void xpram_watchdog(void)
580 {
581 if (memcmp(last_xpram, XPRAM, XPRAM_SIZE)) {
582 memcpy(last_xpram, XPRAM, XPRAM_SIZE);
583 SaveXPRAM();
584 }
585 }
586
587 static int xpram_func(void *arg)
588 {
589 while (!xpram_thread_cancel) {
590 for (int i=0; i<60 && !xpram_thread_cancel; i++)
591 Delay_usec(999999); // Only wait 1 second so we quit promptly when xpram_thread_cancel becomes true
592 xpram_watchdog();
593 }
594 return 0;
595 }
596
597
598 /*
599 * 60Hz thread (really 60.15Hz)
600 */
601
602 static void one_second(void)
603 {
604 // Pseudo Mac 1Hz interrupt, update local time
605 WriteMacInt32(0x20c, TimerDateTime());
606
607 SetInterruptFlag(INTFLAG_1HZ);
608 TriggerInterrupt();
609 }
610
611 static void one_tick(...)
612 {
613 static int tick_counter = 0;
614 if (++tick_counter > 60) {
615 tick_counter = 0;
616 one_second();
617 }
618
619 // Trigger 60Hz interrupt
620 if (ROMVersion != ROM_VERSION_CLASSIC || HasMacStarted()) {
621 SetInterruptFlag(INTFLAG_60HZ);
622 TriggerInterrupt();
623 }
624 }
625
626 static int tick_func(void *arg)
627 {
628 uint64 start = GetTicks_usec();
629 int64 ticks = 0;
630 uint64 next = GetTicks_usec();
631 while (!tick_thread_cancel) {
632 one_tick();
633 next += 16625;
634 int64 delay = next - GetTicks_usec();
635 if (delay > 0)
636 Delay_usec(delay);
637 else if (delay < -16625)
638 next = GetTicks_usec();
639 ticks++;
640 }
641 uint64 end = GetTicks_usec();
642 D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
643 return 0;
644 }
645
646
647 /*
648 * Get the main window handle
649 */
650
651 #ifdef USE_SDL_VIDEO
652 #include <SDL_syswm.h>
653 static HWND GetMainWindowHandle(void)
654 {
655 SDL_SysWMinfo wmInfo;
656 wmInfo.version.major = SDL_MAJOR_VERSION;
657 wmInfo.version.minor = SDL_MINOR_VERSION;
658 wmInfo.version.patch = SDL_PATCHLEVEL;
659 return SDL_GetWMInfo(&wmInfo) ? wmInfo.window : NULL;
660 }
661 #endif
662
663
664 /*
665 * Display alert
666 */
667
668 static void display_alert(int title_id, const char *text, int flags)
669 {
670 HWND hMainWnd = GetMainWindowHandle();
671 MessageBox(hMainWnd, text, GetString(title_id), MB_OK | flags);
672 }
673
674
675 /*
676 * Display error alert
677 */
678
679 void ErrorAlert(const char *text)
680 {
681 if (PrefsFindBool("nogui"))
682 return;
683
684 VideoQuitFullScreen();
685 display_alert(STR_ERROR_ALERT_TITLE, text, MB_ICONSTOP);
686 }
687
688
689 /*
690 * Display warning alert
691 */
692
693 void WarningAlert(const char *text)
694 {
695 if (PrefsFindBool("nogui"))
696 return;
697
698 display_alert(STR_WARNING_ALERT_TITLE, text, MB_ICONINFORMATION);
699 }
700
701
702 /*
703 * Display choice alert
704 */
705
706 bool ChoiceAlert(const char *text, const char *pos, const char *neg)
707 {
708 printf(GetString(STR_SHELL_WARNING_PREFIX), text);
709 return false; //!!
710 }