|
|
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:
1.1.1.21! root 295: DestTicks += pulse_swallowing_count; /* audio.c - Audio_CallBack() */
! 296:
1.1.1.19 root 297: nDelay = DestTicks - CurrentTicks;
1.1.1.13 root 298:
1.1.1.15 root 299: /* Do not wait if we are in fast forward mode or if we are totally out of sync */
1.1.1.17 root 300: if (ConfigureParams.System.bFastForward == true
1.1.1.19 root 301: || nDelay < -4*FrameDuration_micro)
1.1.1.13 root 302: {
1.1.1.17 root 303: if (ConfigureParams.System.bFastForward == true)
304: {
305: if (!nFirstMilliTick)
306: nFirstMilliTick = Main_GetTicks();
307: }
1.1.1.15 root 308: if (nFrameSkips < ConfigureParams.Screen.nFrameSkips)
309: {
310: nFrameSkips += 1;
1.1.1.17 root 311: // Log_Printf(LOG_DEBUG, "Increased frameskip to %d\n", nFrameSkips);
1.1.1.15 root 312: }
1.1.1.19 root 313: /* Only update DestTicks for next VBL */
314: DestTicks = CurrentTicks + FrameDuration_micro;
1.1.1.13 root 315: return;
316: }
1.1.1.15 root 317: /* If automatic frameskip is enabled and delay's more than twice
318: * the effect of single frameskip, decrease frameskip
319: */
320: if (nFrameSkips > 0
321: && ConfigureParams.Screen.nFrameSkips >= AUTO_FRAMESKIP_LIMIT
1.1.1.19 root 322: && 2*nDelay > FrameDuration_micro/nFrameSkips)
1.1.1.15 root 323: {
324: nFrameSkips -= 1;
1.1.1.17 root 325: // Log_Printf(LOG_DEBUG, "Decreased frameskip to %d\n", nFrameSkips);
1.1.1.15 root 326: }
1.1.1.12 root 327:
1.1.1.13 root 328: if (bAccurateDelays)
329: {
330: /* Accurate sleeping is possible -> use SDL_Delay to free the CPU */
1.1.1.19 root 331: if (nDelay > 1000)
332: Time_Delay(nDelay - 1000);
1.1.1.13 root 333: }
334: else
335: {
336: /* No accurate SDL_Delay -> only wait if more than 5ms to go... */
1.1.1.19 root 337: if (nDelay > 5000)
338: Time_Delay(nDelay<10000 ? nDelay-1000 : 9000);
1.1.1.13 root 339: }
340:
341: /* Now busy-wait for the right tick: */
342: while (nDelay > 0)
343: {
1.1.1.19 root 344: CurrentTicks = Time_GetTicks();
345: nDelay = DestTicks - CurrentTicks;
1.1.1.13 root 346: }
347:
1.1.1.19 root 348: //printf ( "tick %lld\n" , CurrentTicks );
349: /* Update DestTicks for next VBL */
350: DestTicks += FrameDuration_micro;
1.1.1.12 root 351: }
352:
353:
354: /*-----------------------------------------------------------------------*/
1.1.1.13 root 355: /**
356: * Since SDL_Delay and friends are very inaccurate on some systems, we have
357: * to check if we can rely on this delay function.
358: */
1.1.1.12 root 359: static void Main_CheckForAccurateDelays(void)
360: {
1.1.1.13 root 361: int nStartTicks, nEndTicks;
1.1.1.12 root 362:
1.1.1.13 root 363: /* Force a task switch now, so we have a longer timeslice afterwards */
364: SDL_Delay(10);
1.1.1.12 root 365:
1.1.1.13 root 366: nStartTicks = SDL_GetTicks();
367: SDL_Delay(1);
368: nEndTicks = SDL_GetTicks();
369:
370: /* If the delay took longer than 10ms, we are on an inaccurate system! */
371: bAccurateDelays = ((nEndTicks - nStartTicks) < 9);
372:
373: if (bAccurateDelays)
374: Log_Printf(LOG_DEBUG, "Host system has accurate delays. (%d)\n", nEndTicks - nStartTicks);
375: else
1.1.1.15 root 376: Log_Printf(LOG_WARN, "Host system does not have accurate delays. (%d)\n", nEndTicks - nStartTicks);
1.1.1.12 root 377: }
378:
379:
1.1 root 380: /* ----------------------------------------------------------------------- */
1.1.1.13 root 381: /**
382: * Set mouse pointer to new coordinates and set flag to ignore the mouse event
383: * that is generated by SDL_WarpMouse().
384: */
1.1.1.9 root 385: void Main_WarpMouse(int x, int y)
386: {
1.1.1.13 root 387: SDL_WarpMouse(x, y); /* Set mouse pointer to new position */
1.1.1.17 root 388: bIgnoreNextMouseMotion = true; /* Ignore mouse motion event from SDL_WarpMouse */
1.1.1.9 root 389: }
390:
391:
392: /* ----------------------------------------------------------------------- */
1.1.1.13 root 393: /**
394: * Handle mouse motion event.
395: */
1.1.1.12 root 396: static void Main_HandleMouseMotion(SDL_Event *pEvent)
397: {
398: int dx, dy;
399: static int ax = 0, ay = 0;
400:
1.1.1.17 root 401: /* Ignore motion when position has changed right after a reset or TOS
402: * (especially version 4.04) might get confused and play key clicks */
403: if (bIgnoreNextMouseMotion || nVBLs < 10)
1.1.1.12 root 404: {
1.1.1.17 root 405: bIgnoreNextMouseMotion = false;
1.1.1.12 root 406: return;
407: }
408:
409: dx = pEvent->motion.xrel;
410: dy = pEvent->motion.yrel;
411:
1.1.1.13 root 412: /* In zoomed low res mode, we divide dx and dy by the zoom factor so that
413: * the ST mouse cursor stays in sync with the host mouse. However, we have
414: * to take care of lowest bit of dx and dy which will get lost when
415: * dividing. So we store these bits in ax and ay and add them to dx and dy
416: * the next time. */
417: if (nScreenZoomX != 1)
418: {
1.1.1.12 root 419: dx += ax;
1.1.1.13 root 420: ax = dx % nScreenZoomX;
421: dx /= nScreenZoomX;
1.1.1.12 root 422: }
1.1.1.13 root 423: if (nScreenZoomY != 1)
1.1.1.12 root 424: {
425: dy += ay;
1.1.1.13 root 426: ay = dy % nScreenZoomY;
427: dy /= nScreenZoomY;
1.1.1.12 root 428: }
429:
430: KeyboardProcessor.Mouse.dx += dx;
431: KeyboardProcessor.Mouse.dy += dy;
432: }
433:
434:
435: /* ----------------------------------------------------------------------- */
1.1.1.13 root 436: /**
437: * SDL message handler.
438: * Here we process the SDL events (keyboard, mouse, ...) and map it to
439: * Atari IKBD events.
440: */
1.1.1.8 root 441: void Main_EventHandler(void)
1.1 root 442: {
1.1.1.17 root 443: bool bContinueProcessing;
1.1.1.13 root 444: SDL_Event event;
1.1.1.17 root 445: int events;
446: int remotepause;
447:
1.1.1.15 root 448: do
1.1.1.13 root 449: {
1.1.1.17 root 450: bContinueProcessing = false;
451:
1.1.1.15 root 452: /* check remote process control */
1.1.1.17 root 453: remotepause = Control_CheckUpdates();
1.1.1.15 root 454:
455: if ( bEmulationActive || remotepause )
456: {
1.1.1.17 root 457: events = SDL_PollEvent(&event);
1.1.1.15 root 458: }
459: else
460: {
461: ShortCut_ActKey();
462: /* last (shortcut) event activated emulation? */
463: if ( bEmulationActive )
464: break;
1.1.1.17 root 465: events = SDL_WaitEvent(&event);
1.1.1.15 root 466: }
1.1.1.17 root 467: if (!events)
1.1.1.15 root 468: {
1.1.1.17 root 469: /* no events -> if emulation is active or
470: * user is quitting -> return from function.
471: */
1.1.1.15 root 472: continue;
473: }
1.1.1.13 root 474: switch (event.type)
475: {
1.1 root 476:
1.1.1.13 root 477: case SDL_QUIT:
478: Main_RequestQuit();
479: break;
1.1.1.17 root 480:
1.1.1.13 root 481: case SDL_MOUSEMOTION: /* Read/Update internal mouse position */
482: Main_HandleMouseMotion(&event);
1.1.1.17 root 483: bContinueProcessing = true;
1.1.1.13 root 484: break;
485:
486: case SDL_MOUSEBUTTONDOWN:
487: if (event.button.button == SDL_BUTTON_LEFT)
488: {
489: if (Keyboard.LButtonDblClk == 0)
490: Keyboard.bLButtonDown |= BUTTON_MOUSE; /* Set button down flag */
491: }
492: else if (event.button.button == SDL_BUTTON_RIGHT)
493: {
494: Keyboard.bRButtonDown |= BUTTON_MOUSE;
495: }
496: else if (event.button.button == SDL_BUTTON_MIDDLE)
497: {
498: /* Start double-click sequence in emulation time */
499: Keyboard.LButtonDblClk = 1;
500: }
501: else if (event.button.button == SDL_BUTTON_WHEELDOWN)
502: {
503: /* Simulate pressing the "cursor down" key */
1.1.1.17 root 504: IKBD_PressSTKey(0x50, true);
1.1.1.13 root 505: }
506: else if (event.button.button == SDL_BUTTON_WHEELUP)
507: {
508: /* Simulate pressing the "cursor up" key */
1.1.1.17 root 509: IKBD_PressSTKey(0x48, true);
1.1.1.13 root 510: }
511: break;
512:
513: case SDL_MOUSEBUTTONUP:
514: if (event.button.button == SDL_BUTTON_LEFT)
515: {
516: Keyboard.bLButtonDown &= ~BUTTON_MOUSE;
517: }
518: else if (event.button.button == SDL_BUTTON_RIGHT)
519: {
520: Keyboard.bRButtonDown &= ~BUTTON_MOUSE;
521: }
522: else if (event.button.button == SDL_BUTTON_WHEELDOWN)
523: {
524: /* Simulate releasing the "cursor down" key */
1.1.1.17 root 525: IKBD_PressSTKey(0x50, false);
1.1.1.13 root 526: }
527: else if (event.button.button == SDL_BUTTON_WHEELUP)
528: {
529: /* Simulate releasing the "cursor up" key */
1.1.1.17 root 530: IKBD_PressSTKey(0x48, false);
1.1.1.13 root 531: }
532: break;
533:
534: case SDL_KEYDOWN:
535: Keymap_KeyDown(&event.key.keysym);
536: break;
537:
538: case SDL_KEYUP:
539: Keymap_KeyUp(&event.key.keysym);
540: break;
1.1.1.17 root 541:
542: default:
543: /* don't let unknown events delay event processing */
544: bContinueProcessing = true;
545: break;
1.1.1.13 root 546: }
1.1.1.17 root 547: } while (bContinueProcessing || !(bEmulationActive || bQuitProgram));
1.1.1.13 root 548: }
549:
550:
551: /*-----------------------------------------------------------------------*/
552: /**
1.1.1.19 root 553: * Set Hatari window title. Use NULL for default
554: */
555: void Main_SetTitle(const char *title)
556: {
557: if (title)
558: SDL_WM_SetCaption(title, "Hatari");
559: else
560: SDL_WM_SetCaption(PROG_NAME, "Hatari");
561: }
562:
563: /*-----------------------------------------------------------------------*/
564: /**
1.1.1.13 root 565: * Initialise emulation
566: */
1.1.1.8 root 567: static void Main_Init(void)
1.1 root 568: {
1.1.1.13 root 569: /* Open debug log file */
1.1.1.15 root 570: if (!Log_Init())
571: {
572: fprintf(stderr, "Logging/tracing initialization failed\n");
573: exit(-1);
574: }
1.1.1.13 root 575: Log_Printf(LOG_INFO, PROG_NAME ", compiled on: " __DATE__ ", " __TIME__ "\n");
576:
577: /* Init SDL's video subsystem. Note: Audio and joystick subsystems
578: will be initialized later (failures there are not fatal). */
1.1.1.18 root 579: if (SDL_Init(SDL_INIT_VIDEO | Opt_GetNoParachuteFlag()) < 0)
1.1.1.13 root 580: {
581: fprintf(stderr, "Could not initialize the SDL library:\n %s\n", SDL_GetError() );
582: exit(-1);
583: }
1.1.1.19 root 584: ClocksTimings_InitMachine ( ConfigureParams.System.nMachineType );
585: Resolution_Init();
1.1.1.13 root 586: SDLGui_Init();
587: Printer_Init();
588: RS232_Init();
589: Midi_Init();
1.1.1.20 root 590: Control_CheckUpdates(); /* enable window embedding? */
1.1.1.13 root 591: Screen_Init();
1.1.1.19 root 592: Main_SetTitle(NULL);
1.1.1.13 root 593: HostScreen_Init();
1.1.1.18 root 594: DSP_Init();
1.1.1.13 root 595: Floppy_Init();
1.1.1.18 root 596: M68000_Init(); /* Init CPU emulation */
1.1.1.13 root 597: Audio_Init();
1.1.1.18 root 598: DmaSnd_Init();
1.1.1.13 root 599: Keymap_Init();
600:
601: /* Init HD emulation */
1.1.1.18 root 602: HDC_Init();
1.1.1.16 root 603: Ide_Init();
1.1.1.13 root 604: GemDOS_Init();
605: if (ConfigureParams.HardDisk.bUseHardDiskDirectories)
606: {
1.1.1.18 root 607: /* uses variables set by HDC_Init()! */
1.1.1.13 root 608: GemDOS_InitDrives();
609: }
610:
611: if (Reset_Cold()) /* Reset all systems, load TOS image */
612: {
613: /* If loading of the TOS failed, we bring up the GUI to let the
614: * user choose another TOS ROM file. */
615: Dialog_DoProperty();
616: }
617: if (!bTosImageLoaded || bQuitProgram)
618: {
619: fprintf(stderr, "Failed to load TOS image!\n");
620: SDL_Quit();
621: exit(-2);
622: }
623:
624: IoMem_Init();
625: NvRam_Init();
626: Joy_Init();
627: Sound_Init();
1.1.1.18 root 628:
629: /* done as last, needs CPU & DSP running... */
630: DebugUI_Init();
1.1 root 631: }
632:
1.1.1.6 root 633:
1.1.1.2 root 634: /*-----------------------------------------------------------------------*/
1.1.1.13 root 635: /**
636: * Un-Initialise emulation
637: */
1.1.1.8 root 638: static void Main_UnInit(void)
1.1 root 639: {
1.1.1.13 root 640: Screen_ReturnFromFullScreen();
641: Floppy_UnInit();
642: HDC_UnInit();
643: Midi_UnInit();
644: RS232_UnInit();
645: Printer_UnInit();
646: IoMem_UnInit();
647: NvRam_UnInit();
648: GemDOS_UnInitDrives();
1.1.1.16 root 649: Ide_UnInit();
1.1.1.13 root 650: Joy_UnInit();
651: if (Sound_AreWeRecording())
652: Sound_EndRecording();
653: Audio_UnInit();
654: SDLGui_UnInit();
1.1.1.18 root 655: DSP_UnInit();
1.1.1.15 root 656: HostScreen_UnInit();
1.1.1.13 root 657: Screen_UnInit();
658: Exit680x0();
1.1 root 659:
1.1.1.13 root 660: /* SDL uninit: */
661: SDL_Quit();
1.1.1.10 root 662:
1.1.1.13 root 663: /* Close debug log file */
664: Log_UnInit();
1.1 root 665: }
666:
1.1.1.6 root 667:
1.1.1.2 root 668: /*-----------------------------------------------------------------------*/
1.1.1.13 root 669: /**
1.1.1.15 root 670: * Load initial configuration file(s)
671: */
672: static void Main_LoadInitialConfig(void)
673: {
674: char *psGlobalConfig;
675:
676: psGlobalConfig = malloc(FILENAME_MAX);
677: if (psGlobalConfig)
678: {
679: #if defined(__AMIGAOS4__)
680: strncpy(psGlobalConfig, CONFDIR"hatari.cfg", FILENAME_MAX);
681: #else
682: snprintf(psGlobalConfig, FILENAME_MAX, CONFDIR"%chatari.cfg", PATHSEP);
683: #endif
684: /* Try to load the global configuration file */
685: Configuration_Load(psGlobalConfig);
686:
687: free(psGlobalConfig);
688: }
689:
690: /* Now try the users configuration file */
691: Configuration_Load(NULL);
692: }
693:
694: /*-----------------------------------------------------------------------*/
695: /**
696: * Set TOS etc information and initial help message
697: */
698: static void Main_StatusbarSetup(void)
699: {
700: const char *name = NULL;
701: SDLKey key;
702:
703: key = ConfigureParams.Shortcut.withoutModifier[SHORTCUT_OPTIONS];
704: if (!key)
705: key = ConfigureParams.Shortcut.withModifier[SHORTCUT_OPTIONS];
706: if (key)
707: name = SDL_GetKeyName(key);
708: if (name)
709: {
710: char message[24], *keyname;
1.1.1.18 root 711: #ifdef _MUDFLAP
1.1.1.21! root 712: __mf_register((void*)name, 32, __MF_TYPE_GUESS, "SDL keyname");
1.1.1.18 root 713: #endif
1.1.1.15 root 714: keyname = Str_ToUpper(strdup(name));
715: snprintf(message, sizeof(message), "Press %s for Options", keyname);
716: free(keyname);
717:
718: Statusbar_AddMessage(message, 6000);
719: }
720: /* update information loaded by Main_Init() */
721: Statusbar_UpdateInfo();
722: }
723:
724: /*-----------------------------------------------------------------------*/
725: /**
1.1.1.13 root 726: * Main
1.1.1.15 root 727: *
728: * Note: 'argv' cannot be declared const, MinGW would then fail to link.
1.1.1.13 root 729: */
1.1 root 730: int main(int argc, char *argv[])
731: {
1.1.1.13 root 732: /* Generate random seed */
733: srand(time(NULL));
734:
735: /* Initialize directory strings */
736: Paths_Init(argv[0]);
737:
738: /* Set default configuration values: */
739: Configuration_SetDefault();
1.1.1.8 root 740:
1.1.1.13 root 741: /* Now load the values from the configuration file */
1.1.1.15 root 742: Main_LoadInitialConfig();
1.1 root 743:
1.1.1.15 root 744: /* Check for any passed parameters */
1.1.1.19 root 745: if (!Opt_ParseParameters(argc, (const char * const *)argv))
1.1.1.15 root 746: {
747: return 1;
748: }
1.1.1.17 root 749: /* monitor type option might require "reset" -> true */
750: Configuration_Apply(true);
1.1.1.2 root 751:
1.1.1.13 root 752: #ifdef WIN32
753: Win_OpenCon();
754: #endif
1.1.1.7 root 755:
1.1.1.13 root 756: #if HAVE_SETENV
1.1.1.20 root 757: /* Needed on maemo but useful also with normal X11 window managers for
758: * window grouping when you have multiple Hatari SDL windows open */
1.1.1.13 root 759: setenv("SDL_VIDEO_X11_WMCLASS", "hatari", 1);
1.1.1.20 root 760:
761: /* Needed for proper behavior of Caps Lock on some systems */
762: setenv("SDL_DISABLE_LOCK_KEYS", "1", 1);
1.1.1.13 root 763: #endif
1.1 root 764:
1.1.1.13 root 765: /* Init emulator system */
766: Main_Init();
1.1 root 767:
1.1.1.15 root 768: /* Set initial Statusbar information */
769: Main_StatusbarSetup();
770:
1.1.1.13 root 771: /* Check if SDL_Delay is accurate */
772: Main_CheckForAccurateDelays();
1.1.1.12 root 773:
1.1.1.18 root 774: if ( AviRecordOnStartup ) /* Immediatly starts avi recording ? */
1.1.1.19 root 775: Avi_StartRecording ( ConfigureParams.Video.AviRecordFile , ConfigureParams.Screen.bCrop ,
776: ConfigureParams.Video.AviRecordFps == 0 ?
777: ClocksTimings_GetVBLPerSec ( ConfigureParams.System.nMachineType , nScreenRefreshRate ) :
778: (Uint32)ConfigureParams.Video.AviRecordFps << CLOCKS_TIMINGS_SHIFT_VBL ,
779: 1 << CLOCKS_TIMINGS_SHIFT_VBL ,
780: ConfigureParams.Video.AviRecordVcodec );
1.1.1.18 root 781:
1.1.1.13 root 782: /* Run emulation */
783: Main_UnPauseEmulation();
784: M68000_Start(); /* Start emulation */
1.1 root 785:
1.1.1.18 root 786: if (bRecordingAvi)
787: {
788: /* cleanly close the avi file */
789: Statusbar_AddMessage("Finishing AVI file...", 100);
790: Statusbar_Update(sdlscrn);
791: Avi_StopRecording();
792: }
1.1.1.13 root 793: /* Un-init emulation system */
794: Main_UnInit();
1.1 root 795:
1.1.1.13 root 796: return 0;
1.1 root 797: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.