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

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

unix.superglobalmegacorp.com

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