ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/main_windows.cpp
Revision: 1.10
Committed: 2006-05-08T16:56:07Z (18 years, 2 months ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-19
Changes since 1.9: +2 -2 lines
Log Message:
Fix for LAZY_FLUSH_ICACHE_RANGE. Blocks are indexed by native addresses.

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