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