Annotation of hatari/src/main.c, revision 1.1.1.12

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.