Annotation of hatari/src/memorySnapShot.c, revision 1.1.1.21

1.1       root        1: /*
1.1.1.4   root        2:   Hatari - memorySnapShot.c
                      3: 
1.1.1.19  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       root        6: 
                      7:   Memory Snapshot
                      8: 
1.1.1.5   root        9:   This handles the saving/restoring of the emulator's state so any game or
                     10:   application can be saved and restored at any time. This is quite complicated
                     11:   as we need to store all STRam, all chip states, all emulation variables and
                     12:   then things get really complicated as we need to restore file handles
1.1       root       13:   and such like.
1.1.1.5   root       14:   To help keep things simple each file has one function which is used to
                     15:   save/restore all variables that are local to it. We use one function to
                     16:   reduce redundancy and the function 'MemorySnapShot_Store' decides if it
                     17:   should save or restore the data.
1.1       root       18: */
1.1.1.13  root       19: const char MemorySnapShot_fileid[] = "Hatari memorySnapShot.c : " __DATE__ " " __TIME__;
1.1.1.10  root       20: 
1.1.1.4   root       21: #include <SDL_types.h>
1.1.1.5   root       22: #include <errno.h>
1.1       root       23: 
                     24: #include "main.h"
1.1.1.5   root       25: #include "blitter.h"
1.1.1.8   root       26: #include "configuration.h"
1.1.1.14  root       27: #include "debugui.h"
1.1.1.8   root       28: #include "dmaSnd.h"
1.1       root       29: #include "fdc.h"
                     30: #include "file.h"
                     31: #include "floppy.h"
1.1.1.20  root       32: #include "floppy_ipf.h"
                     33: #include "floppy_stx.h"
1.1       root       34: #include "gemdos.h"
1.1.1.19  root       35: #include "acia.h"
1.1       root       36: #include "ikbd.h"
1.1.1.15  root       37: #include "cycInt.h"
                     38: #include "cycles.h"
1.1.1.10  root       39: #include "ioMem.h"
1.1.1.7   root       40: #include "log.h"
1.1       root       41: #include "m68000.h"
                     42: #include "memorySnapShot.h"
                     43: #include "mfp.h"
1.1.1.21! root       44: #include "midi.h"
1.1       root       45: #include "psg.h"
                     46: #include "reset.h"
                     47: #include "sound.h"
1.1.1.14  root       48: #include "str.h"
1.1.1.15  root       49: #include "stMemory.h"
1.1       root       50: #include "tos.h"
1.1.1.16  root       51: #include "screen.h"
1.1       root       52: #include "video.h"
1.1.1.14  root       53: #include "falcon/dsp.h"
1.1.1.16  root       54: #include "falcon/crossbar.h"
                     55: #include "falcon/videl.h"
                     56: #include "statusbar.h"
1.1.1.21! root       57: #include "cart.h"
1.1.1.2   root       58: 
1.1       root       59: 
1.1.1.21! root       60: #define VERSION_STRING      "1.9.0"   /* Version number of compatible memory snapshots - Always 6 bytes (inc' NULL) */
        !            61: #define SNAPSHOT_MAGIC      0xDeadBeef
1.1.1.6   root       62: 
1.1.1.20  root       63: #if HAVE_LIBZ
1.1.1.8   root       64: #define COMPRESS_MEMORYSNAPSHOT       /* Compress snapshots to reduce disk space used */
1.1.1.20  root       65: #endif
1.1       root       66: 
1.1.1.5   root       67: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1       root       68: 
1.1.1.16  root       69: /* Remove possible conflicting mkdir declaration from cpu/sysdeps.h */
                     70: #undef mkdir
1.1.1.5   root       71: #include <zlib.h>
                     72: typedef gzFile MSS_File;
                     73: 
                     74: #else
                     75: 
                     76: typedef FILE* MSS_File;
1.1       root       77: 
1.1.1.5   root       78: #endif
                     79: 
                     80: 
                     81: static MSS_File CaptureFile;
1.1.1.12  root       82: static bool bCaptureSave, bCaptureError;
1.1.1.5   root       83: 
                     84: 
                     85: /*-----------------------------------------------------------------------*/
1.1.1.10  root       86: /**
                     87:  * Open file.
                     88:  */
1.1.1.7   root       89: static MSS_File MemorySnapShot_fopen(const char *pszFileName, const char *pszMode)
1.1       root       90: {
                     91: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1.1.5   root       92:        return gzopen(pszFileName, pszMode);
                     93: #else
                     94:        return fopen(pszFileName, pszMode);
                     95: #endif
1.1       root       96: }
                     97: 
1.1.1.5   root       98: 
                     99: /*-----------------------------------------------------------------------*/
1.1.1.10  root      100: /**
                    101:  * Close file.
                    102:  */
1.1.1.5   root      103: static void MemorySnapShot_fclose(MSS_File fhndl)
1.1       root      104: {
                    105: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1.1.5   root      106:        gzclose(fhndl);
                    107: #else
                    108:        fclose(fhndl);
                    109: #endif
1.1       root      110: }
                    111: 
1.1.1.5   root      112: 
                    113: /*-----------------------------------------------------------------------*/
1.1.1.10  root      114: /**
                    115:  * Read from file.
                    116:  */
1.1.1.5   root      117: static int MemorySnapShot_fread(MSS_File fhndl, char *buf, int len)
1.1       root      118: {
                    119: #ifdef COMPRESS_MEMORYSNAPSHOT
1.1.1.5   root      120:        return gzread(fhndl, buf, len);
                    121: #else
                    122:        return fread(buf, 1, len, fhndl);
                    123: #endif
1.1       root      124: }
                    125: 
1.1.1.5   root      126: 
                    127: /*-----------------------------------------------------------------------*/
1.1.1.10  root      128: /**
                    129:  * Write data to file.
                    130:  */
1.1.1.7   root      131: static int MemorySnapShot_fwrite(MSS_File fhndl, const char *buf, int len)
1.1       root      132: {
1.1.1.5   root      133: #ifdef COMPRESS_MEMORYSNAPSHOT
                    134:        return gzwrite(fhndl, buf, len);
                    135: #else
                    136:        return fwrite(buf, 1, len, fhndl);
                    137: #endif
1.1       root      138: }
                    139: 
1.1.1.5   root      140: 
                    141: /*-----------------------------------------------------------------------*/
1.1.1.10  root      142: /**
1.1.1.20  root      143:  * Seek into file from current position
                    144:  */
                    145: static int MemorySnapShot_fseek(MSS_File fhndl, int pos)
                    146: {
                    147: #ifdef COMPRESS_MEMORYSNAPSHOT
                    148:        return (int)gzseek(fhndl, pos, SEEK_CUR);       /* return -1 if error, new position >=0 if OK */
                    149: #else
1.1.1.21! root      150:        return fseek(fhndl, pos, SEEK_CUR);             /* return -1 if error, 0 if OK */
1.1.1.20  root      151: #endif
                    152: }
                    153: 
                    154: 
                    155: /*-----------------------------------------------------------------------*/
                    156: /**
1.1.1.10  root      157:  * Open/Create snapshot file, and set flag so 'MemorySnapShot_Store' knows
                    158:  * how to handle data.
                    159:  */
1.1.1.12  root      160: static bool MemorySnapShot_OpenFile(const char *pszFileName, bool bSave)
1.1       root      161: {
1.1.1.16  root      162:        char VersionString[] = VERSION_STRING;
1.1.1.21! root      163: #if ENABLE_WINUAE_CPU
        !           164: # define CORE_VERSION 1
        !           165: #else
        !           166: # define CORE_VERSION 0
        !           167: #endif
        !           168:        Uint8 CpuCore;
1.1.1.3   root      169: 
1.1.1.5   root      170:        /* Set error */
1.1.1.14  root      171:        bCaptureError = false;
1.1       root      172: 
1.1.1.16  root      173:        /* after opening file, set bCaptureSave to indicate whether
                    174:         * 'MemorySnapShot_Store' should load from or save to a file
                    175:         */
1.1.1.5   root      176:        if (bSave)
                    177:        {
1.1.1.16  root      178:                if (!File_QueryOverwrite(pszFileName))
                    179:                        return false;
                    180: 
1.1.1.5   root      181:                /* Save */
                    182:                CaptureFile = MemorySnapShot_fopen(pszFileName, "wb");
                    183:                if (!CaptureFile)
                    184:                {
                    185:                        fprintf(stderr, "Failed to open save file '%s': %s\n",
                    186:                                pszFileName, strerror(errno));
1.1.1.14  root      187:                        bCaptureError = true;
                    188:                        return false;
1.1.1.5   root      189:                }
1.1.1.14  root      190:                bCaptureSave = true;
1.1.1.5   root      191:                /* Store version string */
1.1.1.16  root      192:                MemorySnapShot_Store(VersionString, sizeof(VersionString));
1.1.1.21! root      193:                /* Store CPU core version */
        !           194:                CpuCore = CORE_VERSION;
        !           195:                MemorySnapShot_Store(&CpuCore, sizeof(CpuCore));
1.1.1.5   root      196:        }
                    197:        else
                    198:        {
                    199:                /* Restore */
                    200:                CaptureFile = MemorySnapShot_fopen(pszFileName, "rb");
                    201:                if (!CaptureFile)
                    202:                {
                    203:                        fprintf(stderr, "Failed to open file '%s': %s\n",
                    204:                                pszFileName, strerror(errno));
1.1.1.14  root      205:                        bCaptureError = true;
                    206:                        return false;
1.1.1.5   root      207:                }
1.1.1.14  root      208:                bCaptureSave = false;
1.1.1.5   root      209:                /* Restore version string */
1.1.1.16  root      210:                MemorySnapShot_Store(VersionString, sizeof(VersionString));
1.1.1.5   root      211:                /* Does match current version? */
1.1.1.21! root      212:                if (strcmp(VersionString, VERSION_STRING))
1.1.1.5   root      213:                {
                    214:                        /* No, inform user and error */
1.1.1.21! root      215:                        Log_AlertDlg(LOG_ERROR,
        !           216:                                     "Unable to restore Hatari memory state.\n"
        !           217:                                     "Given state file is compatible only with\n"
        !           218:                                     "Hatari version " VERSION_STRING ".");
        !           219:                        bCaptureError = true;
        !           220:                        return false;
        !           221:                }
        !           222:                /* Check CPU core version */
        !           223:                MemorySnapShot_Store(&CpuCore, sizeof(CpuCore));
        !           224:                if (CpuCore != CORE_VERSION)
        !           225:                {
        !           226:                        Log_AlertDlg(LOG_ERROR,
        !           227:                                     "Unable to restore Hatari memory state.\n"
        !           228:                                     "Given state file is for different Hatari\n"
        !           229:                                     "CPU core version.");
1.1.1.14  root      230:                        bCaptureError = true;
                    231:                        return false;
1.1.1.5   root      232:                }
                    233:        }
1.1       root      234: 
1.1.1.5   root      235:        /* All OK */
1.1.1.14  root      236:        return true;
1.1       root      237: }
                    238: 
1.1.1.5   root      239: 
                    240: /*-----------------------------------------------------------------------*/
1.1.1.10  root      241: /**
                    242:  * Close snapshot file.
                    243:  */
1.1.1.5   root      244: static void MemorySnapShot_CloseFile(void)
1.1       root      245: {
1.1.1.5   root      246:        MemorySnapShot_fclose(CaptureFile);
1.1       root      247: }
                    248: 
1.1.1.5   root      249: 
                    250: /*-----------------------------------------------------------------------*/
1.1.1.10  root      251: /**
1.1.1.20  root      252:  * Skip Nb bytes when reading from/writing to file.
                    253:  */
                    254: void MemorySnapShot_Skip(int Nb)
                    255: {
                    256:        int res;
                    257: 
                    258:        /* Check no file errors */
                    259:        if (CaptureFile != NULL)
                    260:        {
                    261:                res = MemorySnapShot_fseek(CaptureFile, Nb);
                    262: 
                    263:                /* Did seek OK? */
                    264:                if (res < 0)
                    265:                        bCaptureError = true;
                    266:        }
                    267: }
                    268: 
                    269: 
                    270: /*-----------------------------------------------------------------------*/
                    271: /**
1.1.1.10  root      272:  * Save/Restore data to/from file.
                    273:  */
1.1       root      274: void MemorySnapShot_Store(void *pData, int Size)
                    275: {
1.1.1.5   root      276:        long nBytes;
1.1.1.3   root      277: 
1.1.1.5   root      278:        /* Check no file errors */
                    279:        if (CaptureFile != NULL)
                    280:        {
                    281:                /* Saving or Restoring? */
                    282:                if (bCaptureSave)
                    283:                        nBytes = MemorySnapShot_fwrite(CaptureFile, (char *)pData, Size);
                    284:                else
                    285:                        nBytes = MemorySnapShot_fread(CaptureFile, (char *)pData, Size);
                    286: 
                    287:                /* Did save OK? */
                    288:                if (nBytes != Size)
1.1.1.14  root      289:                        bCaptureError = true;
1.1.1.5   root      290:        }
1.1       root      291: }
                    292: 
1.1.1.5   root      293: 
                    294: /*-----------------------------------------------------------------------*/
1.1.1.10  root      295: /**
                    296:  * Save 'snapshot' of memory/chips/emulation variables
                    297:  */
1.1.1.12  root      298: void MemorySnapShot_Capture(const char *pszFileName, bool bConfirm)
1.1       root      299: {
1.1.1.21! root      300:        Uint32 magic = SNAPSHOT_MAGIC;
        !           301: 
1.1.1.5   root      302:        /* Set to 'saving' */
1.1.1.14  root      303:        if (MemorySnapShot_OpenFile(pszFileName, true))
1.1.1.5   root      304:        {
                    305:                /* Capture each files details */
1.1.1.14  root      306:                Configuration_MemorySnapShot_Capture(true);
                    307:                TOS_MemorySnapShot_Capture(true);
1.1.1.15  root      308:                STMemory_MemorySnapShot_Capture(true);
1.1.1.20  root      309:                Cycles_MemorySnapShot_Capture(true);                    /* Before fdc (for CyclesGlobalClockCounter) */
1.1.1.14  root      310:                FDC_MemorySnapShot_Capture(true);
                    311:                Floppy_MemorySnapShot_Capture(true);
1.1.1.20  root      312:                IPF_MemorySnapShot_Capture(true);                       /* After fdc/floppy are saved */
                    313:                STX_MemorySnapShot_Capture(true);                       /* After fdc/floppy are saved */
1.1.1.14  root      314:                GemDOS_MemorySnapShot_Capture(true);
1.1.1.19  root      315:                ACIA_MemorySnapShot_Capture(true);
1.1.1.14  root      316:                IKBD_MemorySnapShot_Capture(true);
1.1.1.21! root      317:                MIDI_MemorySnapShot_Capture(true);
1.1.1.15  root      318:                CycInt_MemorySnapShot_Capture(true);
1.1.1.14  root      319:                M68000_MemorySnapShot_Capture(true);
                    320:                MFP_MemorySnapShot_Capture(true);
                    321:                PSG_MemorySnapShot_Capture(true);
                    322:                Sound_MemorySnapShot_Capture(true);
                    323:                Video_MemorySnapShot_Capture(true);
                    324:                Blitter_MemorySnapShot_Capture(true);
                    325:                DmaSnd_MemorySnapShot_Capture(true);
1.1.1.16  root      326:                Crossbar_MemorySnapShot_Capture(true);
                    327:                VIDEL_MemorySnapShot_Capture(true);
1.1.1.14  root      328:                DSP_MemorySnapShot_Capture(true);
1.1.1.15  root      329:                DebugUI_MemorySnapShot_Capture(pszFileName, true);
1.1.1.16  root      330:                IoMem_MemorySnapShot_Capture(true);
1.1.1.21! root      331:                /* end marker */
        !           332:                MemorySnapShot_Store(&magic, sizeof(magic));
1.1.1.5   root      333:                /* And close */
                    334:                MemorySnapShot_CloseFile();
1.1.1.16  root      335:        } else {
                    336:                /* just canceled? */
                    337:                if (!bCaptureError)
                    338:                        return;
1.1.1.5   root      339:        }
                    340: 
                    341:        /* Did error */
                    342:        if (bCaptureError)
1.1.1.7   root      343:                Log_AlertDlg(LOG_ERROR, "Unable to save memory state to file.");
1.1.1.10  root      344:        else if (bConfirm)
1.1.1.7   root      345:                Log_AlertDlg(LOG_INFO, "Memory state file saved.");
1.1       root      346: }
                    347: 
1.1.1.5   root      348: 
                    349: /*-----------------------------------------------------------------------*/
1.1.1.10  root      350: /**
                    351:  * Restore 'snapshot' of memory/chips/emulation variables
                    352:  */
1.1.1.12  root      353: void MemorySnapShot_Restore(const char *pszFileName, bool bConfirm)
1.1       root      354: {
1.1.1.21! root      355:        Uint32 magic;
        !           356: 
1.1.1.5   root      357:        /* Set to 'restore' */
1.1.1.14  root      358:        if (MemorySnapShot_OpenFile(pszFileName, false))
1.1.1.5   root      359:        {
1.1.1.14  root      360:                Configuration_MemorySnapShot_Capture(false);
                    361:                TOS_MemorySnapShot_Capture(false);
1.1.1.10  root      362: 
1.1.1.5   root      363:                /* Reset emulator to get things running */
1.1.1.10  root      364:                IoMem_UnInit();  IoMem_Init();
1.1.1.5   root      365:                Reset_Cold();
                    366: 
                    367:                /* Capture each files details */
1.1.1.15  root      368:                STMemory_MemorySnapShot_Capture(false);
1.1.1.20  root      369:                Cycles_MemorySnapShot_Capture(false);                   /* Before fdc (for CyclesGlobalClockCounter) */
1.1.1.14  root      370:                FDC_MemorySnapShot_Capture(false);
                    371:                Floppy_MemorySnapShot_Capture(false);
1.1.1.20  root      372:                IPF_MemorySnapShot_Capture(false);                      /* After fdc/floppy are restored, as IPF depends on them */
                    373:                STX_MemorySnapShot_Capture(false);                      /* After fdc/floppy are restored, as STX depends on them */
1.1.1.14  root      374:                GemDOS_MemorySnapShot_Capture(false);
1.1.1.19  root      375:                ACIA_MemorySnapShot_Capture(false);
                    376:                IKBD_MemorySnapShot_Capture(false);                     /* After ACIA */
1.1.1.21! root      377:                MIDI_MemorySnapShot_Capture(false);
1.1.1.15  root      378:                CycInt_MemorySnapShot_Capture(false);
1.1.1.14  root      379:                M68000_MemorySnapShot_Capture(false);
                    380:                MFP_MemorySnapShot_Capture(false);
                    381:                PSG_MemorySnapShot_Capture(false);
                    382:                Sound_MemorySnapShot_Capture(false);
                    383:                Video_MemorySnapShot_Capture(false);
                    384:                Blitter_MemorySnapShot_Capture(false);
                    385:                DmaSnd_MemorySnapShot_Capture(false);
1.1.1.16  root      386:                Crossbar_MemorySnapShot_Capture(false);
                    387:                VIDEL_MemorySnapShot_Capture(false);
1.1.1.14  root      388:                DSP_MemorySnapShot_Capture(false);
1.1.1.15  root      389:                DebugUI_MemorySnapShot_Capture(pszFileName, false);
1.1.1.16  root      390:                IoMem_MemorySnapShot_Capture(false);
1.1.1.5   root      391: 
1.1.1.21! root      392:                /* version string check catches release-to-release
        !           393:                 * state changes, bCaptureError catches too short
        !           394:                 * state file, this check a too long state file.
        !           395:                 */
        !           396:                MemorySnapShot_Store(&magic, sizeof(magic));
        !           397:                if (!bCaptureError && magic != SNAPSHOT_MAGIC)
        !           398:                        bCaptureError = true;
        !           399: 
1.1.1.5   root      400:                /* And close */
                    401:                MemorySnapShot_CloseFile();
1.1.1.16  root      402: 
1.1.1.21! root      403:                /* Apply patches for gemdos HD if needed */
        !           404:                /* (we need to do it after cpu tables for all opcodes were rebuilt) */
        !           405:                Cart_Patch();
        !           406: 
1.1.1.16  root      407:                /* changes may affect also info shown in statusbar */
                    408:                Statusbar_UpdateInfo();
1.1.1.21! root      409: 
        !           410:                if (bCaptureError)
        !           411:                {
        !           412:                        Log_AlertDlg(LOG_ERROR, "Full memory state restore failed!\nPlease reboot emulation.");
        !           413:                        return;
        !           414:                }
1.1.1.5   root      415:        }
                    416: 
                    417:        /* Did error? */
                    418:        if (bCaptureError)
1.1.1.7   root      419:                Log_AlertDlg(LOG_ERROR, "Unable to restore memory state from file.");
1.1.1.10  root      420:        else if (bConfirm)
1.1.1.7   root      421:                Log_AlertDlg(LOG_INFO, "Memory state file restored.");
1.1       root      422: }
1.1.1.10  root      423: 
                    424: 
                    425: /*-----------------------------------------------------------------------*/
                    426: /*
                    427:  * Save and restore functions required by the UAE CPU core...
                    428:  * ... don't use them in normal Hatari code!
                    429:  */
                    430: #include <savestate.h>
                    431: 
1.1.1.21! root      432: void save_u64(uae_u64 data)
        !           433: {
        !           434:        MemorySnapShot_Store(&data, 8);
        !           435: }
        !           436: 
1.1.1.10  root      437: void save_u32(uae_u32 data)
                    438: {
                    439:        MemorySnapShot_Store(&data, 4);
1.1.1.21! root      440: //printf ("s32 %x\n", data);
1.1.1.10  root      441: }
                    442: 
                    443: void save_u16(uae_u16 data)
                    444: {
                    445:        MemorySnapShot_Store(&data, 2);
1.1.1.21! root      446: //printf ("s16 %x\n", data);
        !           447: }
        !           448: 
        !           449: void save_u8(uae_u8 data)
        !           450: {
        !           451:        MemorySnapShot_Store(&data, 1);
        !           452: //printf ("s8 %x\n", data);
        !           453: }
        !           454: 
        !           455: uae_u64 restore_u64(void)
        !           456: {
        !           457:        uae_u64 data;
        !           458:        MemorySnapShot_Store(&data, 8);
        !           459:        return data;
1.1.1.10  root      460: }
                    461: 
                    462: uae_u32 restore_u32(void)
                    463: {
                    464:        uae_u32 data;
                    465:        MemorySnapShot_Store(&data, 4);
1.1.1.21! root      466: //printf ("r32 %x\n", data);
1.1.1.10  root      467:        return data;
                    468: }
                    469: 
                    470: uae_u16 restore_u16(void)
                    471: {
                    472:        uae_u16 data;
                    473:        MemorySnapShot_Store(&data, 2);
1.1.1.21! root      474: //printf ("r16 %x\n", data);
1.1.1.10  root      475:        return data;
                    476: }
1.1.1.21! root      477: 
        !           478: uae_u8 restore_u8(void)
        !           479: {
        !           480:        uae_u8 data;
        !           481:        MemorySnapShot_Store(&data, 1);
        !           482: //printf ("r8 %x\n", data);
        !           483:        return data;
        !           484: }
        !           485: 

unix.superglobalmegacorp.com

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