~ubuntu-branches/ubuntu/feisty/basilisk2/feisty

« back to all changes in this revision

Viewing changes to src/Windows/main_windows.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2005-07-30 20:42:20 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050730204220-1nl1cg2jkjvy63ry
Tags: 0.9.20050730-1
* New upstream CVS snapshot.
* Build-depend on virtual libsdl-dev (not libsdl1.2-dev).
* Invoke init rules also on clean (to separate better from official
  builds).
* Update URL of upstream source in debian/copyright.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        // 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
        // Release win32 libraries
 
497
        KernelExit();
 
498
 
 
499
        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
 *  Get the main window handle
 
645
 */
 
646
 
 
647
#ifdef USE_SDL_VIDEO
 
648
#include <SDL_syswm.h>
 
649
static HWND GetMainWindowHandle(void)
 
650
{
 
651
        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
}
 
657
#endif
 
658
 
 
659
 
 
660
/*
 
661
 *  Display alert
 
662
 */
 
663
 
 
664
static void display_alert(int title_id, const char *text, int flags)
 
665
{
 
666
        HWND hMainWnd = GetMainWindowHandle();
 
667
        MessageBox(hMainWnd, text, GetString(title_id), MB_OK | flags);
 
668
}
 
669
 
 
670
 
 
671
/*
 
672
 *  Display error alert
 
673
 */
 
674
 
 
675
void ErrorAlert(const char *text)
 
676
{
 
677
        if (PrefsFindBool("nogui"))
 
678
                return;
 
679
 
 
680
        VideoQuitFullScreen();
 
681
        display_alert(STR_ERROR_ALERT_TITLE, text, MB_ICONSTOP);
 
682
}
 
683
 
 
684
 
 
685
/*
 
686
 *  Display warning alert
 
687
 */
 
688
 
 
689
void WarningAlert(const char *text)
 
690
{
 
691
        if (PrefsFindBool("nogui"))
 
692
                return;
 
693
 
 
694
        display_alert(STR_WARNING_ALERT_TITLE, text, MB_ICONINFORMATION);
 
695
}
 
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
}