|
|
1.1 root 1: /*
1.1.1.6 root 2: Hatari - main.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: Main initialization and event handling routines.
1.1 root 8: */
1.1.1.12! root 9: const char Opt_rcsid[] = "Hatari $Id: main.c,v 1.86 2006/08/02 07:45:00 thothy Exp $";
1.1 root 10:
11: #include <time.h>
1.1.1.5 root 12: #include <unistd.h>
1.1 root 13:
14: #include <SDL.h>
15:
16: #include "main.h"
17: #include "configuration.h"
1.1.1.12! root 18: #include "options.h"
1.1 root 19: #include "dialog.h"
20: #include "audio.h"
21: #include "joy.h"
22: #include "file.h"
23: #include "floppy.h"
24: #include "gemdos.h"
1.1.1.4 root 25: #include "hdc.h"
1.1 root 26: #include "ikbd.h"
1.1.1.10 root 27: #include "ioMem.h"
1.1.1.5 root 28: #include "keymap.h"
1.1.1.10 root 29: #include "log.h"
1.1 root 30: #include "m68000.h"
31: #include "memorySnapShot.h"
32: #include "misc.h"
1.1.1.8 root 33: #include "midi.h"
1.1 root 34: #include "printer.h"
1.1.1.8 root 35: #include "reset.h"
1.1 root 36: #include "rs232.h"
37: #include "screen.h"
1.1.1.5 root 38: #include "sdlgui.h"
1.1 root 39: #include "shortcut.h"
40: #include "sound.h"
1.1.1.8 root 41: #include "stMemory.h"
1.1 root 42: #include "tos.h"
1.1.1.5 root 43: #include "vdi.h"
1.1 root 44: #include "video.h"
45: #include "ymFormat.h"
1.1.1.2 root 46: #include "debugui.h"
1.1 root 47:
48: #include "uae-cpu/hatari-glue.h"
49:
50:
1.1.1.12! root 51: BOOL bQuitProgram = FALSE; /* Flag to quit program cleanly */
! 52: BOOL bEnableDebug = FALSE; /* Enable debug UI? */
1.1.1.8 root 53: char szWorkingDir[FILENAME_MAX]; /* Working directory */
1.1.1.12! root 54: static BOOL bEmulationActive = TRUE; /* Run emulation when started */
! 55: static BOOL bAccurateDelays; /* Host system has an accurate SDL_Delay()? */
! 56: static char szBootDiskImage[FILENAME_MAX]; /* boot disk path or empty */
! 57: static BOOL bIgnoreNextMouseMotion = FALSE; /* Next mouse motion will be ignored (needed after SDL_WarpMouse) */
1.1 root 58:
59:
60: /*-----------------------------------------------------------------------*/
61: /*
62: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
63: */
64: void Main_MemorySnapShot_Capture(BOOL bSave)
65: {
66: int nBytes;
67:
68: /* Save/Restore details */
69: /* Only save/restore area of memory machine ie set to, eg 1Mb */
70: if (bSave) {
1.1.1.11 root 71: nBytes = STRamEnd;
1.1 root 72: MemorySnapShot_Store(&nBytes,sizeof(nBytes));
73: MemorySnapShot_Store(STRam,nBytes);
74: }
75: else {
76: MemorySnapShot_Store(&nBytes,sizeof(nBytes));
77: MemorySnapShot_Store(STRam,nBytes);
78: }
79: /* And Cart/TOS/Hardware area */
80: MemorySnapShot_Store(&STRam[0xE00000],0x200000);
1.1.1.11 root 81: MemorySnapShot_Store(szBootDiskImage, sizeof(szBootDiskImage));
1.1 root 82: MemorySnapShot_Store(szWorkingDir,sizeof(szWorkingDir));
83: }
84:
85:
86: /*-----------------------------------------------------------------------*/
87: /*
88: Pause emulation, stop sound
89: */
90: void Main_PauseEmulation(void)
91: {
1.1.1.4 root 92: if( bEmulationActive )
93: {
1.1.1.6 root 94: Audio_EnableAudio(FALSE);
1.1.1.4 root 95: bEmulationActive = FALSE;
96: }
1.1 root 97: }
98:
1.1.1.2 root 99: /*-----------------------------------------------------------------------*/
1.1 root 100: /*
101: Start emulation
102: */
103: void Main_UnPauseEmulation(void)
104: {
1.1.1.4 root 105: if( !bEmulationActive )
106: {
1.1.1.11 root 107: Sound_ResetBufferIndex();
1.1.1.6 root 108: Audio_EnableAudio(ConfigureParams.Sound.bEnableSound);
1.1.1.11 root 109: Screen_SetFullUpdate(); /* Cause full screen update (to clear all) */
1.1 root 110:
1.1.1.4 root 111: bEmulationActive = TRUE;
112: }
1.1 root 113: }
114:
1.1.1.7 root 115:
1.1.1.12! root 116: /*-----------------------------------------------------------------------*/
! 117: /*
! 118: This function waits on each emulated VBL to synchronize the real time
! 119: with the emulated ST.
! 120: Unfortunately SDL_Delay and other sleep functions like usleep or nanosleep
! 121: are very inaccurate on some systems like Linux 2.4 or Mac OS X (they can only
! 122: wait for a multiple of 10ms due to the scheduler on these systems), so we have
! 123: to "busy wait" there to get an accurate timing.
! 124: */
! 125: void Main_WaitOnVbl(void)
! 126: {
! 127: int nCurrentMilliTicks;
! 128: static int nDestMilliTicks = 0;
! 129: int nFrameDuration;
! 130: signed int nDelay;
! 131:
! 132: nCurrentMilliTicks = SDL_GetTicks();
! 133:
! 134: nFrameDuration = 1000/nScreenRefreshRate;
! 135: nDelay = nDestMilliTicks - nCurrentMilliTicks;
! 136:
! 137: /* Do not wait if we are in max speed mode or if we are totally out of sync */
! 138: if (ConfigureParams.System.nMinMaxSpeed == MINMAXSPEED_MAX
! 139: || nDelay < -4*nFrameDuration)
! 140: {
! 141: /* Only update nDestMilliTicks for next VBL */
! 142: nDestMilliTicks = nCurrentMilliTicks + nFrameDuration;
! 143: return;
! 144: }
! 145:
! 146: if (bAccurateDelays)
! 147: {
! 148: /* Accurate sleeping is possible -> use SDL_Delay to free the CPU */
! 149: if (nDelay > 1)
! 150: SDL_Delay(nDelay - 1);
! 151: }
! 152: else
! 153: {
! 154: /* No accurate SDL_Delay -> only wait if more than 5ms to go... */
! 155: if (nDelay > 5)
! 156: SDL_Delay(nDelay<10 ? nDelay-1 : 9);
! 157: }
! 158:
! 159: /* Now busy-wait for the right tick: */
! 160: while (nDelay > 0)
! 161: {
! 162: nCurrentMilliTicks = SDL_GetTicks();
! 163: nDelay = nDestMilliTicks - nCurrentMilliTicks;
! 164: }
! 165:
! 166: /* Update nDestMilliTicks for next VBL */
! 167: nDestMilliTicks += nFrameDuration;
! 168: }
! 169:
! 170:
! 171: /*-----------------------------------------------------------------------*/
! 172: /*
! 173: Since SDL_Delay and friends are very inaccurate on some systems, we have
! 174: to check if we can rely on this delay function.
! 175: */
! 176: static void Main_CheckForAccurateDelays(void)
! 177: {
! 178: int nStartTicks, nEndTicks;
! 179:
! 180: /* Force a task switch now, so we have a longer timeslice afterwards */
! 181: SDL_Delay(10);
! 182:
! 183: nStartTicks = SDL_GetTicks();
! 184: SDL_Delay(1);
! 185: nEndTicks = SDL_GetTicks();
! 186:
! 187: /* If the delay took longer than 10ms, we are on an inaccurate system! */
! 188: bAccurateDelays = ((nEndTicks - nStartTicks) < 9);
! 189:
! 190: if (bAccurateDelays)
! 191: Log_Printf(LOG_DEBUG, "Host system has accurate delays. (%d)\n", nEndTicks - nStartTicks);
! 192: else
! 193: Log_Printf(LOG_DEBUG, "Host system does not have accurate delays. (%d)\n", nEndTicks - nStartTicks);
! 194: }
! 195:
! 196:
1.1 root 197: /* ----------------------------------------------------------------------- */
198: /*
1.1.1.9 root 199: Set mouse pointer to new coordinates and set flag to ignore the mouse event
200: that is generated by SDL_WarpMouse().
201: */
202: void Main_WarpMouse(int x, int y)
203: {
204: SDL_WarpMouse(x, y); /* Set mouse pointer to new position */
205: bIgnoreNextMouseMotion = TRUE; /* Ignore mouse motion event from SDL_WarpMouse */
206: }
207:
208:
209: /* ----------------------------------------------------------------------- */
210: /*
1.1.1.12! root 211: Handle mouse motion event.
! 212: */
! 213: static void Main_HandleMouseMotion(SDL_Event *pEvent)
! 214: {
! 215: int dx, dy;
! 216: static int ax = 0, ay = 0;
! 217:
! 218:
! 219: if (bIgnoreNextMouseMotion)
! 220: {
! 221: bIgnoreNextMouseMotion = FALSE;
! 222: return;
! 223: }
! 224:
! 225: dx = pEvent->motion.xrel;
! 226: dy = pEvent->motion.yrel;
! 227:
! 228: if (STRes == ST_LOW_RES &&
! 229: (ConfigureParams.Screen.ChosenDisplayMode == DISPLAYMODE_LOWCOL_HIGHRES ||
! 230: ConfigureParams.Screen.ChosenDisplayMode == DISPLAYMODE_HICOL_HIGHRES))
! 231: {
! 232: /* In zoomed ST-Low res mode, we devide dx and dy by two so that the ST mouse
! 233: * cursor stays in sync with the host mouse. However, we have to take care of
! 234: * lowest bit of dx and dy which will get lost when dividing by two. So we
! 235: * store these bits in ax and ay and add them to dx and dy the next time. */
! 236: dx += ax;
! 237: dy += ay;
! 238: if (dx & 1)
! 239: ax = (dx > 0) ? 1 : -1;
! 240: else
! 241: ax = 0;
! 242: if (dy & 1)
! 243: ay = (dy > 0) ? 1 : -1;
! 244: else
! 245: ay = 0;
! 246: dx /= 2;
! 247: dy /= 2;
! 248: }
! 249: else if (STRes == ST_MEDIUM_RES || STRes == ST_LOWMEDIUM_MIX_RES)
! 250: {
! 251: /* In medium resolution, we only have to take care about dy. */
! 252: dy += ay;
! 253: if (dy & 1)
! 254: ay = (dy > 0) ? 1 : -1;
! 255: else
! 256: ay = 0;
! 257: dy /= 2;
! 258: }
! 259:
! 260: KeyboardProcessor.Mouse.dx += dx;
! 261: KeyboardProcessor.Mouse.dy += dy;
! 262: }
! 263:
! 264:
! 265: /* ----------------------------------------------------------------------- */
! 266: /*
1.1.1.7 root 267: Message handler
1.1 root 268: Here we process the SDL events (keyboard, mouse, ...) and map it to
269: Atari IKBD events.
270: */
1.1.1.8 root 271: void Main_EventHandler(void)
1.1 root 272: {
1.1.1.4 root 273: SDL_Event event;
1.1 root 274:
1.1.1.4 root 275: if( SDL_PollEvent(&event) )
276: switch( event.type )
1.1 root 277: {
1.1.1.9 root 278:
1.1 root 279: case SDL_QUIT:
1.1.1.4 root 280: bQuitProgram = TRUE;
1.1.1.8 root 281: set_special(SPCFLAG_BRK); /* Assure that CPU core shuts down */
1.1 root 282: break;
1.1.1.9 root 283:
1.1.1.4 root 284: case SDL_MOUSEMOTION: /* Read/Update internal mouse position */
1.1.1.12! root 285: Main_HandleMouseMotion(&event);
1.1 root 286: break;
1.1.1.9 root 287:
1.1 root 288: case SDL_MOUSEBUTTONDOWN:
1.1.1.12! root 289: if (event.button.button == SDL_BUTTON_LEFT)
1.1.1.4 root 290: {
1.1.1.12! root 291: if (Keyboard.LButtonDblClk == 0)
1.1.1.4 root 292: Keyboard.bLButtonDown |= BUTTON_MOUSE; /* Set button down flag */
293: }
1.1.1.12! root 294: else if (event.button.button == SDL_BUTTON_RIGHT)
! 295: {
1.1.1.4 root 296: Keyboard.bRButtonDown |= BUTTON_MOUSE;
1.1.1.12! root 297: }
! 298: else if (event.button.button == SDL_BUTTON_MIDDLE)
! 299: {
! 300: /* Start double-click sequence in emulation time */
! 301: Keyboard.LButtonDblClk = 1;
! 302: }
! 303: else if (event.button.button == SDL_BUTTON_WHEELDOWN)
! 304: {
! 305: /* Simulate pressing the "cursor down" key */
! 306: IKBD_PressSTKey(0x50, TRUE);
! 307: }
! 308: else if (event.button.button == SDL_BUTTON_WHEELUP)
! 309: {
! 310: /* Simulate pressing the "cursor up" key */
! 311: IKBD_PressSTKey(0x48, TRUE);
! 312: }
1.1 root 313: break;
1.1.1.9 root 314:
1.1 root 315: case SDL_MOUSEBUTTONUP:
1.1.1.12! root 316: if (event.button.button == SDL_BUTTON_LEFT)
! 317: {
1.1.1.4 root 318: Keyboard.bLButtonDown &= ~BUTTON_MOUSE;
1.1.1.12! root 319: }
! 320: else if (event.button.button == SDL_BUTTON_RIGHT)
! 321: {
! 322: Keyboard.bRButtonDown &= ~BUTTON_MOUSE;
! 323: }
! 324: else if (event.button.button == SDL_BUTTON_WHEELDOWN)
! 325: {
! 326: /* Simulate releasing the "cursor down" key */
! 327: IKBD_PressSTKey(0x50, FALSE);
! 328: }
! 329: else if (event.button.button == SDL_BUTTON_WHEELUP)
! 330: {
! 331: /* Simulate releasing the "cursor up" key */
! 332: IKBD_PressSTKey(0x48, FALSE);
! 333: }
1.1 root 334: break;
1.1.1.9 root 335:
1.1.1.7 root 336: case SDL_KEYDOWN:
337: Keymap_KeyDown(&event.key.keysym);
1.1 root 338: break;
1.1.1.9 root 339:
1.1.1.7 root 340: case SDL_KEYUP:
341: Keymap_KeyUp(&event.key.keysym);
1.1 root 342: break;
343: }
344: }
345:
346:
1.1.1.2 root 347: /*-----------------------------------------------------------------------*/
1.1 root 348: /*
349: Initialise emulation
350: */
1.1.1.8 root 351: static void Main_Init(void)
1.1 root 352: {
1.1.1.10 root 353: /* Open debug log file */
354: Log_Init();
355: Log_Printf(LOG_INFO, PROG_NAME ", compiled on: " __DATE__ ", " __TIME__ "\n");
356:
1.1.1.7 root 357: /* Init SDL's video subsystem. Note: Audio and joystick subsystems
1.1.1.5 root 358: will be initialized later (failures there are not fatal). */
1.1.1.7 root 359: if(SDL_Init(SDL_INIT_VIDEO) < 0)
1.1.1.4 root 360: {
1.1.1.2 root 361: fprintf(stderr, "Could not initialize the SDL library:\n %s\n", SDL_GetError() );
362: exit(-1);
1.1.1.4 root 363: }
1.1.1.2 root 364:
1.1 root 365: Misc_SeedRandom(1043618);
1.1.1.4 root 366: SDLGui_Init();
1.1 root 367: Printer_Init();
368: RS232_Init();
1.1.1.8 root 369: Midi_Init();
1.1 root 370: Screen_Init();
371: Floppy_Init();
1.1.1.6 root 372: Init680x0(); /* Init CPU emulation */
373: Audio_Init();
1.1.1.7 root 374: Keymap_Init();
375:
376: /* Init HD emulation */
1.1.1.11 root 377: if (ConfigureParams.HardDisk.bUseHardDiskImage)
1.1.1.7 root 378: {
1.1.1.11 root 379: char *szHardDiskImage = ConfigureParams.HardDisk.szHardDiskImage;
380: if (HDC_Init(szHardDiskImage))
381: printf("Hard drive image %s mounted.\n", szHardDiskImage);
1.1.1.7 root 382: else
1.1.1.11 root 383: printf("Couldn't open HD file: %s, or no partitions\n", szHardDiskImage);
1.1.1.7 root 384: }
385: GemDOS_Init();
1.1.1.11 root 386: if(ConfigureParams.HardDisk.bUseHardDiskDirectories)
1.1.1.7 root 387: {
388: GemDOS_InitDrives();
389: }
1.1.1.6 root 390:
391: if(Reset_Cold()) /* Reset all systems, load TOS image */
392: {
393: /* If loading of the TOS failed, we bring up the GUI to let the
394: * user choose another TOS ROM file. */
395: Dialog_DoProperty();
396: }
397: if(!bTosImageLoaded || bQuitProgram)
398: {
399: fprintf(stderr, "Failed to load TOS image!\n");
400: SDL_Quit();
401: exit(-2);
402: }
403:
1.1.1.10 root 404: IoMem_Init();
1.1 root 405: Joy_Init();
406: Sound_Init();
407:
1.1.1.11 root 408: /* Check passed disk image parameter, boot directly into emulator */
409: if (strlen(szBootDiskImage) > 0)
1.1.1.6 root 410: {
1.1.1.11 root 411: Floppy_InsertDiskIntoDrive(0, szBootDiskImage);
1.1 root 412: }
413: }
414:
1.1.1.6 root 415:
1.1.1.2 root 416: /*-----------------------------------------------------------------------*/
1.1 root 417: /*
418: Un-Initialise emulation
419: */
1.1.1.8 root 420: static void Main_UnInit(void)
1.1 root 421: {
422: Screen_ReturnFromFullScreen();
423: Floppy_UnInit();
1.1.1.4 root 424: HDC_UnInit();
1.1.1.8 root 425: Midi_UnInit();
1.1 root 426: RS232_UnInit();
427: Printer_UnInit();
1.1.1.10 root 428: IoMem_UnInit();
1.1.1.4 root 429: GemDOS_UnInitDrives();
1.1.1.12! root 430: Joy_UnInit();
1.1.1.5 root 431: if(Sound_AreWeRecording())
432: Sound_EndRecording();
1.1.1.2 root 433: Audio_UnInit();
1.1 root 434: YMFormat_FreeRecording();
1.1.1.4 root 435: SDLGui_UnInit();
1.1 root 436: Screen_UnInit();
1.1.1.8 root 437: Exit680x0();
1.1 root 438:
1.1.1.2 root 439: /* SDL uninit: */
440: SDL_Quit();
1.1.1.10 root 441:
442: /* Close debug log file */
443: Log_UnInit();
1.1 root 444: }
445:
1.1.1.6 root 446:
1.1.1.2 root 447: /*-----------------------------------------------------------------------*/
1.1 root 448: /*
449: Main
450: */
451: int main(int argc, char *argv[])
452: {
453: /* Generate random seed */
1.1.1.10 root 454: srand(time(NULL));
1.1 root 455:
1.1.1.8 root 456: /* Get working directory */
457: getcwd(szWorkingDir, FILENAME_MAX);
458:
1.1.1.12! root 459: /* no boot disk image */
1.1.1.11 root 460: szBootDiskImage[0] = 0;
1.1 root 461:
1.1.1.2 root 462: /* Set default configuration values: */
463: Configuration_SetDefault();
464:
1.1.1.7 root 465: /* Now load the values from the configuration file */
1.1.1.10 root 466: Configuration_Load(CONFDIR"/hatari.cfg"); /* Try the global configuration file first */
467: Configuration_Load(NULL); /* Now try the users configuration file */
1.1.1.7 root 468:
1.1.1.12! root 469: /* Check for any passed parameters, get boot disk */
! 470: Opt_ParseParameters(argc, argv, szBootDiskImage, sizeof(szBootDiskImage));
1.1 root 471:
472: /* Init emulator system */
473: Main_Init();
474:
1.1.1.12! root 475: /* Check if SDL_Delay is accurate */
! 476: Main_CheckForAccurateDelays();
! 477:
1.1.1.2 root 478: /* Switch immediately to fullscreen if user wants to */
1.1.1.9 root 479: if (ConfigureParams.Screen.bFullScreen)
1.1.1.2 root 480: Screen_EnterFullScreen();
481:
1.1.1.4 root 482: /* Run emulation */
1.1 root 483: Main_UnPauseEmulation();
1.1.1.4 root 484: Start680x0(); /* Start emulation */
1.1 root 485:
486: /* Un-init emulation system */
1.1.1.7 root 487: Main_UnInit();
1.1 root 488:
1.1.1.10 root 489: return 0;
1.1 root 490: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.