|
|
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.17 root 9: const char Main_fileid[] = "Hatari main.c : " __DATE__ " " __TIME__;
1.1 root 10:
1.1.1.13 root 11: #include <time.h>
1.1.1.19! root 12: #include <errno.h>
1.1 root 13: #include <SDL.h>
14:
15: #include "main.h"
16: #include "configuration.h"
1.1.1.15 root 17: #include "control.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 "floppy.h"
23: #include "gemdos.h"
1.1.1.4 root 24: #include "hdc.h"
1.1.1.16 root 25: #include "ide.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"
1.1.1.8 root 32: #include "midi.h"
1.1.1.13 root 33: #include "nvram.h"
34: #include "paths.h"
1.1 root 35: #include "printer.h"
1.1.1.8 root 36: #include "reset.h"
1.1.1.19! root 37: #include "resolution.h"
1.1 root 38: #include "rs232.h"
39: #include "screen.h"
1.1.1.5 root 40: #include "sdlgui.h"
1.1 root 41: #include "shortcut.h"
42: #include "sound.h"
1.1.1.18 root 43: #include "dmaSnd.h"
1.1.1.15 root 44: #include "statusbar.h"
1.1.1.8 root 45: #include "stMemory.h"
1.1.1.15 root 46: #include "str.h"
1.1 root 47: #include "tos.h"
48: #include "video.h"
1.1.1.18 root 49: #include "avi_record.h"
50: #include "debugui.h"
1.1.1.19! root 51: #include "clocks_timings.h"
1.1 root 52:
1.1.1.13 root 53: #include "hatari-glue.h"
54:
55: #include "falcon/hostscreen.h"
56: #include "falcon/dsp.h"
1.1 root 57:
1.1.1.19! root 58: #if HAVE_GETTIMEOFDAY
! 59: #include <sys/time.h>
! 60: #endif
! 61:
1.1 root 62:
1.1.1.17 root 63: bool bQuitProgram = false; /* Flag to quit program cleanly */
1.1.1.13 root 64:
1.1.1.19! root 65: static Uint32 nRunVBLs; /* Whether and how many VBLS to run before exit */
1.1.1.17 root 66: static Uint32 nFirstMilliTick; /* Ticks when VBL counting started */
67: static Uint32 nVBLCount; /* Frame count */
68:
69: static bool bEmulationActive = true; /* Run emulation when started */
1.1.1.15 root 70: static bool bAccurateDelays; /* Host system has an accurate SDL_Delay()? */
1.1.1.17 root 71: static bool bIgnoreNextMouseMotion = false; /* Next mouse motion will be ignored (needed after SDL_WarpMouse) */
1.1 root 72:
73:
74: /*-----------------------------------------------------------------------*/
1.1.1.13 root 75: /**
1.1.1.17 root 76: * Return current time as millisecond for performance measurements.
77: *
78: * (On Unix only time spent by Hatari itself is counted, on other
79: * platforms less accurate SDL "wall clock".)
80: */
81: #if HAVE_SYS_TIMES_H
82: #include <unistd.h>
83: #include <sys/times.h>
84: static Uint32 Main_GetTicks(void)
85: {
86: static unsigned int ticks_to_msec = 0;
87: struct tms fields;
88: if (!ticks_to_msec)
89: {
90: ticks_to_msec = sysconf(_SC_CLK_TCK);
91: printf("OS clock ticks / second: %d\n", ticks_to_msec);
92: /* Linux has 100Hz virtual clock so no accuracy loss there */
93: ticks_to_msec = 1000UL / ticks_to_msec;
94: }
95: /* return milliseconds (clock ticks) spent in this process
96: */
97: times(&fields);
98: return ticks_to_msec * fields.tms_utime;
99: }
100: #else
1.1.1.18 root 101: # warning "times() function missing, using inaccurate SDL_GetTicks() instead."
102: # define Main_GetTicks SDL_GetTicks
1.1.1.17 root 103: #endif
104:
105:
1.1.1.19! root 106: //#undef HAVE_GETTIMEOFDAY
! 107: //#undef HAVE_NANOSLEEP
! 108:
! 109: /*-----------------------------------------------------------------------*/
! 110: /**
! 111: * Return a time counter in micro seconds.
! 112: * If gettimeofday is available, we use it directly, else we convert the
! 113: * return of SDL_GetTicks in micro sec.
! 114: */
! 115:
! 116: static Sint64 Time_GetTicks ( void )
! 117: {
! 118: Sint64 ticks_micro;
! 119:
! 120: #if HAVE_GETTIMEOFDAY
! 121: struct timeval now;
! 122: gettimeofday ( &now , NULL );
! 123: ticks_micro = (Sint64)now.tv_sec * 1000000 + now.tv_usec;
! 124: #else
! 125: ticks_micro = (Sint64)SDL_GetTicks() * 1000; /* milli sec -> micro sec */
! 126: #endif
! 127:
! 128: return ticks_micro;
! 129: }
! 130:
! 131:
! 132: /*-----------------------------------------------------------------------*/
! 133: /**
! 134: * Sleep for a given number of micro seconds.
! 135: * If nanosleep is available, we use it directly, else we use SDL_Delay
! 136: * (which is portable, but less accurate as is uses milli-seconds)
! 137: */
! 138:
! 139: static void Time_Delay ( Sint64 ticks_micro )
! 140: {
! 141: #if HAVE_NANOSLEEP
! 142: struct timespec ts;
! 143: int ret;
! 144: ts.tv_sec = ticks_micro / 1000000;
! 145: ts.tv_nsec = (ticks_micro % 1000000) * 1000; /* micro sec -> nano sec */
! 146: /* wait until all the delay is elapsed, including possible interruptions by signals */
! 147: do
! 148: {
! 149: errno = 0;
! 150: ret = nanosleep(&ts, &ts);
! 151: } while ( ret && ( errno == EINTR ) ); /* keep on sleeping if we were interrupted */
! 152: #else
! 153: SDL_Delay ( (Uint32)(ticks_micro / 1000) ) ; /* micro sec -> milli sec */
! 154: #endif
! 155: }
! 156:
! 157:
1.1.1.17 root 158: /*-----------------------------------------------------------------------*/
159: /**
160: * Pause emulation, stop sound. 'visualize' should be set true,
1.1.1.15 root 161: * unless unpause will be called immediately afterwards.
162: *
1.1.1.17 root 163: * @return true if paused now, false if was already paused
1.1.1.13 root 164: */
1.1.1.15 root 165: bool Main_PauseEmulation(bool visualize)
1.1 root 166: {
1.1.1.15 root 167: if ( !bEmulationActive )
1.1.1.17 root 168: return false;
1.1.1.15 root 169:
1.1.1.17 root 170: Audio_EnableAudio(false);
171: bEmulationActive = false;
1.1.1.15 root 172: if (visualize)
1.1.1.13 root 173: {
1.1.1.17 root 174: if (nFirstMilliTick)
175: {
176: int interval = Main_GetTicks() - nFirstMilliTick;
177: static float previous;
178: float current;
179:
180: current = (1000.0 * nVBLCount) / interval;
181: printf("SPEED: %.1f VBL/s (%d/%.1fs), diff=%.1f%%\n",
182: current, nVBLCount, interval/1000.0,
1.1.1.19! root 183: previous>0.0 ? 100*(current-previous)/previous : 0.0);
1.1.1.17 root 184: nVBLCount = nFirstMilliTick = 0;
185: previous = current;
186: }
187:
1.1.1.15 root 188: Statusbar_AddMessage("Emulation paused", 100);
189: /* make sure msg gets shown */
190: Statusbar_Update(sdlscrn);
1.1.1.17 root 191:
192: if (bGrabMouse && !bInFullScreen)
193: /* Un-grab mouse pointer in windowed mode */
194: SDL_WM_GrabInput(SDL_GRAB_OFF);
1.1.1.13 root 195: }
1.1.1.17 root 196: return true;
1.1 root 197: }
198:
1.1.1.2 root 199: /*-----------------------------------------------------------------------*/
1.1.1.13 root 200: /**
1.1.1.15 root 201: * Start/continue emulation
202: *
1.1.1.17 root 203: * @return true if continued, false if was already running
1.1.1.13 root 204: */
1.1.1.15 root 205: bool Main_UnPauseEmulation(void)
1.1 root 206: {
1.1.1.15 root 207: if ( bEmulationActive )
1.1.1.17 root 208: return false;
1.1 root 209:
1.1.1.19! root 210: Sound_BufferIndexNeedReset = true;
1.1.1.15 root 211: Audio_EnableAudio(ConfigureParams.Sound.bEnableSound);
1.1.1.17 root 212: bEmulationActive = true;
1.1.1.15 root 213:
214: /* Cause full screen update (to clear all) */
215: Screen_SetFullUpdate();
1.1.1.17 root 216:
217: if (bGrabMouse)
218: /* Grab mouse pointer again */
219: SDL_WM_GrabInput(SDL_GRAB_ON);
220: return true;
1.1 root 221: }
222:
1.1.1.13 root 223: /*-----------------------------------------------------------------------*/
224: /**
225: * Optionally ask user whether to quit and set bQuitProgram accordingly
226: */
227: void Main_RequestQuit(void)
228: {
229: if (ConfigureParams.Memory.bAutoSave)
230: {
1.1.1.17 root 231: bQuitProgram = true;
232: MemorySnapShot_Capture(ConfigureParams.Memory.szAutoSaveFileName, false);
1.1.1.13 root 233: }
234: else if (ConfigureParams.Log.bConfirmQuit)
235: {
1.1.1.17 root 236: bQuitProgram = false; /* if set true, dialog exits */
1.1.1.13 root 237: bQuitProgram = DlgAlert_Query("All unsaved data will be lost.\nDo you really want to quit?");
238: }
239: else
240: {
1.1.1.17 root 241: bQuitProgram = true;
1.1.1.13 root 242: }
243:
244: if (bQuitProgram)
245: {
246: /* Assure that CPU core shuts down */
247: M68000_SetSpecial(SPCFLAG_BRK);
248: }
249: }
1.1.1.7 root 250:
1.1.1.12 root 251: /*-----------------------------------------------------------------------*/
1.1.1.13 root 252: /**
1.1.1.19! root 253: * Set how many VBLs Hatari should run, from the moment this function
! 254: * is called.
! 255: */
! 256: void Main_SetRunVBLs(Uint32 vbls)
! 257: {
! 258: fprintf(stderr, "Exit after %d VBLs.\n", vbls);
! 259: nRunVBLs = vbls;
! 260: nVBLCount = 0;
! 261: }
! 262:
! 263: /*-----------------------------------------------------------------------*/
! 264: /**
1.1.1.13 root 265: * This function waits on each emulated VBL to synchronize the real time
266: * with the emulated ST.
267: * Unfortunately SDL_Delay and other sleep functions like usleep or nanosleep
268: * are very inaccurate on some systems like Linux 2.4 or Mac OS X (they can only
269: * wait for a multiple of 10ms due to the scheduler on these systems), so we have
270: * to "busy wait" there to get an accurate timing.
1.1.1.19! root 271: * All times are expressed as micro seconds, to avoid too much rounding error.
1.1.1.13 root 272: */
1.1.1.12 root 273: void Main_WaitOnVbl(void)
274: {
1.1.1.19! root 275: Sint64 CurrentTicks;
! 276: static Sint64 DestTicks = 0;
! 277: Sint64 FrameDuration_micro;
! 278: Sint64 nDelay;
1.1.1.13 root 279:
1.1.1.18 root 280: nVBLCount++;
281: if (nRunVBLs && nVBLCount >= nRunVBLs)
282: {
283: /* show VBLs/s */
284: Main_PauseEmulation(true);
285: exit(0);
286: }
1.1.1.13 root 287:
1.1.1.19! root 288: // FrameDuration_micro = (Sint64) ( 1000000.0 / nScreenRefreshRate + 0.5 ); /* round to closest integer */
! 289: FrameDuration_micro = ClocksTimings_GetVBLDuration_micro ( ConfigureParams.System.nMachineType , nScreenRefreshRate );
! 290: CurrentTicks = Time_GetTicks();
! 291:
! 292: if ( DestTicks == 0 ) /* first call, init DestTicks */
! 293: DestTicks = CurrentTicks + FrameDuration_micro;
! 294:
! 295: nDelay = DestTicks - CurrentTicks;
1.1.1.13 root 296:
1.1.1.15 root 297: /* Do not wait if we are in fast forward mode or if we are totally out of sync */
1.1.1.17 root 298: if (ConfigureParams.System.bFastForward == true
1.1.1.19! root 299: || nDelay < -4*FrameDuration_micro)
1.1.1.13 root 300: {
1.1.1.17 root 301: if (ConfigureParams.System.bFastForward == true)
302: {
303: if (!nFirstMilliTick)
304: nFirstMilliTick = Main_GetTicks();
305: }
1.1.1.15 root 306: if (nFrameSkips < ConfigureParams.Screen.nFrameSkips)
307: {
308: nFrameSkips += 1;
1.1.1.17 root 309: // Log_Printf(LOG_DEBUG, "Increased frameskip to %d\n", nFrameSkips);
1.1.1.15 root 310: }
1.1.1.19! root 311: /* Only update DestTicks for next VBL */
! 312: DestTicks = CurrentTicks + FrameDuration_micro;
1.1.1.13 root 313: return;
314: }
1.1.1.15 root 315: /* If automatic frameskip is enabled and delay's more than twice
316: * the effect of single frameskip, decrease frameskip
317: */
318: if (nFrameSkips > 0
319: && ConfigureParams.Screen.nFrameSkips >= AUTO_FRAMESKIP_LIMIT
1.1.1.19! root 320: && 2*nDelay > FrameDuration_micro/nFrameSkips)
1.1.1.15 root 321: {
322: nFrameSkips -= 1;
1.1.1.17 root 323: // Log_Printf(LOG_DEBUG, "Decreased frameskip to %d\n", nFrameSkips);
1.1.1.15 root 324: }
1.1.1.12 root 325:
1.1.1.13 root 326: if (bAccurateDelays)
327: {
328: /* Accurate sleeping is possible -> use SDL_Delay to free the CPU */
1.1.1.19! root 329: if (nDelay > 1000)
! 330: Time_Delay(nDelay - 1000);
1.1.1.13 root 331: }
332: else
333: {
334: /* No accurate SDL_Delay -> only wait if more than 5ms to go... */
1.1.1.19! root 335: if (nDelay > 5000)
! 336: Time_Delay(nDelay<10000 ? nDelay-1000 : 9000);
1.1.1.13 root 337: }
338:
339: /* Now busy-wait for the right tick: */
340: while (nDelay > 0)
341: {
1.1.1.19! root 342: CurrentTicks = Time_GetTicks();
! 343: nDelay = DestTicks - CurrentTicks;
1.1.1.13 root 344: }
345:
1.1.1.19! root 346: //printf ( "tick %lld\n" , CurrentTicks );
! 347: /* Update DestTicks for next VBL */
! 348: DestTicks += FrameDuration_micro;
1.1.1.12 root 349: }
350:
351:
352: /*-----------------------------------------------------------------------*/
1.1.1.13 root 353: /**
354: * Since SDL_Delay and friends are very inaccurate on some systems, we have
355: * to check if we can rely on this delay function.
356: */
1.1.1.12 root 357: static void Main_CheckForAccurateDelays(void)
358: {
1.1.1.13 root 359: int nStartTicks, nEndTicks;
1.1.1.12 root 360:
1.1.1.13 root 361: /* Force a task switch now, so we have a longer timeslice afterwards */
362: SDL_Delay(10);
1.1.1.12 root 363:
1.1.1.13 root 364: nStartTicks = SDL_GetTicks();
365: SDL_Delay(1);
366: nEndTicks = SDL_GetTicks();
367:
368: /* If the delay took longer than 10ms, we are on an inaccurate system! */
369: bAccurateDelays = ((nEndTicks - nStartTicks) < 9);
370:
371: if (bAccurateDelays)
372: Log_Printf(LOG_DEBUG, "Host system has accurate delays. (%d)\n", nEndTicks - nStartTicks);
373: else
1.1.1.15 root 374: Log_Printf(LOG_WARN, "Host system does not have accurate delays. (%d)\n", nEndTicks - nStartTicks);
1.1.1.12 root 375: }
376:
377:
1.1 root 378: /* ----------------------------------------------------------------------- */
1.1.1.13 root 379: /**
380: * Set mouse pointer to new coordinates and set flag to ignore the mouse event
381: * that is generated by SDL_WarpMouse().
382: */
1.1.1.9 root 383: void Main_WarpMouse(int x, int y)
384: {
1.1.1.13 root 385: SDL_WarpMouse(x, y); /* Set mouse pointer to new position */
1.1.1.17 root 386: bIgnoreNextMouseMotion = true; /* Ignore mouse motion event from SDL_WarpMouse */
1.1.1.9 root 387: }
388:
389:
390: /* ----------------------------------------------------------------------- */
1.1.1.13 root 391: /**
392: * Handle mouse motion event.
393: */
1.1.1.12 root 394: static void Main_HandleMouseMotion(SDL_Event *pEvent)
395: {
396: int dx, dy;
397: static int ax = 0, ay = 0;
398:
1.1.1.17 root 399: /* Ignore motion when position has changed right after a reset or TOS
400: * (especially version 4.04) might get confused and play key clicks */
401: if (bIgnoreNextMouseMotion || nVBLs < 10)
1.1.1.12 root 402: {
1.1.1.17 root 403: bIgnoreNextMouseMotion = false;
1.1.1.12 root 404: return;
405: }
406:
407: dx = pEvent->motion.xrel;
408: dy = pEvent->motion.yrel;
409:
1.1.1.13 root 410: /* In zoomed low res mode, we divide dx and dy by the zoom factor so that
411: * the ST mouse cursor stays in sync with the host mouse. However, we have
412: * to take care of lowest bit of dx and dy which will get lost when
413: * dividing. So we store these bits in ax and ay and add them to dx and dy
414: * the next time. */
415: if (nScreenZoomX != 1)
416: {
1.1.1.12 root 417: dx += ax;
1.1.1.13 root 418: ax = dx % nScreenZoomX;
419: dx /= nScreenZoomX;
1.1.1.12 root 420: }
1.1.1.13 root 421: if (nScreenZoomY != 1)
1.1.1.12 root 422: {
423: dy += ay;
1.1.1.13 root 424: ay = dy % nScreenZoomY;
425: dy /= nScreenZoomY;
1.1.1.12 root 426: }
427:
428: KeyboardProcessor.Mouse.dx += dx;
429: KeyboardProcessor.Mouse.dy += dy;
430: }
431:
432:
433: /* ----------------------------------------------------------------------- */
1.1.1.13 root 434: /**
435: * SDL message handler.
436: * Here we process the SDL events (keyboard, mouse, ...) and map it to
437: * Atari IKBD events.
438: */
1.1.1.8 root 439: void Main_EventHandler(void)
1.1 root 440: {
1.1.1.17 root 441: bool bContinueProcessing;
1.1.1.13 root 442: SDL_Event event;
1.1.1.17 root 443: int events;
444: int remotepause;
445:
1.1.1.15 root 446: do
1.1.1.13 root 447: {
1.1.1.17 root 448: bContinueProcessing = false;
449:
1.1.1.15 root 450: /* check remote process control */
1.1.1.17 root 451: remotepause = Control_CheckUpdates();
1.1.1.15 root 452:
453: if ( bEmulationActive || remotepause )
454: {
1.1.1.17 root 455: events = SDL_PollEvent(&event);
1.1.1.15 root 456: }
457: else
458: {
459: ShortCut_ActKey();
460: /* last (shortcut) event activated emulation? */
461: if ( bEmulationActive )
462: break;
1.1.1.17 root 463: events = SDL_WaitEvent(&event);
1.1.1.15 root 464: }
1.1.1.17 root 465: if (!events)
1.1.1.15 root 466: {
1.1.1.17 root 467: /* no events -> if emulation is active or
468: * user is quitting -> return from function.
469: */
1.1.1.15 root 470: continue;
471: }
1.1.1.13 root 472: switch (event.type)
473: {
1.1 root 474:
1.1.1.13 root 475: case SDL_QUIT:
476: Main_RequestQuit();
477: break;
1.1.1.17 root 478:
1.1.1.13 root 479: case SDL_MOUSEMOTION: /* Read/Update internal mouse position */
480: Main_HandleMouseMotion(&event);
1.1.1.17 root 481: bContinueProcessing = true;
1.1.1.13 root 482: break;
483:
484: case SDL_MOUSEBUTTONDOWN:
485: if (event.button.button == SDL_BUTTON_LEFT)
486: {
487: if (Keyboard.LButtonDblClk == 0)
488: Keyboard.bLButtonDown |= BUTTON_MOUSE; /* Set button down flag */
489: }
490: else if (event.button.button == SDL_BUTTON_RIGHT)
491: {
492: Keyboard.bRButtonDown |= BUTTON_MOUSE;
493: }
494: else if (event.button.button == SDL_BUTTON_MIDDLE)
495: {
496: /* Start double-click sequence in emulation time */
497: Keyboard.LButtonDblClk = 1;
498: }
499: else if (event.button.button == SDL_BUTTON_WHEELDOWN)
500: {
501: /* Simulate pressing the "cursor down" key */
1.1.1.17 root 502: IKBD_PressSTKey(0x50, true);
1.1.1.13 root 503: }
504: else if (event.button.button == SDL_BUTTON_WHEELUP)
505: {
506: /* Simulate pressing the "cursor up" key */
1.1.1.17 root 507: IKBD_PressSTKey(0x48, true);
1.1.1.13 root 508: }
509: break;
510:
511: case SDL_MOUSEBUTTONUP:
512: if (event.button.button == SDL_BUTTON_LEFT)
513: {
514: Keyboard.bLButtonDown &= ~BUTTON_MOUSE;
515: }
516: else if (event.button.button == SDL_BUTTON_RIGHT)
517: {
518: Keyboard.bRButtonDown &= ~BUTTON_MOUSE;
519: }
520: else if (event.button.button == SDL_BUTTON_WHEELDOWN)
521: {
522: /* Simulate releasing the "cursor down" key */
1.1.1.17 root 523: IKBD_PressSTKey(0x50, false);
1.1.1.13 root 524: }
525: else if (event.button.button == SDL_BUTTON_WHEELUP)
526: {
527: /* Simulate releasing the "cursor up" key */
1.1.1.17 root 528: IKBD_PressSTKey(0x48, false);
1.1.1.13 root 529: }
530: break;
531:
532: case SDL_KEYDOWN:
533: Keymap_KeyDown(&event.key.keysym);
534: break;
535:
536: case SDL_KEYUP:
537: Keymap_KeyUp(&event.key.keysym);
538: break;
1.1.1.17 root 539:
540: default:
541: /* don't let unknown events delay event processing */
542: bContinueProcessing = true;
543: break;
1.1.1.13 root 544: }
1.1.1.17 root 545: } while (bContinueProcessing || !(bEmulationActive || bQuitProgram));
1.1.1.13 root 546: }
547:
548:
549: /*-----------------------------------------------------------------------*/
550: /**
1.1.1.19! root 551: * Set Hatari window title. Use NULL for default
! 552: */
! 553: void Main_SetTitle(const char *title)
! 554: {
! 555: if (title)
! 556: SDL_WM_SetCaption(title, "Hatari");
! 557: else
! 558: SDL_WM_SetCaption(PROG_NAME, "Hatari");
! 559: }
! 560:
! 561: /*-----------------------------------------------------------------------*/
! 562: /**
1.1.1.13 root 563: * Initialise emulation
564: */
1.1.1.8 root 565: static void Main_Init(void)
1.1 root 566: {
1.1.1.13 root 567: /* Open debug log file */
1.1.1.15 root 568: if (!Log_Init())
569: {
570: fprintf(stderr, "Logging/tracing initialization failed\n");
571: exit(-1);
572: }
1.1.1.13 root 573: Log_Printf(LOG_INFO, PROG_NAME ", compiled on: " __DATE__ ", " __TIME__ "\n");
574:
575: /* Init SDL's video subsystem. Note: Audio and joystick subsystems
576: will be initialized later (failures there are not fatal). */
1.1.1.18 root 577: if (SDL_Init(SDL_INIT_VIDEO | Opt_GetNoParachuteFlag()) < 0)
1.1.1.13 root 578: {
579: fprintf(stderr, "Could not initialize the SDL library:\n %s\n", SDL_GetError() );
580: exit(-1);
581: }
1.1.1.19! root 582: ClocksTimings_InitMachine ( ConfigureParams.System.nMachineType );
! 583: Resolution_Init();
1.1.1.13 root 584: SDLGui_Init();
585: Printer_Init();
586: RS232_Init();
587: Midi_Init();
588: Screen_Init();
1.1.1.19! root 589: Main_SetTitle(NULL);
1.1.1.13 root 590: HostScreen_Init();
1.1.1.18 root 591: DSP_Init();
1.1.1.13 root 592: Floppy_Init();
1.1.1.18 root 593: M68000_Init(); /* Init CPU emulation */
1.1.1.13 root 594: Audio_Init();
1.1.1.18 root 595: DmaSnd_Init();
1.1.1.13 root 596: Keymap_Init();
597:
598: /* Init HD emulation */
1.1.1.18 root 599: HDC_Init();
1.1.1.16 root 600: Ide_Init();
1.1.1.13 root 601: GemDOS_Init();
602: if (ConfigureParams.HardDisk.bUseHardDiskDirectories)
603: {
1.1.1.18 root 604: /* uses variables set by HDC_Init()! */
1.1.1.13 root 605: GemDOS_InitDrives();
606: }
607:
608: if (Reset_Cold()) /* Reset all systems, load TOS image */
609: {
610: /* If loading of the TOS failed, we bring up the GUI to let the
611: * user choose another TOS ROM file. */
612: Dialog_DoProperty();
613: }
614: if (!bTosImageLoaded || bQuitProgram)
615: {
616: fprintf(stderr, "Failed to load TOS image!\n");
617: SDL_Quit();
618: exit(-2);
619: }
620:
621: IoMem_Init();
622: NvRam_Init();
623: Joy_Init();
624: Sound_Init();
1.1.1.18 root 625:
626: /* done as last, needs CPU & DSP running... */
627: DebugUI_Init();
1.1 root 628: }
629:
1.1.1.6 root 630:
1.1.1.2 root 631: /*-----------------------------------------------------------------------*/
1.1.1.13 root 632: /**
633: * Un-Initialise emulation
634: */
1.1.1.8 root 635: static void Main_UnInit(void)
1.1 root 636: {
1.1.1.13 root 637: Screen_ReturnFromFullScreen();
638: Floppy_UnInit();
639: HDC_UnInit();
640: Midi_UnInit();
641: RS232_UnInit();
642: Printer_UnInit();
643: IoMem_UnInit();
644: NvRam_UnInit();
645: GemDOS_UnInitDrives();
1.1.1.16 root 646: Ide_UnInit();
1.1.1.13 root 647: Joy_UnInit();
648: if (Sound_AreWeRecording())
649: Sound_EndRecording();
650: Audio_UnInit();
651: SDLGui_UnInit();
1.1.1.18 root 652: DSP_UnInit();
1.1.1.15 root 653: HostScreen_UnInit();
1.1.1.13 root 654: Screen_UnInit();
655: Exit680x0();
1.1 root 656:
1.1.1.13 root 657: /* SDL uninit: */
658: SDL_Quit();
1.1.1.10 root 659:
1.1.1.13 root 660: /* Close debug log file */
661: Log_UnInit();
1.1 root 662: }
663:
1.1.1.6 root 664:
1.1.1.2 root 665: /*-----------------------------------------------------------------------*/
1.1.1.13 root 666: /**
1.1.1.15 root 667: * Load initial configuration file(s)
668: */
669: static void Main_LoadInitialConfig(void)
670: {
671: char *psGlobalConfig;
672:
673: psGlobalConfig = malloc(FILENAME_MAX);
674: if (psGlobalConfig)
675: {
676: #if defined(__AMIGAOS4__)
677: strncpy(psGlobalConfig, CONFDIR"hatari.cfg", FILENAME_MAX);
678: #else
679: snprintf(psGlobalConfig, FILENAME_MAX, CONFDIR"%chatari.cfg", PATHSEP);
680: #endif
681: /* Try to load the global configuration file */
682: Configuration_Load(psGlobalConfig);
683:
684: free(psGlobalConfig);
685: }
686:
687: /* Now try the users configuration file */
688: Configuration_Load(NULL);
689: }
690:
691: /*-----------------------------------------------------------------------*/
692: /**
693: * Set TOS etc information and initial help message
694: */
695: static void Main_StatusbarSetup(void)
696: {
697: const char *name = NULL;
698: SDLKey key;
699:
700: key = ConfigureParams.Shortcut.withoutModifier[SHORTCUT_OPTIONS];
701: if (!key)
702: key = ConfigureParams.Shortcut.withModifier[SHORTCUT_OPTIONS];
703: if (key)
704: name = SDL_GetKeyName(key);
705: if (name)
706: {
707: char message[24], *keyname;
1.1.1.18 root 708: #ifdef _MUDFLAP
709: __mf_register(name, 32, __MF_TYPE_GUESS, "SDL keyname");
710: #endif
1.1.1.15 root 711: keyname = Str_ToUpper(strdup(name));
712: snprintf(message, sizeof(message), "Press %s for Options", keyname);
713: free(keyname);
714:
715: Statusbar_AddMessage(message, 6000);
716: }
717: /* update information loaded by Main_Init() */
718: Statusbar_UpdateInfo();
719: }
720:
721: /*-----------------------------------------------------------------------*/
722: /**
1.1.1.13 root 723: * Main
1.1.1.15 root 724: *
725: * Note: 'argv' cannot be declared const, MinGW would then fail to link.
1.1.1.13 root 726: */
1.1 root 727: int main(int argc, char *argv[])
728: {
1.1.1.13 root 729: /* Generate random seed */
730: srand(time(NULL));
731:
732: /* Initialize directory strings */
733: Paths_Init(argv[0]);
734:
735: /* Set default configuration values: */
736: Configuration_SetDefault();
1.1.1.8 root 737:
1.1.1.13 root 738: /* Now load the values from the configuration file */
1.1.1.15 root 739: Main_LoadInitialConfig();
1.1 root 740:
1.1.1.15 root 741: /* Check for any passed parameters */
1.1.1.19! root 742: if (!Opt_ParseParameters(argc, (const char * const *)argv))
1.1.1.15 root 743: {
744: return 1;
745: }
1.1.1.17 root 746: /* monitor type option might require "reset" -> true */
747: Configuration_Apply(true);
1.1.1.2 root 748:
1.1.1.13 root 749: #ifdef WIN32
750: Win_OpenCon();
751: #endif
1.1.1.7 root 752:
1.1.1.13 root 753: /* Needed on maemo but useful also with normal X11 window managers
754: * for window grouping when you have multiple Hatari SDL windows open
755: */
756: #if HAVE_SETENV
757: setenv("SDL_VIDEO_X11_WMCLASS", "hatari", 1);
758: #endif
1.1 root 759:
1.1.1.13 root 760: /* Init emulator system */
761: Main_Init();
1.1 root 762:
1.1.1.15 root 763: /* Set initial Statusbar information */
764: Main_StatusbarSetup();
765:
1.1.1.13 root 766: /* Check if SDL_Delay is accurate */
767: Main_CheckForAccurateDelays();
1.1.1.12 root 768:
1.1.1.18 root 769: if ( AviRecordOnStartup ) /* Immediatly starts avi recording ? */
1.1.1.19! root 770: Avi_StartRecording ( ConfigureParams.Video.AviRecordFile , ConfigureParams.Screen.bCrop ,
! 771: ConfigureParams.Video.AviRecordFps == 0 ?
! 772: ClocksTimings_GetVBLPerSec ( ConfigureParams.System.nMachineType , nScreenRefreshRate ) :
! 773: (Uint32)ConfigureParams.Video.AviRecordFps << CLOCKS_TIMINGS_SHIFT_VBL ,
! 774: 1 << CLOCKS_TIMINGS_SHIFT_VBL ,
! 775: ConfigureParams.Video.AviRecordVcodec );
1.1.1.18 root 776:
1.1.1.13 root 777: /* Run emulation */
778: Main_UnPauseEmulation();
779: M68000_Start(); /* Start emulation */
1.1 root 780:
1.1.1.18 root 781: if (bRecordingAvi)
782: {
783: /* cleanly close the avi file */
784: Statusbar_AddMessage("Finishing AVI file...", 100);
785: Statusbar_Update(sdlscrn);
786: Avi_StopRecording();
787: }
1.1.1.13 root 788: /* Un-init emulation system */
789: Main_UnInit();
1.1 root 790:
1.1.1.13 root 791: return 0;
1.1 root 792: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.